]> granicus.if.org Git - strace/commitdiff
Implement kexec_load decoding
authorDmitry V. Levin <ldv@altlinux.org>
Wed, 5 Feb 2014 13:48:26 +0000 (13:48 +0000)
committerDmitry V. Levin <ldv@altlinux.org>
Wed, 5 Feb 2014 14:25:20 +0000 (14:25 +0000)
* kexec.c: New file.
* linux/kexec.h: Likewise.
* Makefile.am (strace_SOURCES): Add kexec.c.
(EXTRA_DIST): Add linux/kexec.h.
* linux/dummy.h (sys_kexec_load): Remove.
* linux/syscall.h (sys_kexec_load): New prototype.

Makefile.am
kexec.c [new file with mode: 0644]
linux/dummy.h
linux/kexec.h [new file with mode: 0644]
linux/syscall.h

index e9e4d2126674e91852af2000898a03ec79cb397b..55cd4ccdab711fda7bcb0909d853cfc0d876c9be 100644 (file)
@@ -25,6 +25,7 @@ strace_SOURCES =      \
        io.c            \
        ioctl.c         \
        ipc.c           \
+       kexec.c         \
        loop.c          \
        mem.c           \
        mtd.c           \
@@ -109,6 +110,7 @@ EXTRA_DIST =                                \
        linux/ioctlent.h.in             \
        linux/ioctlent.sh               \
        linux/ioctlsort.c               \
+       linux/kexec.h                   \
        linux/m68k/ioctlent.h.in        \
        linux/m68k/syscallent.h         \
        linux/metag/ioctlent.h.in       \
diff --git a/kexec.c b/kexec.c
new file mode 100644 (file)
index 0000000..9c675cc
--- /dev/null
+++ b/kexec.c
@@ -0,0 +1,108 @@
+#include "defs.h"
+#include <linux/kexec.h>
+
+static const struct xlat kexec_arch_values[] = {
+       XLAT(KEXEC_ARCH_DEFAULT),
+       XLAT(KEXEC_ARCH_386),
+       XLAT(KEXEC_ARCH_X86_64),
+       XLAT(KEXEC_ARCH_PPC),
+       XLAT(KEXEC_ARCH_PPC64),
+       XLAT(KEXEC_ARCH_IA_64),
+       XLAT(KEXEC_ARCH_ARM),
+       XLAT(KEXEC_ARCH_S390),
+       XLAT(KEXEC_ARCH_SH),
+       XLAT(KEXEC_ARCH_MIPS_LE),
+       XLAT(KEXEC_ARCH_MIPS),
+       XLAT_END
+};
+
+static const struct xlat kexec_flags[] = {
+       XLAT(KEXEC_ON_CRASH),
+       XLAT(KEXEC_PRESERVE_CONTEXT),
+       XLAT_END
+};
+
+static void
+print_kexec_segments(struct tcb *tcp, unsigned long addr, unsigned long len)
+{
+#if SUPPORTED_PERSONALITIES > 1
+       union {
+               struct { u_int32_t buf, bufsz, mem, memsz; } seg32;
+               struct { u_int64_t buf, bufsz, mem, memsz; } seg64;
+       } seg;
+# define sizeof_seg \
+       (current_wordsize == 4 ? sizeof(seg.seg32) : sizeof(seg.seg64))
+# define seg_buf \
+       (current_wordsize == 4 ? (uint64_t) seg.seg32.buf : seg.seg64.buf)
+# define seg_bufsz \
+       (current_wordsize == 4 ? (uint64_t) seg.seg32.bufsz : seg.seg64.bufsz)
+# define seg_mem \
+       (current_wordsize == 4 ? (uint64_t) seg.seg32.mem : seg.seg64.mem)
+# define seg_memsz \
+       (current_wordsize == 4 ? (uint64_t) seg.seg32.memsz : seg.seg64.memsz)
+#else
+       struct kexec_segment seg;
+# define sizeof_seg sizeof(seg)
+# define seg_buf seg.seg_buf
+# define seg_bufsz seg.seg_bufsz
+# define seg_mem seg.seg_mem
+# define seg_memsz seg.seg_memsz
+#endif
+       unsigned int i, failed;
+
+       if (!len) {
+               tprints("[]");
+               return;
+       }
+
+       if (len > KEXEC_SEGMENT_MAX) {
+               tprintf("%#lx", addr);
+               return;
+       }
+
+       failed = 0;
+       tprints("[");
+       for (i = 0; i < len; ++i) {
+               if (i)
+                       tprints(", ");
+               if (umoven(tcp, addr + i * sizeof_seg, sizeof_seg,
+                          (char *) &seg) < 0) {
+                       tprints("?");
+                       failed = 1;
+                       break;
+               }
+               tprintf("{%#lx, %lu, %#lx, %lu}",
+                       (long) seg_buf, (unsigned long) seg_bufsz,
+                       (long) seg_mem, (unsigned long) seg_memsz);
+       }
+       tprints("]");
+       if (failed)
+               tprintf(" %#lx", addr);
+}
+
+int
+sys_kexec_load(struct tcb *tcp)
+{
+       unsigned long n;
+
+       if (exiting(tcp))
+               return 0;
+
+       /* entry, nr_segments */
+       tprintf("%#lx, %lu, ", tcp->u_arg[0], tcp->u_arg[1]);
+
+       /* segments */
+       print_kexec_segments(tcp, tcp->u_arg[2], tcp->u_arg[1]);
+       tprints(", ");
+
+       /* flags */
+       n = tcp->u_arg[3];
+       printxval(kexec_arch_values, n & KEXEC_ARCH_MASK, "KEXEC_ARCH_???");
+       n &= ~KEXEC_ARCH_MASK;
+       if (n) {
+               tprints("|");
+               printflags(kexec_flags, n, "KEXEC_???");
+       }
+
+       return 0;
+}
index 979ed376df95ee24d3d3a97c2653ac1bc71ad49e..78d264f688a56ff78dc538594a51fd0dbc97734b 100644 (file)
@@ -39,7 +39,6 @@
 #define        sys_ioprio_get          printargs
 #define        sys_ioprio_set          printargs
 #define        sys_kcmp                printargs
