Fix output of return arguments in nested calls on x86_64
diff --git a/ChangeLog b/ChangeLog
index 6f9a470..3c60de2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -11,6 +11,18 @@
 
 2010-11-03  Petr Machata  <pmachata@redhat.com>
 
+	* common.h: Add arch_ptr to callstack_element
+	* handle_event.c: Move callstack manipulation so that it's around
+	the output calls--push before output_left, pop after output_right.
+	(callstack_pop): Free the arch_ptr if it was set.
+	* sysdeps/linux-gnu/x86_64/ptrace.h: Split the archdep struct to
+	the proc part and the callstack_element part.
+	* sysdeps/linux-gnu/x86_64/trace.c (save_register_args): Init
+	callstack_element.arch_ptr.
+	(gimme_arg): Use it.
+
+2010-11-03  Petr Machata  <pmachata@redhat.com>
+
 	* testsuite/ltrace.main/parameters.* (func_work, func_call): new
 	functions for testing nested library calls
 
diff --git a/common.h b/common.h
index 20f1a96..753d3dc 100644
--- a/common.h
+++ b/common.h
@@ -149,6 +149,7 @@
 	int is_syscall;
 	void * return_addr;
 	struct timeval time_spent;
+	void * arch_ptr;
 };
 
 #define MAX_CALLDEPTH 64
diff --git a/handle_event.c b/handle_event.c
index 1107cf0..b6ea172 100644
--- a/handle_event.c
+++ b/handle_event.c
@@ -386,6 +386,7 @@
 handle_syscall(Event *event) {
 	debug(DEBUG_FUNCTION, "handle_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
 	if (event->proc->state != STATE_IGNORED) {
+		callstack_push_syscall(event->proc, event->e_un.sysnum);
 		if (options.syscalls) {
 			output_left(LT_TOF_SYSCALL, event->proc,
 					sysname(event->proc, event->e_un.sysnum));
@@ -393,7 +394,6 @@
 		if (event->proc->breakpoints_enabled == 0) {
 			enable_all_breakpoints(event->proc);
 		}
-		callstack_push_syscall(event->proc, event->e_un.sysnum);
 	}
 	continue_process(event->proc->pid);
 }
@@ -427,6 +427,7 @@
 handle_arch_syscall(Event *event) {
 	debug(DEBUG_FUNCTION, "handle_arch_syscall(pid=%d, sysnum=%d)", event->proc->pid, event->e_un.sysnum);
 	if (event->proc->state != STATE_IGNORED) {
+		callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
 		if (options.syscalls) {
 			output_left(LT_TOF_SYSCALL, event->proc,
 					arch_sysname(event->proc, event->e_un.sysnum));
@@ -434,7 +435,6 @@
 		if (event->proc->breakpoints_enabled == 0) {
 			enable_all_breakpoints(event->proc);
 		}
-		callstack_push_syscall(event->proc, 0xf0000 + event->e_un.sysnum);
 	}
 	continue_process(event->proc->pid);
 }
@@ -470,11 +470,11 @@
 		if (opt_T || options.summary) {
 			calc_time_spent(event->proc);
 		}
-		callstack_pop(event->proc);
 		if (options.syscalls) {
 			output_right(LT_TOF_SYSCALLR, event->proc,
 					sysname(event->proc, event->e_un.sysnum));
 		}
+		callstack_pop(event->proc);
 	}
 	continue_process(event->proc->pid);
 }
@@ -486,11 +486,11 @@
 		if (opt_T || options.summary) {
 			calc_time_spent(event->proc);
 		}
-		callstack_pop(event->proc);
 		if (options.syscalls) {
 			output_right(LT_TOF_SYSCALLR, event->proc,
 					arch_sysname(event->proc, event->e_un.sysnum));
 		}
+		callstack_pop(event->proc);
 	}
 	continue_process(event->proc->pid);
 }
@@ -595,12 +595,12 @@
 					calc_time_spent(event->proc);
 				}
 			}
