arch/loongarch/kernel/kprobes.c

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

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kernel/kprobes.c
Extension
.c
Size
8595 bytes
Lines
341
Domain
Architecture Layer
Bucket
arch/loongarch
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 (cur_kprobe) {
			if (reenter_kprobe(p, regs, kcb))
				return true;
		} else {
			/* Probe hit */
			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, it will
			 * modify the execution path and no need to single
			 * stepping. Let's just reset current kprobe and exit.
			 *
			 * pre_handler can hit a breakpoint and can step thru
			 * before return.
			 */
			if (!p->pre_handler || !p->pre_handler(p, regs)) {
				setup_singlestep(p, regs, kcb, 0);
			} else {
				reset_current_kprobe();
				preempt_enable_no_resched();
			}
			return true;
		}
	}

	if (*addr != KPROBE_BP_INSN) {
		/*
		 * The breakpoint instruction was removed right
		 * after we hit it.  Another cpu has removed
		 * either a probepoint or a debugger breakpoint
		 * at this address.  In either case, no further
		 * handling of this interrupt is appropriate.
		 * Return back to original instruction, and continue.
		 */
		regs->csr_era = (unsigned long)addr;
		preempt_enable_no_resched();
		return true;
	}

	preempt_enable_no_resched();
	return false;
}
NOKPROBE_SYMBOL(kprobe_breakpoint_handler);

bool kprobe_singlestep_handler(struct pt_regs *regs)
{
	struct kprobe *cur = kprobe_running();
	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
	unsigned long addr = instruction_pointer(regs);

	if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) &&
	    ((unsigned long)&cur->ainsn.insn[1] == addr)) {
		restore_local_irqflag(kcb, regs);
		post_kprobe_handler(cur, kcb, regs);
		return true;
	}

	preempt_enable_no_resched();
	return false;
}
NOKPROBE_SYMBOL(kprobe_singlestep_handler);

bool kprobe_fault_handler(struct pt_regs *regs, int trapnr)
{
	struct kprobe *cur = kprobe_running();
	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();

	switch (kcb->kprobe_status) {
	case KPROBE_HIT_SS:
	case KPROBE_REENTER:
		/*
		 * We are here because the instruction being single
		 * stepped caused a page fault. We reset the current
		 * kprobe and the ip points back to the probe address
		 * and allow the page fault handler to continue as a
		 * normal page fault.
		 */
		regs->csr_era = (unsigned long)cur->addr;
		WARN_ON_ONCE(!instruction_pointer(regs));

		if (kcb->kprobe_status == KPROBE_REENTER) {
			restore_previous_kprobe(kcb);
		} else {
			restore_local_irqflag(kcb, regs);
			reset_current_kprobe();
		}
		preempt_enable_no_resched();

Annotation

Implementation Notes