This is the mail archive of the
systemtap@sourceware.org
mailing list for the systemtap project.
[Bug uprobes/5274] New: uprobes: Handle longjmps
- From: "jkenisto at us dot ibm dot com" <sourceware-bugzilla at sourceware dot org>
- To: systemtap at sources dot redhat dot com
- Date: 5 Nov 2007 23:16:55 -0000
- Subject: [Bug uprobes/5274] New: uprobes: Handle longjmps
- Reply-to: sourceware-bugzilla at sourceware dot org
As documented in Documentation/uprobes.txt, a longjmp in a probed program may
cause one or more uretprobed functions to terminate without returning. This
would leave uretprobe_instances on the task's list, with the result that (a)
bypassed uretprobe_instances accumulate without being freed, or (b) a bypassed
uretprobe_instance is mistaken for one further up the call chain -- resulting in
a return to the wrong address.
I think the following solution would work:
1. Add a stack_ptr member to struct uretprobe_instance. (That's what the
reserved1 member is for, actually.) When a uretprobed function is called, an
architecture-specific function is passed the regs pointer and asked to predict
the value of the stack pointer when that function returns. For powerpc, I think
it'd be the same as the current value. i386 or x86_64 would have to add 4 or 8
bytes to account for the return address being popped on return.
2. When a uretprobed function is called or returns, any uretprobe_instances with
stack_ptr beyond the current top of stack are presumed to have been previously
bypassed; they are recycled without calling their handlers.
3. Similarly, when a uretprobe is unregistered, each thread's
uretprobe_instances are examined, and any beyond the current TOS are recycled.
I think zap_uretprobe_instances() can do this safely, because it holds the uproc
write-locked, and no thread will fuss its uretprobe_instance list without
read-locking the uproc.
I have this mostly coded.
The x86 instruction set allows instructions like "ret $8", which means "pop the
return address, then pop 8 more bytes, then jump to the popped RA." Such
instructions would defeat this approach**, but such instructions also break the
ABI. [**unless we required the caller of register_uretprobe() to specify the
amount of "extra pop" in such instances]
BTW, on a related topic... For code like
extern void f1(void);
void f2(void) { f1(); }
the code generated for f2() may end with a JUMP to f1 rather than a call and
return. f1() returns to f2()'s return address. I think we're OK here even if
both f1() and f2() are uretprobed. When f2() is called, its return address will
be saved in a uretprobe_instance, and the uretprobe_trampoline address will
replace the return address on the stack. When f1() is entered, its
uretprobe_instance will get the uretprobe_trampoline address as its return
address... giving us the same situation we see when we have multiple uretprobes
associated with the same function.
--
Summary: uprobes: Handle longjmps
Product: systemtap
Version: unspecified
Status: NEW
Severity: normal
Priority: P2
Component: uprobes
AssignedTo: systemtap at sources dot redhat dot com
ReportedBy: jkenisto at us dot ibm dot com
http://sourceware.org/bugzilla/show_bug.cgi?id=5274
------- You are receiving this mail because: -------
You are the assignee for the bug, or are watching the assignee.