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

Reply via email to