コード例 #1
0
static void dump_backtrace_entry(unsigned long where, unsigned long stack)
{
	print_ip_sym(where);
	if (in_exception_text(where))
		dump_mem("", "Exception stack", stack,
			 stack + sizeof(struct pt_regs));
}
コード例 #2
0
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
	kprobe_opcode_t insn;
	kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
	unsigned long addr = (unsigned long)p->addr;
	int is;

	if (addr & 0x3 || in_exception_text(addr))
		return -EINVAL;

	insn = *p->addr;
	p->opcode = insn;
	p->ainsn.insn = tmp_insn;

	switch (arm_kprobe_decode_insn(insn, &p->ainsn)) {
	case INSN_REJECTED:	/* not supported */
		return -EINVAL;

	case INSN_GOOD:		/* instruction uses slot */
		p->ainsn.insn = get_insn_slot();
		if (!p->ainsn.insn)
			return -ENOMEM;
		for (is = 0; is < MAX_INSN_SIZE; ++is)
			p->ainsn.insn[is] = tmp_insn[is];
		flush_insns(p->ainsn.insn, MAX_INSN_SIZE);
		break;

	case INSN_GOOD_NO_SLOT:	/* instruction doesn't need insn slot */
		p->ainsn.insn = NULL;
		break;
	}

	return 0;
}
コード例 #3
0
ファイル: traps.c プロジェクト: Duiesel/ZTE_Blade_L5
static void dump_backtrace_entry(unsigned long where, unsigned long stack)
{
	print_ip_sym(where);
	if (in_exception_text(where))
		dump_mem("", "Exception stack", stack,
			 stack + sizeof(struct pt_regs) + 180); /* Additional 180 to workaround sp offset */
}
コード例 #4
0
ファイル: kprobes.c プロジェクト: 1ee7/linux_l4t_tx1
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
	kprobe_opcode_t insn;
	kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
	unsigned long addr = (unsigned long)p->addr;
	bool thumb;
	kprobe_decode_insn_t *decode_insn;
	int is;

	if (in_exception_text(addr))
		return -EINVAL;

#ifdef CONFIG_THUMB2_KERNEL
	thumb = true;
	addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
	insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
	if (is_wide_instruction(insn)) {
		u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
		insn = __opcode_thumb32_compose(insn, inst2);
		decode_insn = thumb32_kprobe_decode_insn;
	} else
		decode_insn = thumb16_kprobe_decode_insn;
#else /* !CONFIG_THUMB2_KERNEL */
	thumb = false;
	if (addr & 0x3)
		return -EINVAL;
	insn = __mem_to_opcode_arm(*p->addr);
	decode_insn = arm_kprobe_decode_insn;
