arch/x86/kernel/kprobes/core.c

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

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/kprobes/core.c
Extension
.c
Size
32199 bytes
Lines
1082
Domain
Architecture Layer
Bucket
arch/x86
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

struct __arch_relative_insn {
		u8 op;
		s32 raddr;
	} __packed *insn;

	insn = (struct __arch_relative_insn *)dest;
	insn->raddr = (s32)((long)(to) - ((long)(from) + 5));
	insn->op = op;
}

/* Insert a jump instruction at address 'from', which jumps to address 'to'.*/
void synthesize_reljump(void *dest, void *from, void *to)
{
	__synthesize_relative_insn(dest, from, to, JMP32_INSN_OPCODE);
}
NOKPROBE_SYMBOL(synthesize_reljump);

/* Insert a call instruction at address 'from', which calls address 'to'.*/
void synthesize_relcall(void *dest, void *from, void *to)
{
	__synthesize_relative_insn(dest, from, to, CALL_INSN_OPCODE);
}
NOKPROBE_SYMBOL(synthesize_relcall);

/*
 * Returns non-zero if INSN is boostable.
 * RIP relative instructions are adjusted at copying time in 64 bits mode
 */
bool can_boost(struct insn *insn, void *addr)
{
	kprobe_opcode_t opcode;
	insn_byte_t prefix;

	if (search_exception_tables((unsigned long)addr))
		return false;	/* Page fault may occur on this address. */

	/* 2nd-byte opcode */
	if (insn->opcode.nbytes == 2)
		return test_bit(insn->opcode.bytes[1],
				(unsigned long *)twobyte_is_boostable);

	if (insn->opcode.nbytes != 1)
		return false;

	for_each_insn_prefix(insn, prefix) {
		insn_attr_t attr;

		attr = inat_get_opcode_attribute(prefix);
		/* Can't boost Address-size override prefix and CS override prefix */
		if (prefix == 0x2e || inat_is_address_size_prefix(attr))
			return false;
	}

	opcode = insn->opcode.bytes[0];

	switch (opcode) {
	case 0x62:		/* bound */
	case 0x70 ... 0x7f:	/* Conditional jumps */
	case 0x9a:		/* Call far */
	case 0xcc ... 0xce:	/* software exceptions */
	case 0xd6:		/* (UD) */
	case 0xd8 ... 0xdf:	/* ESC */
	case 0xe0 ... 0xe3:	/* LOOP*, JCXZ */
	case 0xe8 ... 0xe9:	/* near Call, JMP */
	case 0xeb:		/* Short JMP */
	case 0xf0 ... 0xf4:	/* LOCK/REP, HLT */
		/* ... are not boostable */
		return false;
	case 0xc0 ... 0xc1:	/* Grp2 */
	case 0xd0 ... 0xd3:	/* Grp2 */
		/*
		 * AMD uses nnn == 110 as SHL/SAL, but Intel makes it reserved.
		 */
		return X86_MODRM_REG(insn->modrm.bytes[0]) != 0b110;
	case 0xf6 ... 0xf7:	/* Grp3 */
		/* AMD uses nnn == 001 as TEST, but Intel makes it reserved. */
		return X86_MODRM_REG(insn->modrm.bytes[0]) != 0b001;
	case 0xfe:		/* Grp4 */
		/* Only INC and DEC are boostable */
		return X86_MODRM_REG(insn->modrm.bytes[0]) == 0b000 ||
		       X86_MODRM_REG(insn->modrm.bytes[0]) == 0b001;
	case 0xff:		/* Grp5 */
		/* Only INC, DEC, and indirect JMP are boostable */
		return X86_MODRM_REG(insn->modrm.bytes[0]) == 0b000 ||
		       X86_MODRM_REG(insn->modrm.bytes[0]) == 0b001 ||
		       X86_MODRM_REG(insn->modrm.bytes[0]) == 0b100;
	default:
		return true;
	}
}

Annotation

Implementation Notes