-#define        sys_kexec_load          printargs
 #define        sys_keyctl              printargs
 #define        sys_lookup_dcookie      printargs
 #define        sys_name_to_handle_at   printargs
diff --git a/linux/kexec.h b/linux/kexec.h
new file mode 100644 (file)
index 0000000..767ccb5
--- /dev/null
@@ -0,0 +1,50 @@
+#ifndef LINUX_KEXEC_H
+#define LINUX_KEXEC_H
+
+/* kexec system call -  It loads the new kernel to boot into.
+ * kexec does not sync, or unmount filesystems so if you need
+ * that to happen you need to do that yourself.
+ */
+
+/* kexec flags for different usage scenarios */
+#define KEXEC_ON_CRASH         0x00000001
+#define KEXEC_PRESERVE_CONTEXT 0x00000002
+#define KEXEC_ARCH_MASK                0xffff0000
+
+/* These values match the ELF architecture values.
+ * Unless there is a good reason that should continue to be the case.
+ */
+#define KEXEC_ARCH_DEFAULT ( 0 << 16)
+#define KEXEC_ARCH_386     ( 3 << 16)
+#define KEXEC_ARCH_X86_64  (62 << 16)
+#define KEXEC_ARCH_PPC     (20 << 16)
+#define KEXEC_ARCH_PPC64   (21 << 16)
+#define KEXEC_ARCH_IA_64   (50 << 16)
+#define KEXEC_ARCH_ARM     (40 << 16)
+#define KEXEC_ARCH_S390    (22 << 16)
+#define KEXEC_ARCH_SH      (42 << 16)
+#define KEXEC_ARCH_MIPS_LE (10 << 16)
+#define KEXEC_ARCH_MIPS    ( 8 << 16)
+
+/* The artificial cap on the number of segments passed to kexec_load. */
+#define KEXEC_SEGMENT_MAX 16
+
+/*
+ * This structure is used to hold the arguments that are used when
+ * loading  kernel binaries.
+ */
+struct kexec_segment {
+       const void *buf;
+       size_t bufsz;
+       const void *mem;
+       size_t memsz;
+};
+
+/* Load a new kernel image as described by the kexec_segment array
+ * consisting of passed number of segments at the entry-point address.
+ * The flags allow different useage types.
+ */
+extern int kexec_load(void *, size_t, struct kexec_segment *,
+               unsigned long int);
+
+#endif /* LINUX_KEXEC_H */
index d2ba126c05b7bd5d1324dec8bb8f09f298b3ceb6..d8ce91fe0ea818bbc8ef4920150f4002a6efa2ad 100644 (file)
@@ -121,6 +121,7 @@ int sys_io_setup();
 int sys_io_submit();
 int sys_ioctl();
 int sys_ipc();
+int sys_kexec_load();
 int sys_kill();
 int sys_link();
 int sys_linkat();