#endif

	p->opcode = insn;
	p->ainsn.insn = tmp_insn;

	switch ((*decode_insn)(insn, &p->ainsn)) {
	case INSN_REJECTED:	/* not supported */
		return -EINVAL;

	case INSN_GOOD:		/* instruction uses slot */
		p->ainsn.insn = get_insn_slot();
		if (!p->ainsn.insn)
			return -ENOMEM;
		for (is = 0; is < MAX_INSN_SIZE; ++is)
			p->ainsn.insn[is] = tmp_insn[is];
		flush_insns(p->ainsn.insn,
				sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
		p->ainsn.insn_fn = (kprobe_insn_fn_t *)
					((uintptr_t)p->ainsn.insn | thumb);
		break;

	case INSN_GOOD_NO_SLOT:	/* instruction doesn't need insn slot */
		p->ainsn.insn = NULL;
		break;
	}

	return 0;
}
コード例 #5
0
ファイル: aed-process.c プロジェクト: bju2000/mediatek
static int aed_walk_stackframe(struct stackframe *frame, struct aee_process_bt *bt,
                               unsigned int stack_address)
{
    int count;
    struct stackframe current_stk;
    bt->entries = aed_backtrace_buffer;

    memcpy(&current_stk, frame, sizeof(struct stackframe));
    for (count = 0; count < AEE_NR_FRAME; count++) {
        unsigned long prev_fp = current_stk.fp;
        int ret;

        bt->entries[bt->nr_entries].pc = current_stk.pc;
        bt->entries[bt->nr_entries].lr = current_stk.lr;
        snprintf(bt->entries[bt->nr_entries].pc_symbol, AEE_SZ_SYMBOL_S, "%pS",
                 (void *)current_stk.pc);
        snprintf(bt->entries[bt->nr_entries].lr_symbol, AEE_SZ_SYMBOL_L, "%pS",
                 (void *)current_stk.lr);

        bt->nr_entries++;
        if (bt->nr_entries >= AEE_NR_FRAME) {
            break;
        }

        ret = aed_unwind_frame(&current_stk, stack_address);
        /* oops, reached end without exception. return original info */
        if (ret < 0)
            break;

        if (in_exception_text(current_stk.pc)
                || ((current_stk.pc - FUNCTION_OFFSET) ==
                    (unsigned long)preempt_schedule_irq)) {
            struct pt_regs *regs = (struct pt_regs *)(prev_fp + 4);

            /* passed exception point, return this if unwinding is sucessful */
            current_stk.pc = regs->ARM_pc;
            current_stk.lr = regs->ARM_lr;
            current_stk.fp = regs->ARM_fp;
            current_stk.sp = regs->ARM_sp;
        }

    }

    if (bt->nr_entries < AEE_NR_FRAME) {
        bt->entries[bt->nr_entries].pc = ULONG_MAX;
        bt->entries[bt->nr_entries].pc_symbol[0] = '\0';
        bt->entries[bt->nr_entries].lr = ULONG_MAX;
        bt->entries[bt->nr_entries++].lr_symbol[0] = '\0';
    }
    return 0;
}
コード例 #6
0
inline void aee_print_bt(struct pt_regs *regs)
{
    int i;
    unsigned long high, bottom, fp;
    struct stackframe cur_frame;
    struct pt_regs *exp_regs;
    bottom = regs->ARM_sp;
    if (!virt_addr_valid(bottom)) {
        aee_nested_printf("invalid sp[%x]\n", regs);
        return;
    }
    high = ALIGN(bottom, THREAD_SIZE);
    cur_frame.lr = regs->ARM_lr;
    cur_frame.fp = regs->ARM_fp;
    cur_frame.pc = regs->ARM_pc;
    for (i = 0; i < AEE_MAX_EXCP_FRAME; i++) {
        fp = cur_frame.fp;
        if ((fp < (bottom + 12)) || ((fp + 4) >= (high + 8192))) {
            if (fp != 0)
                aee_nested_printf("fp(%x)", fp);
            break;
        }
        cur_frame.fp = *(unsigned long *)(fp - 12);
        cur_frame.lr = *(unsigned long *)(fp - 4);
        cur_frame.pc = *(unsigned long *)fp;
        if (!
                ((cur_frame.lr >= (PAGE_OFFSET + THREAD_SIZE))
                 && virt_addr_valid(cur_frame.lr)))
            break;
        if (in_exception_text(cur_frame.pc)) {
            exp_regs = (struct pt_regs *)(fp + 4);
            cur_frame.lr = exp_regs->ARM_pc;
        }
        aee_nested_printf("%08lx, ", cur_frame.lr);
    }
    aee_nested_printf("\n");
    return;
}
コード例 #7
0
ファイル: stacktrace.c プロジェクト: 0-T-0/ps4-linux
static int save_trace(struct stackframe *frame, void *d)
{
	struct stack_trace_data *data = d;
	struct stack_trace *trace = data->trace;
	struct pt_regs *regs;
	unsigned long addr = frame->pc;

	if (data->no_sched_functions && in_sched_functions(addr))
		return 0;
	if (data->skip) {
		data->skip--;
		return 0;
	}

	trace->entries[trace->nr_entries++] = addr;

	if (trace->nr_entries >= trace->max_entries)
		return 1;

	/*
	 * in_exception_text() is designed to test if the PC is one of
	 * the functions which has an exception stack above it, but
	 * unfortunately what is in frame->pc is the return LR value,
	 * not the saved PC value.  So, we need to track the previous
	 * frame PC value when doing this.
	 */
	addr = data->last_pc;
	data->last_pc = frame->pc;
	if (!in_exception_text(addr))
		return 0;

	regs = (struct pt_regs *)frame->sp;

	trace->entries[trace->nr_entries++] = regs->ARM_pc;

	return trace->nr_entries >= trace->max_entries;
}
コード例 #8
0
void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk)
{
	struct stackframe frame;
	unsigned long irq_stack_ptr;
	int skip;

	pr_debug("%s(regs = %p tsk = %p)\n", __func__, regs, tsk);

	if (!tsk)
		tsk = current;

	if (!try_get_task_stack(tsk))
		return;

	/*
	 * Switching between stacks is valid when tracing current and in
	 * non-preemptible context.
	 */
	if (tsk == current && !preemptible())
		irq_stack_ptr = IRQ_STACK_PTR(smp_processor_id());
	else
		irq_stack_ptr = 0;

	if (tsk == current) {
		frame.fp = (unsigned long)__builtin_frame_address(0);
		frame.sp = current_stack_pointer;
		frame.pc = (unsigned long)dump_backtrace;
	} else {
		/*
		 * task blocked in __switch_to
		 */
		frame.fp = thread_saved_fp(tsk);
		frame.sp = thread_saved_sp(tsk);
		frame.pc = thread_saved_pc(tsk);
	}
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
	frame.graph = tsk->curr_ret_stack;
#endif

	skip = !!regs;
	printk("Call trace:\n");
	while (1) {
		unsigned long where = frame.pc;
		unsigned long stack;
		int ret;

		/* skip until specified stack frame */
		if (!skip) {
			dump_backtrace_entry(where);
		} else if (frame.fp == regs->regs[29]) {
			skip = 0;
			/*
			 * Mostly, this is the case where this function is
			 * called in panic/abort. As exception handler's
			 * stack frame does not contain the corresponding pc
			 * at which an exception has taken place, use regs->pc
			 * instead.
			 */
			dump_backtrace_entry(regs->pc);
		}
		ret = unwind_frame(tsk, &frame);
		if (ret < 0)
			break;
		stack = frame.sp;
		if (in_exception_text(where)) {
			/*
			 * If we switched to the irq_stack before calling this
			 * exception handler, then the pt_regs will be on the
			 * task stack. The easiest way to tell is if the large
			 * pt_regs would overlap with the end of the irq_stack.
			 */
			if (stack < irq_stack_ptr &&
			    (stack + sizeof(struct pt_regs)) > irq_stack_ptr)
				stack = IRQ_STACK_TO_TASK_STACK(irq_stack_ptr);

			dump_mem("", "Exception stack", stack,
				 stack + sizeof(struct pt_regs));
		}
	}

	put_task_stack(tsk);
}
コード例 #9
0
ファイル: core.c プロジェクト: 0-T-0/ps4-linux
int __kprobes arch_prepare_kprobe(struct kprobe *p)
{
	kprobe_opcode_t insn;
	kprobe_opcode_t tmp_insn[MAX_INSN_SIZE];
	unsigned long addr = (unsigned long)p->addr;
	bool thumb;
	kprobe_decode_insn_t *decode_insn;
	const union decode_action *actions;
	int is;
	const struct decode_checker **checkers;

	if (in_exception_text(addr))
		return -EINVAL;

#ifdef CONFIG_THUMB2_KERNEL
	thumb = true;
	addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */
	insn = __mem_to_opcode_thumb16(((u16 *)addr)[0]);
	if (is_wide_instruction(insn)) {
		u16 inst2 = __mem_to_opcode_thumb16(((u16 *)addr)[1]);
		insn = __opcode_thumb32_compose(insn, inst2);
		decode_insn = thumb32_probes_decode_insn;
		actions = kprobes_t32_actions;
		checkers = kprobes_t32_checkers;
	} else {
		decode_insn = thumb16_probes_decode_insn;
		actions = kprobes_t16_actions;
		checkers = kprobes_t16_checkers;
	}
#else /* !CONFIG_THUMB2_KERNEL */
	thumb = false;
	if (addr & 0x3)
		return -EINVAL;
	insn = __mem_to_opcode_arm(*p->addr);
	decode_insn = arm_probes_decode_insn;
	actions = kprobes_arm_actions;
	checkers = kprobes_arm_checkers;
#endif

	p->opcode = insn;
	p->ainsn.insn = tmp_insn;

	switch ((*decode_insn)(insn, &p->ainsn, true, actions, checkers)) {
	case INSN_REJECTED:	/* not supported */
		return -EINVAL;

	case INSN_GOOD:		/* instruction uses slot */
		p->ainsn.insn = get_insn_slot();
		if (!p->ainsn.insn)
			return -ENOMEM;
		for (is = 0; is < MAX_INSN_SIZE; ++is)
			p->ainsn.insn[is] = tmp_insn[is];
		flush_insns(p->ainsn.insn,
				sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE);
		p->ainsn.insn_fn = (probes_insn_fn_t *)
					((uintptr_t)p->ainsn.insn | thumb);
		break;

	case INSN_GOOD_NO_SLOT:	/* instruction doesn't need insn slot */
		p->ainsn.insn = NULL;
		break;
	}

	/*
	 * Never instrument insn like 'str r0, [sp, +/-r1]'. Also, insn likes
	 * 'str r0, [sp, #-68]' should also be prohibited.
	 * See __und_svc.
	 */
	if ((p->ainsn.stack_space < 0) ||
			(p->ainsn.stack_space > MAX_STACK_SIZE))
		return -EINVAL;

	return 0;
}