arch/arc/kernel/kprobes.c

Source file repositories/reference/linux-study-clean/arch/arc/kernel/kprobes.c

File Facts

System
Linux kernel
Corpus path
arch/arc/kernel/kprobes.c
Extension
.c
Size
10063 bytes
Lines
417
Domain
Architecture Layer
Bucket
arch/arc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (!p->ainsn.is_short) {
			if (bta & 0x01)
				regs->blink += 2;
			else {
				/* Branch not taken */
				next_pc += 2;

				/* next pc is taken from bta after executing the
				 * delay slot instruction
				 */
				regs->bta += 2;
			}
		}

		is_branch = 0;
	} else
		is_branch =
		    disasm_next_pc((unsigned long)p->addr, regs,
			(struct callee_regs *) current->thread.callee_reg,
			&next_pc, &tgt_if_br);

	p->ainsn.t1_addr = (kprobe_opcode_t *) next_pc;
	p->ainsn.t1_opcode = *(p->ainsn.t1_addr);
	*(p->ainsn.t1_addr) = TRAP_S_2_INSTRUCTION;

	flush_icache_range((unsigned long)p->ainsn.t1_addr,
			   (unsigned long)p->ainsn.t1_addr +
			   sizeof(kprobe_opcode_t));

	if (is_branch) {
		p->ainsn.t2_addr = (kprobe_opcode_t *) tgt_if_br;
		p->ainsn.t2_opcode = *(p->ainsn.t2_addr);
		*(p->ainsn.t2_addr) = TRAP_S_2_INSTRUCTION;

		flush_icache_range((unsigned long)p->ainsn.t2_addr,
				   (unsigned long)p->ainsn.t2_addr +
				   sizeof(kprobe_opcode_t));
	}
}

static int
__kprobes arc_kprobe_handler(unsigned long addr, struct pt_regs *regs)
{
	struct kprobe *p;
	struct kprobe_ctlblk *kcb;

	preempt_disable();

	kcb = get_kprobe_ctlblk();
	p = get_kprobe((unsigned long *)addr);

	if (p) {
		/*
		 * We have reentered the kprobe_handler, since another kprobe
		 * was hit while within the handler, we save the original
		 * kprobes and single step on the instruction of the new probe
		 * without calling any user handlers to avoid recursive
		 * kprobes.
		 */
		if (kprobe_running()) {
			save_previous_kprobe(kcb);
			set_current_kprobe(p);
			kprobes_inc_nmissed_count(p);
			setup_singlestep(p, regs);
			kcb->kprobe_status = KPROBE_REENTER;
			return 1;
		}

		set_current_kprobe(p);
		kcb->kprobe_status = KPROBE_HIT_ACTIVE;

		/* If we have no pre-handler or it returned 0, we continue with
		 * normal processing. If we have a pre-handler and it returned
		 * non-zero - which means user handler setup registers to exit
		 * to another instruction, we must skip the single stepping.
		 */
		if (!p->pre_handler || !p->pre_handler(p, regs)) {
			setup_singlestep(p, regs);
			kcb->kprobe_status = KPROBE_HIT_SS;
		} else {
			reset_current_kprobe();
			preempt_enable_no_resched();
		}

		return 1;
	}

	/* no_kprobe: */
	preempt_enable_no_resched();
	return 0;

Annotation

Implementation Notes