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);