arch/x86/kernel/kprobes/opt.c

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

File Facts

System
Linux kernel
Corpus path
arch/x86/kernel/kprobes/opt.c
Extension
.c
Size
14827 bytes
Lines
552
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

if (kp && kprobe_optimized(kp)) {
			op = container_of(kp, struct optimized_kprobe, kp);
			/* If op is optimized or under unoptimizing */
			if (list_empty(&op->list) || optprobe_queued_unopt(op))
				goto found;
		}
	}

	return addr;
found:
	/*
	 * If the kprobe can be optimized, original bytes which can be
	 * overwritten by jump destination address. In this case, original
	 * bytes must be recovered from op->optinsn.copied_insn buffer.
	 */
	if (copy_from_kernel_nofault(buf, (void *)addr,
		MAX_INSN_SIZE * sizeof(kprobe_opcode_t)))
		return 0UL;

	if (addr == (unsigned long)kp->addr) {
		buf[0] = kp->opcode;
		memcpy(buf + 1, op->optinsn.copied_insn, DISP32_SIZE);
	} else {
		offs = addr - (unsigned long)kp->addr - 1;
		memcpy(buf, op->optinsn.copied_insn + offs, DISP32_SIZE - offs);
	}

	return (unsigned long)buf;
}

static void synthesize_clac(kprobe_opcode_t *addr)
{
	/*
	 * Can't be static_cpu_has() due to how objtool treats this feature bit.
	 * This isn't a fast path anyway.
	 */
	if (!boot_cpu_has(X86_FEATURE_SMAP))
		return;

	/* Replace the NOP3 with CLAC */
	addr[0] = 0x0f;
	addr[1] = 0x01;
	addr[2] = 0xca;
}

/* Insert a move instruction which sets a pointer to eax/rdi (1st arg). */
static void synthesize_set_arg1(kprobe_opcode_t *addr, unsigned long val)
{
#ifdef CONFIG_X86_64
	*addr++ = 0x48;
	*addr++ = 0xbf;
#else
	*addr++ = 0xb8;
#endif
	*(unsigned long *)addr = val;
}

asm (
			".pushsection .rodata\n"
			".global optprobe_template_entry\n"
			"optprobe_template_entry:\n"
#ifdef CONFIG_X86_64
			"       pushq $" __stringify(__KERNEL_DS) "\n"
			/* Save the 'sp - 8', this will be fixed later. */
			"	pushq %rsp\n"
			"	pushfq\n"
			".global optprobe_template_clac\n"
			"optprobe_template_clac:\n"
			ASM_NOP3
			SAVE_REGS_STRING
			"	movq %rsp, %rsi\n"
			".global optprobe_template_val\n"
			"optprobe_template_val:\n"
			ASM_NOP5
			ASM_NOP5
			".global optprobe_template_call\n"
			"optprobe_template_call:\n"
			ASM_NOP5
			/* Copy 'regs->flags' into 'regs->ss'. */
			"	movq 18*8(%rsp), %rdx\n"
			"	movq %rdx, 20*8(%rsp)\n"
			RESTORE_REGS_STRING
			/* Skip 'regs->flags' and 'regs->sp'. */
			"	addq $16, %rsp\n"
			/* And pop flags register from 'regs->ss'. */
			"	popfq\n"
#else /* CONFIG_X86_32 */
			"	pushl %ss\n"
			/* Save the 'sp - 4', this will be fixed later. */
			"	pushl %esp\n"

Annotation

Implementation Notes