Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > media > main-src > by-pkgid > b3bd92884018251b87f9099340c300c3 > files > 47

ltrace-0.5-13.45svn.el5_7.12.src.rpm

diff -urp ltrace-0.5/ltrace.h ltrace-0.5-64/ltrace.h
--- ltrace-0.5/ltrace.h	2011-10-25 09:15:34.000000000 -0400
+++ ltrace-0.5-64/ltrace.h	2011-10-25 09:02:00.000000000 -0400
@@ -280,6 +280,7 @@ extern void disable_breakpoint(struct pr
 extern int syscall_p(struct process *proc, int status, int *sysnum);
 extern void continue_process(pid_t pid);
 extern void continue_after_signal(pid_t pid, int signum);
+extern void continue_after_syscall(struct process *proc, int sysnum, int ret_p);
 extern void continue_after_breakpoint(struct process *proc, struct breakpoint *sbp);
 extern void continue_after_vfork(struct process * proc);
 extern void ltrace_exiting(void);
diff -urp ltrace-0.5/process_event.c ltrace-0.5-64/process_event.c
--- ltrace-0.5/process_event.c	2011-10-25 09:15:34.000000000 -0400
+++ ltrace-0.5-64/process_event.c	2011-10-24 18:14:00.000000000 -0400
@@ -250,7 +250,9 @@ void process_event(struct event *event)
 
 		/* Note: the previous handler has a chance to alter
 		 * the event.  */
-		if (event->proc->leader != NULL) {
+		if (event->proc != NULL
+		    && event->proc->leader != NULL
+		    && event->proc != event->proc->leader) {
 			event = call_handler(event->proc->leader, event);
 			if (event == NULL)
 				/* It was handled.  */
@@ -353,7 +360,7 @@ static void process_syscall(struct event
 		}
 			callstack_push_syscall(event->proc, event->e_un.sysnum);
 	}
-	continue_process(event->proc->pid);
+	continue_after_syscall(event->proc, event->e_un.sysnum, 0);
 }
 
 static void process_exec(struct event * event) {
@@ -408,13 +415,16 @@ static void process_sysret(struct event 
 		if (opt_T || opt_c) {
 			calc_time_spent(event->proc);
 		}
+		assert(event->proc->callstack_depth > 0);
+		unsigned d = event->proc->callstack_depth - 1;
+		assert(event->proc->callstack[d].is_syscall);
 		callstack_pop(event->proc);
 		if (opt_S) {
 			output_right(LT_TOF_SYSCALLR, event->proc,
 				sysname(event->proc, event->e_un.sysnum));
 		}
 	}
-	continue_process(event->proc->pid);
+	continue_after_syscall(event->proc, event->e_un.sysnum, 1);
 }
 
 static void process_breakpoint(struct event *event)
diff -urp ltrace-0.5/sysdeps/linux-gnu/trace.c ltrace-0.5-64/sysdeps/linux-gnu/trace.c
--- ltrace-0.5/sysdeps/linux-gnu/trace.c	2011-10-25 09:15:34.000000000 -0400
+++ ltrace-0.5-64/sysdeps/linux-gnu/trace.c	2011-10-25 09:01:30.000000000 -0400
@@ -22,6 +22,7 @@
 #include "ltrace.h"
 #include "options.h"
 #include "sysdep.h"
+#include "debug.h"
 
 void trace_me(void)
 {
@@ -118,6 +128,7 @@ struct pid_task {
 	int got_event : 1;
 	int delivered : 1;
 	int vforked : 1;
+	int sysret : 1;
 } * pids;
 
 struct pid_set {
@@ -209,10 +209,14 @@ task_stopped(struct process * task, void
 	case ps_invalid:
 	case ps_tracing_stop:
 	case ps_zombie:
+	case ps_sleeping:
 		return pcb_cont;
-	default:
+	case ps_stop:
+	case ps_other:
 		return pcb_stop;
 	}
+
+	abort();
 }
 
 /* Task is blocked if it's stopped, or if it's a vfork parent.  */
@@ -322,9 +334,11 @@ process_stopping_done(struct process_sto
 {
 	size_t i;
 	if (!self->exiting) {
+		debug(1, "pid=%d", self->task_enabling_breakpoint->pid);
 		for (i = 0; i < self->pids.count; ++i)
 			if (self->pids.tasks[i].pid != 0
-			    && self->pids.tasks[i].delivered)
+			    && (self->pids.tasks[i].delivered
+				|| self->pids.tasks[i].sysret))
 				continue_process(self->pids.tasks[i].pid);
 		continue_process(self->task_enabling_breakpoint->pid);
 		destroy_event_handler(leader);
@@ -493,6 +514,14 @@ all_stops_accountable(struct pid_set * p
 	return 1;
 }
 
+static void
+singlestep(struct process * proc)
+{
+	debug(1, "PTRACE_SINGLESTEP");
+	if (ptrace(PTRACE_SINGLESTEP, proc->pid, 0, 0))
+		perror("PTRACE_SINGLESTEP");
+}
+
 /* This event handler is installed when we are in the process of
  * stopping the whole thread group to do the pointer re-enablement for
  * one of the threads.  We pump all events to the queue for later
@@ -520,23 +551,40 @@ process_stopping_on_event(Event_Handler 
 	if (event_exit_p(event) && task_info != NULL)
 		task_info->pid = 0;
 
+	/* Always handle sysrets.  Whether sysret occurred and what
+	 * sys it rets from may need to be determined based on process
+	 * stack, so we need to keep that in sync with reality.  Note
+	 * that we don't continue the process after the sysret is
+	 * handled.  See continue_after_syscall.  */
+	if (event != NULL && event->thing == LT_EV_SYSRET) {
+		debug(1, "%d LT_EV_SYSRET", event->proc->pid);
+		event_to_queue = 0;
+		task_info->sysret = 1;
+	}
+
 	switch (state) {
 	case psh_stopping:
 		/* If everyone is stopped, singlestep.  */
 		if (each_task(leader, &task_blocked, &self->pids) == NULL) {
 			if (sbp->enabled)
 				disable_breakpoint(teb, sbp);
-			if (ptrace(PTRACE_SINGLESTEP, teb->pid, 0, 0))
-				perror("PTRACE_SINGLESTEP");
+			singlestep(teb);
 			self->state = state = psh_singlestep;
 		}
 		break;
 
-	case psh_singlestep: {
+	case psh_singlestep:
 		/* In singlestep state, breakpoint signifies that we
 		 * have now stepped, and can re-enable the breakpoint.  */
 		if (event != NULL
 		    && task == self->task_enabling_breakpoint) {
+
+			/* This is not the singlestep that we are waiting for.  */
+			if (event->thing == LT_EV_SIGNAL) {
+				singlestep(task);
+				break;
+			}
+
 			/* Essentially we don't care what event caused
 			 * the thread to stop.  We can do the
 			 * re-enablement now.  */
@@ -561,7 +611,6 @@ process_stopping_on_event(Event_Handler 
 				event = NULL; // handled
 		} else
 			break;
-	}
 
 		/* fall-through */
 
@@ -870,6 +920,23 @@ continue_after_vfork(struct process * pr
 	change_process_leader(proc, proc->parent->leader);
 }
 
+static int
+is_mid_stopping(struct process *proc)
+{
+	return proc != NULL
+		&& proc->event_handler != NULL
+		&& proc->event_handler->on_event == &process_stopping_on_event;
+}
+
+void
+continue_after_syscall(struct process * proc, int sysnum, int ret_p)
+{
+	/* Don't continue if we are mid-stopping.  */
+	if (ret_p && (is_mid_stopping(proc) || is_mid_stopping(proc->leader)))
+		return;
+	continue_process(proc->pid);
+}
+
 /* If ltrace gets SIGINT, the processes directly or indirectly run by
  * ltrace get it too.  We just have to wait long enough for the signal
  * to be delivered and the process terminated, which we notice and
diff --git a/testsuite/ltrace.main/hello-vfork.c b/testsuite/ltrace.main/hello-vfork.c
new file mode 100644
index 0000000..228c052
--- /dev/null
+++ b/testsuite/ltrace.main/hello-vfork.c
@@ -0,0 +1,11 @@
+/* Copyright (C) 2008, Red Hat, Inc.
+ * Written by Denys Vlasenko */
+#include <stdio.h>
+#include <unistd.h>
+
+int main() {
+        int r = vfork();
+        fprintf(stderr, "vfork():%d\n", r);
+        _exit(0);
+}
+
diff --git a/testsuite/ltrace.main/hello-vfork.exp b/testsuite/ltrace.main/hello-vfork.exp
new file mode 100644
index 0000000..12c9ca3
--- /dev/null
+++ b/testsuite/ltrace.main/hello-vfork.exp
@@ -0,0 +1,35 @@
+# This file was written by Yao Qi <qiyao@cn.ibm.com>.
+
+set testfile "hello-vfork"
+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 "-f"
+
+# 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
+}
+
+# Verify the output by checking numbers of print in main-vfork.ltrace.
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace "_exit" 2
+ltrace_verify_output ${objdir}/${subdir}/${testfile}.ltrace "vfork resumed" 2