On 15. 04. 19 17:29, Jiri Palecek wrote:
So I prepared a patch that would use the existing 64bit functions to obtain syscall arguments on 32bit too.
On review, I found a typo in the patch. Sorry for that. The revised version is attached. Refards Jiri Palecek
Index: ltrace-0.7.3/sysdeps/linux-gnu/x86/fetch.c =================================================================== --- ltrace-0.7.3.orig/sysdeps/linux-gnu/x86/fetch.c +++ ltrace-0.7.3/sysdeps/linux-gnu/x86/fetch.c @@ -53,6 +53,12 @@ enum reg_pool { POOL_RETVAL, }; +enum syscall_flavor { + SYSCALL_INT80, + SYSCALL_SYSCALL, + SYSCALL_SYSENTER, +}; + struct fetch_context { struct user_regs_struct iregs; @@ -74,6 +80,8 @@ struct fetch_context struct value retval; } ix86; } u; + enum syscall_flavor syscall_flavor; + int target_machine; }; #ifndef __x86_64__ @@ -208,6 +216,39 @@ allocate_x87(struct fetch_context *conte return CLASS_X87; } +/* + * This is to guess which syscall entry point to the 32bit kernel was + * used. See arch/x86/entry/entry*.S and + * arch/x86/entry/vdso/vdso32/system_call.S + * + * The information is then used in allocate_integer to find the + * arguments in the correct register. This function isn't perfect, but + * should work in the majority of cases (vdso and direct-coded int 80) + */ +static enum syscall_flavor +get_syscall_flavor(struct Process* proc, struct fetch_context *context) +{ + char data[4]; +#ifdef __x86_64__ + if (umovebytes(proc, (char*)context->iregs.rip-4, data, 4) != 4) { +#else + if (umovebytes(proc, (char*)context->iregs.eip-4, data, 4) != 4) { +#endif + fprintf(stderr, "Couldn't read code to detect syscall instructions\n"); + return SYSCALL_INT80; + } + if (memcmp (data, "\x0f\x34\xcd\x80", 4) == 0) + return SYSCALL_SYSENTER; + else if (memcmp (data, "\x0f\x05\xcd\x80", 4) == 0) + return SYSCALL_SYSCALL; + else if (memcmp (data+2, "\xcd\x80", 2) == 0) + return SYSCALL_INT80; + else { + fprintf (stderr, "Couldn't match known syscall instruction\n"); + return SYSCALL_INT80; /* fallback */ + } +} + static enum arg_class allocate_integer(struct fetch_context *context, struct value *valuep, size_t sz, size_t offset, enum reg_pool pool) @@ -238,20 +279,66 @@ allocate_integer(struct fetch_context *c case POOL_SYSCALL: #ifdef __x86_64__ + if (context->target_machine == EM_X86_64) + switch (context->ireg) { + HANDLE(0, rdi); + HANDLE(1, rsi); + HANDLE(2, rdx); + HANDLE(3, r10); + HANDLE(4, r8); + HANDLE(5, r9); + default: + assert(!"More than six syscall arguments???"); + abort(); + } +#endif + + /* Common name for the registers */ +#ifndef __x86_64__ +#define rbx ebx +#define rbp ebp +#define rcx ecx +#define rdx edx +#define rsi esi +#define rdi edi +#define rbp ebp +#endif + switch (context->ireg) { - HANDLE(0, rdi); - HANDLE(1, rsi); + HANDLE(0, rbx); + case 1: + if (context->syscall_flavor == SYSCALL_SYSCALL) + copy_int_register(context, valuep, + context->iregs.rbp, offset); + else + copy_int_register(context, valuep, + context->iregs.rcx, offset); + return CLASS_INTEGER; + HANDLE(2, rdx); - HANDLE(3, r10); - HANDLE(4, r8); - HANDLE(5, r9); + HANDLE(3, rsi); + HANDLE(4, rdi); + case 5: + if (context->syscall_flavor == SYSCALL_INT80) { + copy_int_register(context, valuep, + context->iregs.rbp, offset); + return CLASS_INTEGER; + } + allocate_stack_slot(context, valuep, sz, offset, 4); + return CLASS_MEMORY; + default: assert(!"More than six syscall arguments???"); abort(); } -#else - i386_unreachable(); -#endif + /* End of common code, undefine common register names */ +#undef rbx +#undef rbp +#undef rcx +#undef rdx +#undef rsi +#undef rdi +#undef rbp case POOL_RETVAL: switch (context->ireg) { @@ -668,6 +755,9 @@ arch_fetch_arg_init_32(struct fetch_cont value_init_detached(retval, NULL, NULL, 0); } + if (type == LT_TOF_SYSCALLR || type == LT_TOF_SYSCALL) + context->syscall_flavor = get_syscall_flavor(proc, context); + return context; } @@ -713,6 +803,7 @@ arch_fetch_arg_init(enum tof type, struc return NULL; } + ctx->target_machine = proc->e_machine; struct fetch_context *ret; if (proc->e_machine == EM_386) ret = arch_fetch_arg_init_32(ctx, type, proc, ret_info); @@ -811,13 +902,13 @@ arch_fetch_arg_next(struct fetch_context struct Process *proc, struct arg_type_info *info, struct value *valuep) { - if (proc->e_machine == EM_386) - return arch_fetch_arg_next_32(context, type, proc, - info, valuep); - switch (type) { case LT_TOF_FUNCTION: case LT_TOF_FUNCTIONR: + if (proc->e_machine == EM_386) + return arch_fetch_arg_next_32(context, type, proc, + info, valuep); + return arch_fetch_pool_arg_next(context, type, proc, info, valuep, POOL_FUNCALL);