arch/arm/probes/uprobes/actions-arm.c

Source file repositories/reference/linux-study-clean/arch/arm/probes/uprobes/actions-arm.c

File Facts

System
Linux kernel
Corpus path
arch/arm/probes/uprobes/actions-arm.c
Extension
.c
Size
6090 bytes
Lines
230
Domain
Architecture Layer
Bucket
arch/arm
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
/*
 * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/wait.h>
#include <linux/uprobes.h>
#include <linux/module.h>

#include "../decode.h"
#include "../decode-arm.h"
#include "core.h"

static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
{
	probes_opcode_t insn = __mem_to_opcode_arm(*pinsn);
	probes_opcode_t temp;
	probes_opcode_t mask;
	int freereg;
	u32 free = 0xffff;
	u32 regs;

	for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
		if ((regs & 0xf) == REG_TYPE_NONE)
			continue;

		free &= ~(1 << (insn & 0xf));
	}

	/* No PC, no problem */
	if (free & (1 << 15))
		return 15;

	if (!free)
		return -1;

	/*
	 * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
	 * pick LR instead of R1.
	 */
	freereg = free = fls(free) - 1;

	temp = __mem_to_opcode_arm(*pinsn);
	insn = temp;
	regs = oregs;
	mask = 0xf;

	for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
		if ((regs & 0xf) == REG_TYPE_NONE)
			continue;

		if ((temp & 0xf) != 15)
			continue;

		insn &= ~mask;
		insn |= free & mask;
	}

	*pinsn = __opcode_to_mem_arm(insn);
	return freereg;
}

static void uprobe_set_pc(struct arch_uprobe *auprobe,
			  struct arch_uprobe_task *autask,
			  struct pt_regs *regs)
{
	u32 pcreg = auprobe->pcreg;

	autask->backup = regs->uregs[pcreg];
	regs->uregs[pcreg] = regs->ARM_pc + 8;
}

static void uprobe_unset_pc(struct arch_uprobe *auprobe,
			    struct arch_uprobe_task *autask,
			    struct pt_regs *regs)
{
	/* PC will be taken care of by common code */
	regs->uregs[auprobe->pcreg] = autask->backup;
}

static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe,
			       struct arch_uprobe_task *autask,
			       struct pt_regs *regs)
{
	u32 pcreg = auprobe->pcreg;

	alu_write_pc(regs->uregs[pcreg], regs);

Annotation

Implementation Notes