arch/loongarch/kernel/uprobes.c

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

File Facts

System
Linux kernel
Corpus path
arch/loongarch/kernel/uprobes.c
Extension
.c
Size
3210 bytes
Lines
145
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

// SPDX-License-Identifier: GPL-2.0-only
#include <linux/highmem.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/uprobes.h>
#include <asm/cacheflush.h>

#define UPROBE_TRAP_NR	UINT_MAX

int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
			     struct mm_struct *mm, unsigned long addr)
{
	int idx;
	union loongarch_instruction insn;

	if (addr & 0x3)
		return -EILSEQ;

	for (idx = ARRAY_SIZE(auprobe->insn) - 1; idx >= 0; idx--) {
		insn.word = auprobe->insn[idx];
		if (insns_not_supported(insn))
			return -EINVAL;
	}

	if (insns_need_simulation(insn)) {
		auprobe->ixol[0] = larch_insn_gen_nop();
		auprobe->simulate = true;
	} else {
		auprobe->ixol[0] = auprobe->insn[0];
		auprobe->simulate = false;
	}

	auprobe->ixol[1] = UPROBE_XOLBP_INSN;

	return 0;
}

int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
	struct uprobe_task *utask = current->utask;

	utask->autask.saved_trap_nr = current->thread.trap_nr;
	current->thread.trap_nr = UPROBE_TRAP_NR;
	instruction_pointer_set(regs, utask->xol_vaddr);

	return 0;
}

int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
	struct uprobe_task *utask = current->utask;

	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
	current->thread.trap_nr = utask->autask.saved_trap_nr;
	instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);

	return 0;
}

void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
	struct uprobe_task *utask = current->utask;

	current->thread.trap_nr = utask->autask.saved_trap_nr;
	instruction_pointer_set(regs, utask->vaddr);
}

bool arch_uprobe_xol_was_trapped(struct task_struct *t)
{
	if (t->thread.trap_nr != UPROBE_TRAP_NR)
		return true;

	return false;
}

bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
{
	union loongarch_instruction insn;

	if (!auprobe->simulate)
		return false;

	insn.word = auprobe->insn[0];
	arch_simulate_insn(insn, regs);

	return true;
}

unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
						struct pt_regs *regs)

Annotation

Implementation Notes