static void __stp_dwarf_stack_user_print(struct pt_regs *regs, int verbose, int levels, struct unwind_context *uwcontext, struct uretprobe_instance *ri, int uregs_valid) { struct unwind_frame_info *info = &uwcontext->info; arch_unw_init_frame_info(info, regs, ! uregs_valid); while (levels) { int ret = unwind(uwcontext, 1); #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_valid_pc_addr(UNW_PC(info), current)) { _stp_print_addr(UNW_PC(info), verbose, current); levels--; continue; } /* If an error happened or the PC becomes invalid, then * we are done, _stp_stack_print_fallback is only for * kernel space. */ return; } }
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 unsigned long _stp_stack_unwind_one_user(struct context *c, unsigned depth) { struct pt_regs *regs = NULL; int uregs_valid = 0; struct uretprobe_instance *ri = NULL; struct unwind_frame_info *info = NULL; int ret; #ifdef STAPCONF_UPROBE_GET_PC unsigned long maybe_pc; #endif if (c->probe_type == stp_probe_type_uretprobe) ri = c->ips.ri; #ifdef STAPCONF_UPROBE_GET_PC else if (c->probe_type == stp_probe_type_uprobe) ri = GET_PC_URETPROBE_NONE; #endif /* XXX: The computation that gives this is cached, so calling * _stp_get_uregs multiple times is okay... probably. */ regs = _stp_get_uregs(c); uregs_valid = c->full_uregs_p; if (! current->mm || ! regs) return 0; // no user backtrace at this probe point if (depth == 0) { /* Start by fetching the current PC. */ dbug_unwind(1, "STARTING user unwind\n"); #ifdef STAPCONF_UPROBE_GET_PC if (c->probe_type == stp_probe_type_uretprobe && ri) { return ri->ret_addr; } else { return REG_IP(regs); } #else return REG_IP(regs); #endif } #ifdef STP_USE_DWARF_UNWINDER info = &c->uwcontext_user.info; dbug_unwind(1, "CONTINUING user unwind to depth %d\n", depth); if (depth == 1) { /* need to clear uregs & set up uwcontext->info */ if (c->uregs == &c->uwcontext_user.info.regs) { dbug_unwind(1, "clearing uregs\n"); /* Unwinder needs the reg state, clear uregs ref. */ c->uregs = NULL; c->full_uregs_p = 0; } arch_unw_init_frame_info(info, regs, 0); } ret = unwind(&c->uwcontext_user, 1); #ifdef STAPCONF_UPROBE_GET_PC 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=%llx SP=%llx\n", ret, (unsigned long long) UNW_PC(info), (unsigned long long) UNW_SP(info)); /* check if unwind hit an error */ if (ret || ! _stp_valid_pc_addr(UNW_PC(info), current)) { return 0; } return UNW_PC(info); #else /* User stack traces only supported for arches with dwarf unwinder. */ return 0; #endif }