示例#1
0
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;
	}
}
示例#2
0
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
}
示例#3
0
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
}