static void __stp_stack_print(struct pt_regs *regs, int verbose, int levels, struct task_struct *tsk, struct uretprobe_instance *ri, int uregs_valid) { #ifdef STP_USE_DWARF_UNWINDER int start_levels = levels; // FIXME: large stack allocation struct unwind_frame_info info; int sanitize = tsk && ! uregs_valid; arch_unw_init_frame_info(&info, regs, sanitize); while (levels && (tsk || !arch_unw_user_mode(&info))) { int ret = unwind(&info, tsk); #ifdef STAPCONF_UPROBE_GET_PC unsigned long maybe_pc = 0; if (ri) { maybe_pc = uprobe_get_pc(ri, UNW_PC(&info), UNW_SP(&info)); if (!maybe_pc) printk("SYSTEMTAP ERROR: uprobe_get_return returned 0\n"); else UNW_PC(&info) = maybe_pc; } #endif dbug_unwind(1, "ret=%d PC=%lx SP=%lx\n", ret, UNW_PC(&info), UNW_SP(&info)); if (ret == 0) { _stp_print_addr(UNW_PC(&info), verbose, tsk); levels--; if (UNW_PC(&info) != _stp_kretprobe_trampoline) continue; } /* If an error happened or we hit a kretprobe trampoline, * use fallback backtrace, unless user task backtrace. * FIXME: is there a way to unwind across kretprobe * trampolines? PR9999. */ if ((ret < 0 || UNW_PC(&info) == _stp_kretprobe_trampoline) && ! (tsk || arch_unw_user_mode(&info))) _stp_stack_print_fallback(UNW_SP(&info), verbose, levels); return; } #else /* ! STP_USE_DWARF_UNWINDER */ _stp_stack_print_fallback(REG_SP(regs), verbose, levels); #endif }
static int asmlinkage dump_trace_unwind(struct unwind_frame_info *info, const struct stacktrace_ops *ops, void *data) { int n = 0; #ifdef CONFIG_STACK_UNWIND unsigned long sp = UNW_SP(info); if (arch_unw_user_mode(info)) return -1; while (unwind(info) == 0 && UNW_PC(info)) { n++; ops->address(data, UNW_PC(info), 1); if (arch_unw_user_mode(info)) break; if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1)) && sp > UNW_SP(info)) break; sp = UNW_SP(info); } #endif return n; }
int try_stack_unwind(struct task_struct *task, struct pt_regs *regs, unsigned long **stack, unsigned long *bp, const struct stacktrace_ops *ops, void *data) { #ifdef CONFIG_STACK_UNWIND int unw_ret = 0; struct unwind_frame_info info; if (call_trace < 0) return 0; if (regs) { if (unwind_init_frame_info(&info, task, regs) == 0) unw_ret = dump_trace_unwind(&info, ops, data); } else if (task == current) unw_ret = unwind_init_running(&info, dump_trace_unwind, ops, data); #ifdef CONFIG_SMP else if (task->on_cpu) /* nothing */; #endif else if (unwind_init_blocked(&info, task) == 0) unw_ret = dump_trace_unwind(&info, ops, data); if (unw_ret > 0) { if (call_trace == 1 && !arch_unw_user_mode(&info)) { ops->warning_symbol(data, "DWARF2 unwinder stuck at %s\n", UNW_PC(&info)); if (UNW_SP(&info) >= PAGE_OFFSET) { ops->warning(data, "Leftover inexact backtrace:\n"); *stack = (void *)UNW_SP(&info); *bp = UNW_FP(&info); return 0; } } else if (call_trace >= 1) return -1; ops->warning(data, "Full inexact backtrace again:\n"); } else ops->warning(data, "Inexact backtrace:\n"); #endif return 0; }