arch/arm64/kernel/probes/kprobes.c

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

File Facts

System
Linux kernel
Corpus path
arch/arm64/kernel/probes/kprobes.c
Extension
.c
Size
10937 bytes
Lines
427
Domain
Architecture Layer
Bucket
arch/arm64
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 (kcb->kprobe_status == KPROBE_REENTER) {
			restore_previous_kprobe(kcb);
		} else {
			kprobes_restore_local_irqflag(kcb, regs);
			reset_current_kprobe();
		}

		break;
	}
	return 0;
}

int __kprobes
kprobe_brk_handler(struct pt_regs *regs, unsigned long esr)
{
	struct kprobe *p, *cur_kprobe;
	struct kprobe_ctlblk *kcb;
	unsigned long addr = instruction_pointer(regs);

	kcb = get_kprobe_ctlblk();
	cur_kprobe = kprobe_running();

	p = get_kprobe((kprobe_opcode_t *) addr);
	if (WARN_ON_ONCE(!p)) {
		/*
		 * Something went wrong. This BRK used an immediate reserved
		 * for kprobes, but we couldn't find any corresponding probe.
		 */
		return DBG_HOOK_ERROR;
	}

	if (cur_kprobe) {
		/* Hit a kprobe inside another kprobe */
		if (!reenter_kprobe(p, regs, kcb))
			return DBG_HOOK_ERROR;
	} 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 not need to single-step
		 * Let's just reset current kprobe and exit.
		 */
		if (!p->pre_handler || !p->pre_handler(p, regs))
			setup_singlestep(p, regs, kcb, 0);
		else
			reset_current_kprobe();
	}

	return DBG_HOOK_HANDLED;
}

int __kprobes
kprobe_ss_brk_handler(struct pt_regs *regs, unsigned long esr)
{
	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
	unsigned long addr = instruction_pointer(regs);
	struct kprobe *cur = kprobe_running();

	if (cur && (kcb->kprobe_status & (KPROBE_HIT_SS | KPROBE_REENTER)) &&
	    ((unsigned long)&cur->ainsn.xol_insn[1] == addr)) {
		kprobes_restore_local_irqflag(kcb, regs);
		post_kprobe_handler(cur, kcb, regs);

		return DBG_HOOK_HANDLED;
	}

	/* not ours, kprobes should ignore it */
	return DBG_HOOK_ERROR;
}

int __kprobes
kretprobe_brk_handler(struct pt_regs *regs, unsigned long esr)
{
	if (regs->pc != (unsigned long)__kretprobe_trampoline)
		return DBG_HOOK_ERROR;

	regs->pc = kretprobe_trampoline_handler(regs, (void *)regs->regs[29]);
	return DBG_HOOK_HANDLED;
}

/*
 * Provide a blacklist of symbols identifying ranges which cannot be kprobed.
 * This blacklist is exposed to userspace via debugfs (kprobes/blacklist).
 */
int __init arch_populate_kprobe_blacklist(void)

Annotation

Implementation Notes