diff options
author | Dmitry V. Levin <ldv@altlinux.org> | 2014-02-05 13:48:26 +0000 |
---|---|---|
committer | Dmitry V. Levin <ldv@altlinux.org> | 2014-02-05 14:25:20 +0000 |
commit | 90aa9f4d72e26581ea0a39c02db625d7bd4e2962 (patch) | |
tree | 3bab8cebbe335010cb7ee1402904320e78e649e7 /kexec.c | |
parent | d21f186a94086fae25788e14c584fcce52bd67b6 (diff) | |
download | strace-90aa9f4d72e26581ea0a39c02db625d7bd4e2962.tar.gz strace-90aa9f4d72e26581ea0a39c02db625d7bd4e2962.tar.bz2 strace-90aa9f4d72e26581ea0a39c02db625d7bd4e2962.tar.xz |
Implement kexec_load decoding
* 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.
Diffstat (limited to 'kexec.c')
-rw-r--r-- | kexec.c | 108 |
1 files changed, 108 insertions, 0 deletions
@@ -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; +} |