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