-			callstack_pop(event->proc);
 			event->proc->return_addr = event->e_un.brk_addr;
 			if (event->proc->state != STATE_IGNORED) {
 				output_right(LT_TOF_FUNCTIONR, event->proc,
 						event->proc->callstack[i].c_un.libfunc->name);
 			}
+			callstack_pop(event->proc);
 			continue_after_breakpoint(event->proc,
 					address2bpstruct(event->proc,
 						event->e_un.brk_addr));
@@ -613,8 +613,8 @@
 			event->proc->stack_pointer = get_stack_pointer(event->proc);
 			event->proc->return_addr =
 				get_return_addr(event->proc, event->proc->stack_pointer);
-			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
 			callstack_push_symfunc(event->proc, sbp->libsym);
+			output_left(LT_TOF_FUNCTION, event->proc, sbp->libsym->name);
 		}
 #ifdef PLT_REINITALISATION_BP
 		if (event->proc->need_to_reinitialize_breakpoints
@@ -699,5 +699,9 @@
 	if (!elem->is_syscall && elem->return_addr) {
 		delete_breakpoint(proc, elem->return_addr);
 	}
+	if (elem->arch_ptr != NULL) {
+		free(elem->arch_ptr);
+		elem->arch_ptr = NULL;
+	}
 	proc->callstack_depth--;
 }
diff --git a/sysdeps/linux-gnu/x86_64/ptrace.h b/sysdeps/linux-gnu/x86_64/ptrace.h
index 48bf539..d92771f 100644
--- a/sysdeps/linux-gnu/x86_64/ptrace.h
+++ b/sysdeps/linux-gnu/x86_64/ptrace.h
@@ -6,7 +6,9 @@
 	int valid;
 	struct user_regs_struct regs;
 	struct user_fpregs_struct fpregs;
-	struct user_regs_struct regs_copy;
-	struct user_fpregs_struct fpregs_copy;
 } proc_archdep;
 
+typedef struct {
+	struct user_regs_struct regs_copy;
+	struct user_fpregs_struct fpregs_copy;
+} callstack_achdep;
diff --git a/sysdeps/linux-gnu/x86_64/trace.c b/sysdeps/linux-gnu/x86_64/trace.c
index 53ee570..e8581af 100644
--- a/sysdeps/linux-gnu/x86_64/trace.c
+++ b/sysdeps/linux-gnu/x86_64/trace.c
@@ -7,6 +7,7 @@
 #include <sys/ptrace.h>
 #include <sys/reg.h>
 #include <string.h>
+#include <assert.h>
 
 #include "common.h"
 #include "ptrace.h"
@@ -145,6 +146,7 @@
 		return (unsigned int)gimme_arg32(type, proc, arg_num);
 
 	proc_archdep *arch = (proc_archdep *)proc->arch_ptr;
+
 	if (arch == NULL || !arch->valid)
 		return -1;
 
@@ -152,10 +154,15 @@
 		if (arg_num == -1)
 			return gimme_retval(proc, arg_num, info,
 					    &arch->regs, &arch->fpregs);
-		else
+		else {
+			struct callstack_element *elem
+				= proc->callstack + proc->callstack_depth - 1;
+			callstack_achdep *csad = elem->arch_ptr;
+			assert(csad != NULL);
 			return gimme_arg_regset(proc, arg_num, info,
-						&arch->regs_copy,
-						&arch->fpregs_copy);
+						&csad->regs_copy,
+						&csad->fpregs_copy);
+		}
 	}
 	else
 		return gimme_arg_regset(proc, arg_num, info,
@@ -168,6 +175,10 @@
         if (arch == NULL || !arch->valid)
                 return;
 
-        memcpy(&arch->regs_copy, &arch->regs, sizeof(arch->regs));
-        memcpy(&arch->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
+	callstack_achdep *csad = malloc(sizeof(*csad));
+	memset(csad, 0, sizeof(*csad));
+	memcpy(&csad->regs_copy, &arch->regs, sizeof(arch->regs));
+	memcpy(&csad->fpregs_copy, &arch->fpregs, sizeof(arch->fpregs));
+
+	proc->callstack[proc->callstack_depth - 1].arch_ptr = csad;
 }