Fix detach from sleeping process, fix return from tail call
The latter in a limited way, true tail recursion is still broken.
This commit is contained in:
parent
e51d038fe7
commit
055adede18
141
ltrace-0.6.0-detach-sleeping.patch
Normal file
141
ltrace-0.6.0-detach-sleeping.patch
Normal file
@ -0,0 +1,141 @@
|
||||
diff --git a/common.h b/common.h
|
||||
index 2399e29..b6e10f2 100644
|
||||
--- a/common.h
|
||||
+++ b/common.h
|
||||
@@ -347,7 +347,6 @@ extern void continue_after_signal(pid_t pid, int signum);
|
||||
extern void continue_after_syscall(Process *proc, int sysnum, int ret_p);
|
||||
extern void continue_after_breakpoint(Process * proc, struct breakpoint *sbp);
|
||||
extern void continue_after_vfork(Process * proc);
|
||||
-extern void ltrace_exiting(void);
|
||||
extern long gimme_arg(enum tof type, Process * proc, int arg_num, arg_type_info * info);
|
||||
extern void save_register_args(enum tof type, Process * proc);
|
||||
extern int umovestr(Process * proc, void * addr, int len, void * laddr);
|
||||
@@ -363,5 +362,21 @@ extern int task_kill (pid_t pid, int sig);
|
||||
* any platform-specific knowledge of why it could be so. */
|
||||
void trace_fail_warning(pid_t pid);
|
||||
|
||||
+/* A pair of functions called to initiate a detachment request when
|
||||
+ * ltrace is about to exit. Their job is to undo any effects that
|
||||
+ * tracing had and eventually detach process, perhaps by way of
|
||||
+ * installing a process handler.
|
||||
+ *
|
||||
+ * OS_LTRACE_EXITING_SIGHANDLER is called from a signal handler
|
||||
+ * context right after the signal was captured. It returns 1 if the
|
||||
+ * request was handled or 0 if it wasn't.
|
||||
+ *
|
||||
+ * If the call to OS_LTRACE_EXITING_SIGHANDLER didn't handle the
|
||||
+ * request, OS_LTRACE_EXITING is called when the next event is
|
||||
+ * generated. Therefore it's called in "safe" context, without
|
||||
+ * re-entrancy concerns, but it's only called after an even is
|
||||
+ * generated. */
|
||||
+int os_ltrace_exiting_sighandler(void);
|
||||
+void os_ltrace_exiting(void);
|
||||
|
||||
extern struct ltelf main_lte;
|
||||
diff --git a/handle_event.c b/handle_event.c
|
||||
index e3d3d0a..725f50d 100644
|
||||
--- a/handle_event.c
|
||||
+++ b/handle_event.c
|
||||
@@ -49,11 +49,12 @@ call_handler(Process * proc, Event * event)
|
||||
}
|
||||
|
||||
void
|
||||
-handle_event(Event *event) {
|
||||
+handle_event(Event *event)
|
||||
+{
|
||||
if (exiting == 1) {
|
||||
- exiting = 2;
|
||||
debug(1, "ltrace about to exit");
|
||||
- ltrace_exiting();
|
||||
+ os_ltrace_exiting();
|
||||
+ exiting = 2;
|
||||
}
|
||||
debug(DEBUG_FUNCTION, "handle_event(pid=%d, type=%d)",
|
||||
event->proc ? event->proc->pid : -1, event->type);
|
||||
diff --git a/libltrace.c b/libltrace.c
|
||||
index 19bfafd..777ad1b 100644
|
||||
--- a/libltrace.c
|
||||
+++ b/libltrace.c
|
||||
@@ -48,9 +48,14 @@ signal_alarm(int sig) {
|
||||
}
|
||||
|
||||
static void
|
||||
-signal_exit(int sig) {
|
||||
- exiting = 1;
|
||||
+signal_exit(int sig)
|
||||
+{
|
||||
debug(1, "Received interrupt signal; exiting...");
|
||||
+ if (exiting != 0)
|
||||
+ return;
|
||||
+
|
||||
+ exiting = 1 + !!os_ltrace_exiting_sighandler();
|
||||
+
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
signal(SIGALRM, signal_alarm);
|
||||
diff --git a/sysdeps/linux-gnu/events.c b/sysdeps/linux-gnu/events.c
|
||||
index 021192f..b6c12ef 100644
|
||||
--- a/sysdeps/linux-gnu/events.c
|
||||
+++ b/sysdeps/linux-gnu/events.c
|
||||
@@ -104,6 +104,8 @@ next_qd_event(void)
|
||||
return each_qd_event(&event_process_not_reenabling, NULL);
|
||||
}
|
||||
|
||||
+int linux_in_waitpid = 0;
|
||||
+
|
||||
Event *
|
||||
next_event(void)
|
||||
{
|
||||
@@ -124,7 +126,11 @@ next_event(void)
|
||||
debug(DEBUG_EVENT, "event: No more traced programs: exiting");
|
||||
exit(0);
|
||||
}
|
||||
+
|
||||
+ linux_in_waitpid = 1;
|
||||
pid = waitpid(-1, &status, __WALL);
|
||||
+ linux_in_waitpid = 0;
|
||||
+
|
||||
if (pid == -1) {
|
||||
if (errno == ECHILD) {
|
||||
debug(DEBUG_EVENT, "event: No more traced programs: exiting");
|
||||
diff --git a/sysdeps/linux-gnu/trace.c b/sysdeps/linux-gnu/trace.c
|
||||
index 82a4154..9ecea1e 100644
|
||||
--- a/sysdeps/linux-gnu/trace.c
|
||||
+++ b/sysdeps/linux-gnu/trace.c
|
||||
@@ -314,8 +314,8 @@ task_stopped(Process * task, void * data)
|
||||
case ps_invalid:
|
||||
case ps_tracing_stop:
|
||||
case ps_zombie:
|
||||
- case ps_sleeping:
|
||||
return pcb_cont;
|
||||
+ case ps_sleeping:
|
||||
case ps_stop:
|
||||
case ps_other:
|
||||
return pcb_stop;
|
||||
@@ -1005,7 +1005,7 @@ continue_after_syscall(Process * proc, int sysnum, int ret_p)
|
||||
* detaches.
|
||||
*/
|
||||
void
|
||||
-ltrace_exiting(void)
|
||||
+os_ltrace_exiting(void)
|
||||
{
|
||||
struct opt_p_t * it;
|
||||
for (it = opt_p; it != NULL; it = it->next) {
|
||||
@@ -1019,6 +1019,17 @@ ltrace_exiting(void)
|
||||
}
|
||||
}
|
||||
|
||||
+int
|
||||
+os_ltrace_exiting_sighandler(void)
|
||||
+{
|
||||
+ extern int linux_in_waitpid;
|
||||
+ if (linux_in_waitpid) {
|
||||
+ os_ltrace_exiting();
|
||||
+ return 1;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
size_t
|
||||
umovebytes(Process *proc, void *addr, void *laddr, size_t len) {
|
||||
|
||||
256
ltrace-0.6.0-tail-return.patch
Normal file
256
ltrace-0.6.0-tail-return.patch
Normal file
@ -0,0 +1,256 @@
|
||||
diff --git a/handle_event.c b/handle_event.c
|
||||
index 725f50d..8c3c7ce 100644
|
||||
--- a/handle_event.c
|
||||
+++ b/handle_event.c
|
||||
@@ -565,11 +565,21 @@ void *get_count_register (Process *proc);
|
||||
}
|
||||
|
||||
static void
|
||||
+output_right_tos(struct Process *proc)
|
||||
+{
|
||||
+ size_t d = proc->callstack_depth;
|
||||
+ struct callstack_element *elem = &proc->callstack[d - 1];
|
||||
+ if (proc->state != STATE_IGNORED)
|
||||
+ output_right(LT_TOF_FUNCTIONR, proc, elem->c_un.libfunc->name);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
handle_breakpoint(Event *event)
|
||||
{
|
||||
int i, j;
|
||||
struct breakpoint *sbp;
|
||||
Process *leader = event->proc->leader;
|
||||
+ void *brk_addr = event->e_un.brk_addr;
|
||||
|
||||
/* The leader has terminated. */
|
||||
if (leader == NULL) {
|
||||
@@ -577,12 +587,14 @@ handle_breakpoint(Event *event)
|
||||
return;
|
||||
}
|
||||
|
||||
- debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)", event->proc->pid, event->e_un.brk_addr);
|
||||
- debug(2, "event: breakpoint (%p)", event->e_un.brk_addr);
|
||||
+ debug(DEBUG_FUNCTION, "handle_breakpoint(pid=%d, addr=%p)",
|
||||
+ event->proc->pid, brk_addr);
|
||||
+ debug(2, "event: breakpoint (%p)", brk_addr);
|
||||
|
||||
for (i = event->proc->callstack_depth - 1; i >= 0; i--) {
|
||||
- if (event->e_un.brk_addr ==
|
||||
- event->proc->callstack[i].return_addr) {
|
||||
+ if (brk_addr == event->proc->callstack[i].return_addr) {
|
||||
+ struct library_symbol *libsym =
|
||||
+ event->proc->callstack[i].c_un.libfunc;
|
||||
#ifdef __powerpc__
|
||||
/*
|
||||
* PPC HACK! (XXX FIXME TODO)
|
||||
@@ -623,8 +625,6 @@ handle_breakpoint(Event *event)
|
||||
* so be sure to re-enable the breakpoint.
|
||||
*/
|
||||
unsigned long a;
|
||||
- struct library_symbol *libsym =
|
||||
- event->proc->callstack[i].c_un.libfunc;
|
||||
void *addr = sym2addr(event->proc, libsym);
|
||||
|
||||
if (libsym->plt_type != LS_TOPLT_POINT) {
|
||||
@@ -668,19 +679,37 @@ handle_breakpoint(Event *event)
|
||||
calc_time_spent(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);
|
||||
- }
|
||||
+ event->proc->return_addr = brk_addr;
|
||||
+
|
||||
+ output_right_tos(event->proc);
|
||||
callstack_pop(event->proc);
|
||||
- sbp = address2bpstruct(leader, event->e_un.brk_addr);
|
||||
+
|
||||
+ /* Pop also any other entries that seem like
|
||||
+ * they are linked to the current one: they
|
||||
+ * have the same return address, but were made
|
||||
+ * for different symbols. This should only
|
||||
+ * happen for entry point tracing, i.e. for -x
|
||||
+ * everywhere, or -x and -e on PPC64. */
|
||||
+ while (event->proc->callstack_depth > 0) {
|
||||
+ struct callstack_element *prev;
|
||||
+ size_t d = event->proc->callstack_depth;
|
||||
+ prev = &event->proc->callstack[d - 1];
|
||||
+
|
||||
+ if (prev->c_un.libfunc == libsym
|
||||
+ || prev->return_addr != brk_addr)
|
||||
+ break;
|
||||
+
|
||||
+ output_right_tos(event->proc);
|
||||
+ callstack_pop(event->proc);
|
||||
+ }
|
||||
+
|
||||
+ sbp = address2bpstruct(leader, brk_addr);
|
||||
continue_after_breakpoint(event->proc, sbp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
- if ((sbp = address2bpstruct(leader, event->e_un.brk_addr))) {
|
||||
+ if ((sbp = address2bpstruct(leader, brk_addr))) {
|
||||
breakpoint_on_hit(sbp, event->proc);
|
||||
|
||||
if (sbp->libsym == NULL) {
|
||||
@@ -711,7 +740,7 @@ handle_breakpoint(Event *event)
|
||||
|
||||
if (event->proc->state != STATE_IGNORED && !options.no_plt) {
|
||||
output_line(event->proc, "unexpected breakpoint at %p",
|
||||
- (void *)event->e_un.brk_addr);
|
||||
+ brk_addr);
|
||||
}
|
||||
continue_process(event->proc->pid);
|
||||
}
|
||||
@@ -742,7 +771,7 @@ callstack_push_syscall(Process *proc, int sysnum) {
|
||||
|
||||
static void
|
||||
callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
|
||||
- struct callstack_element *elem, *prev;
|
||||
+ struct callstack_element *elem;
|
||||
|
||||
debug(DEBUG_FUNCTION, "callstack_push_symfunc(pid=%d, symbol=%s)", proc->pid, sym->name);
|
||||
/* FIXME: not good -- should use dynamic allocation. 19990703 mortene. */
|
||||
@@ -752,8 +781,7 @@ callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
|
||||
return;
|
||||
}
|
||||
|
||||
- prev = &proc->callstack[proc->callstack_depth-1];
|
||||
- elem = &proc->callstack[proc->callstack_depth];
|
||||
+ elem = &proc->callstack[proc->callstack_depth++];
|
||||
elem->is_syscall = 0;
|
||||
elem->c_un.libfunc = sym;
|
||||
|
||||
@@ -763,8 +791,6 @@ callstack_push_symfunc(Process *proc, struct library_symbol *sym) {
|
||||
}
|
||||
|
||||
/* handle functions like atexit() on mips which have no return */
|
||||
- if (elem->return_addr != prev->return_addr)
|
||||
- proc->callstack_depth++;
|
||||
if (opt_T || options.summary) {
|
||||
struct timezone tz;
|
||||
gettimeofday(&elem->time_spent, &tz);
|
||||
diff --git a/testsuite/ltrace.main/branch_func.c b/testsuite/ltrace.main/branch_func.c
|
||||
new file mode 100644
|
||||
index 0000000..0ce311d
|
||||
--- /dev/null
|
||||
+++ b/testsuite/ltrace.main/branch_func.c
|
||||
@@ -0,0 +1,51 @@
|
||||
+/*
|
||||
+ * This file is part of ltrace.
|
||||
+ * Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU General Public License as
|
||||
+ * published by the Free Software Foundation; either version 2 of the
|
||||
+ * License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This program is distributed in the hope that it will be useful, but
|
||||
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU General Public License
|
||||
+ * along with this program; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
+ * 02110-1301 USA
|
||||
+ */
|
||||
+
|
||||
+/* This is specially made to produce tail calls. We then trace them
|
||||
+ * and see if ltrace handles it well, or whether its internal stack
|
||||
+ * overflows. */
|
||||
+
|
||||
+__attribute__((noinline, optimize(3))) int
|
||||
+func3(int i)
|
||||
+{
|
||||
+ return i + 1;
|
||||
+}
|
||||
+
|
||||
+__attribute__((noinline, optimize(3))) int
|
||||
+func2(int i)
|
||||
+{
|
||||
+ return func3(i * 3);
|
||||
+}
|
||||
+
|
||||
+__attribute__((noinline, optimize(3))) int
|
||||
+func1(int i)
|
||||
+{
|
||||
+ return func2(i + 2);
|
||||
+}
|
||||
+
|
||||
+__attribute__((optimize(0))) int
|
||||
+main(int argc, char **argv)
|
||||
+{
|
||||
+ int counter = 0;
|
||||
+ int i;
|
||||
+ for (i = 0; i < 100; ++i)
|
||||
+ counter += func1(i);
|
||||
+ return counter;
|
||||
+}
|
||||
diff --git a/testsuite/ltrace.main/branch_func.exp b/testsuite/ltrace.main/branch_func.exp
|
||||
new file mode 100644
|
||||
index 0000000..fec5700
|
||||
--- /dev/null
|
||||
+++ b/testsuite/ltrace.main/branch_func.exp
|
||||
@@ -0,0 +1,57 @@
|
||||
+# This file is part of ltrace.
|
||||
+# Copyright (C) 2012 Petr Machata, Red Hat Inc.
|
||||
+#
|
||||
+# This program is free software; you can redistribute it and/or
|
||||
+# modify it under the terms of the GNU General Public License as
|
||||
+# published by the Free Software Foundation; either version 2 of the
|
||||
+# License, or (at your option) any later version.
|
||||
+#
|
||||
+# This program is distributed in the hope that it will be useful, but
|
||||
+# WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+# General Public License for more details.
|
||||
+#
|
||||
+# You should have received a copy of the GNU General Public License
|
||||
+# along with this program; if not, write to the Free Software
|
||||
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
||||
+# 02110-1301 USA
|
||||
+
|
||||
+set testfile "branch_func"
|
||||
+set srcfile ${testfile}.c
|
||||
+set binfile ${testfile}
|
||||
+
|
||||
+if [get_compiler_info $binfile] {
|
||||
+ return -1
|
||||
+}
|
||||
+
|
||||
+verbose "compiling source file now....."
|
||||
+if { [ltrace_compile $srcdir/$subdir/$srcfile $objdir/$subdir/$binfile executable {debug} ] != "" } {
|
||||
+ send_user "Testcase compile failed, so all tests in this file will automatically fail\n."
|
||||
+}
|
||||
+
|
||||
+# set options for ltrace.
|
||||
+ltrace_options "-x" "func1" "-x" "func2" "-x" "func3"
|
||||
+
|
||||
+# Run PUT for ltarce.
|
||||
+set exec_output [ltrace_runtest $objdir/$subdir $objdir/$subdir/$binfile]
|
||||
+
|
||||
+# Check the output of this program.
|
||||
+verbose "ltrace runtest output: $exec_output\n"
|
||||
+if [regexp {ELF from incompatible architecture} $exec_output] {
|
||||
+ fail "32-bit ltrace can not perform on 64-bit PUTs and rebuild ltrace in 64 bit mode!"
|
||||
+ return
|
||||
+} elseif [ regexp {Couldn't get .hash data} $exec_output ] {
|
||||
+ fail "Couldn't get .hash data!"
|
||||
+ return
|
||||
+}
|
||||
+
|
||||
+set pattern "func1(.*unfinished"
|
||||
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
|
||||
+set pattern "func2(.*unfinished"
|
||||
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
|
||||
+set pattern "func3(.*)"
|
||||
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
|
||||
+set pattern "func2.resumed"
|
||||
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
|
||||
+set pattern "func1.resumed"
|
||||
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace $pattern 100
|
||||
@ -1,7 +1,7 @@
|
||||
Summary: Tracks runtime library calls from dynamically linked executables
|
||||
Name: ltrace
|
||||
Version: 0.6.0
|
||||
Release: 10%{?dist}
|
||||
Release: 11%{?dist}
|
||||
URL: http://ltrace.alioth.debian.org/
|
||||
License: GPLv2+
|
||||
Group: Development/Debuggers
|
||||
@ -29,6 +29,8 @@ Patch11: ltrace-0.6.0-vfork.patch
|
||||
Patch12: ltrace-0.6.0-thread-races.patch
|
||||
Patch13: ltrace-0.6.0-process-start.patch
|
||||
Patch14: ltrace-0.6.0-selinux.patch
|
||||
Patch15: ltrace-0.6.0-detach-sleeping.patch
|
||||
Patch16: ltrace-0.6.0-tail-return.patch
|
||||
|
||||
%description
|
||||
Ltrace is a debugging program which runs a specified command until the
|
||||
@ -56,6 +58,8 @@ execution of processes.
|
||||
%patch12 -p1
|
||||
%patch13 -p1
|
||||
%patch14 -p1
|
||||
%patch15 -p1
|
||||
%patch16 -p1
|
||||
sed -i -e 's/-o root -g root//' Makefile.in
|
||||
|
||||
%build
|
||||
|
||||
Loading…
Reference in New Issue
Block a user