Bug 12026

Summary: Revamp task_backtrace() to use same unwinder backtrace()
Product: systemtap Reporter: William Cohen <wcohen>
Component: runtimeAssignee: Unassigned <systemtap>
Severity: normal CC: mark
Priority: P2    
Version: unspecified   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Bug Depends on:    
Bug Blocks: 6960    

Description William Cohen 2010-09-15 21:32:07 UTC
The task_backtrace() uses it own unwinder mechanism in _stp_stack_print_tsk().
It looks like there could be some simplification if task_backtrace(), used the
machinery as backtrace(). It might also make the task_backtrace() work better
than the current version of task_backtrace().

A improved version of task_backtrace() would be very useful for improving the
performance of latencytap.
Comment 1 Mark Wielaard 2010-09-27 21:49:32 UTC
function task_backtrace:string (task:long) defined in context-unwind.stp is
different from all other backtrace related functions like [[s]print][u]backtrace().

task_backtrace uses the function _stp_stack_[sn]print_tsk defined in stack.c and
only works when STAPCONF_KERNEL_STACKTRACE is defined true. This is the
in-kernel backtrace fallback which only works when there are frame pointers. All
other unwind related tapset functions go through _stp_stack_print (also from
stack.c). This uses the dwarf unwinder when possible and falls back to an
architecture specific unwinder or the in-kernel backtrace support when available.

Ideally task_backtrace, _stp_stack_[sn]print_tsk, would go through
_stp_stack_print also, so that it would invoke the dwarf unwinder. Currently
_stp_stack_print only works for the current task (if no task/NULL is given a
kernel backtrace is generated). This is because it needs to get a current set of
registers to init the dwarf unwinder state.

The register set comes either from CONTEXT->regs, if CONTEXT->regflags marks it
as valid for the current kernel/user space context. Or through
task_pt_regs(current). In the later case it uses _stp_task_pt_regs_valid from
runtime/compatdefs.h to check whether the register set is valid.

_stp_task_pt_regs_valid uses a very crude heuristic. It assumes the given task
== current, and if so (because the current task must have hit a probe point) the
register set returned by task_pt_regs(current) is valid if it the architecture
is i386, otherwise it is not. (See the XXX in the function comments for some
hints on improving on this.)

The above heuristic cannot really be used when using arbitrary tasks, since they
may be in any state (since they have not just been hitting a probe point). So
they may be running in either user or kernel space, so the register set you get
from task_pt_regs might not be current/sane.

It might be possible to just try to use the results of task_pt_regs and make the
result invalid (so the dwarf unwinder will use as little of the register set as
possible, see arch_unw_init_frame_info sanitize), and just hope for the best.
But this might give inaccurate/invalid/wrong backtraces.

Note that even if the register set is setup correctly the dwarf unwinder still
needs the unwind frame data of the task to function (for user space).

BTW. Double check security impact of this. Inspection of backtraces of tasks
not-owned by the user running the script should be disallowed.
Comment 2 Mark Wielaard 2011-11-29 10:01:57 UTC
Since systemtap 1.6:

- Deprecated task_backtrace:string (task:long). This function will go
  away after 1.6. Please run your scripts with stap --check-version.