arch/x86/events/utils.c

Source file repositories/reference/linux-study-clean/arch/x86/events/utils.c

File Facts

System
Linux kernel
Corpus path
arch/x86/events/utils.c
Extension
.c
Size
6733 bytes
Lines
254
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

switch (insn->opcode.bytes[1]) {
		case 0x05: /* syscall */
		case 0x34: /* sysenter */
			return X86_BR_SYSCALL;
		case 0x07: /* sysret */
		case 0x35: /* sysexit */
			return X86_BR_SYSRET;
		case 0x80 ... 0x8f: /* conditional */
			return X86_BR_JCC;
		}
		return X86_BR_NONE;
	case 0x70 ... 0x7f: /* conditional */
		return X86_BR_JCC;
	case 0xc2: /* near ret */
	case 0xc3: /* near ret */
	case 0xca: /* far ret */
	case 0xcb: /* far ret */
		return X86_BR_RET;
	case 0xcf: /* iret */
		return X86_BR_IRET;
	case 0xcc ... 0xce: /* int */
		return X86_BR_INT;
	case 0xe8: /* call near rel */
		if (insn_get_immediate(insn) || insn->immediate1.value == 0) {
			/* zero length call */
			return X86_BR_ZERO_CALL;
		}
		fallthrough;
	case 0x9a: /* call far absolute */
		return X86_BR_CALL;
	case 0xe0 ... 0xe3: /* loop jmp */
		return X86_BR_JCC;
	case 0xe9 ... 0xeb: /* jmp */
		return X86_BR_JMP;
	case 0xff: /* call near absolute, call far absolute ind */
		if (insn_get_modrm(insn))
			return X86_BR_ABORT;

		ext = (insn->modrm.bytes[0] >> 3) & 0x7;
		switch (ext) {
		case 2: /* near ind call */
		case 3: /* far ind call */
			return X86_BR_IND_CALL;
		case 4:
		case 5:
			return X86_BR_IND_JMP;
		}
		return X86_BR_NONE;
	}

	return X86_BR_NONE;
}

/*
 * return the type of control flow change at address "from"
 * instruction is not necessarily a branch (in case of interrupt).
 *
 * The branch type returned also includes the priv level of the
 * target of the control flow change (X86_BR_USER, X86_BR_KERNEL).
 *
 * If a branch type is unknown OR the instruction cannot be
 * decoded (e.g., text page not present), then X86_BR_NONE is
 * returned.
 *
 * While recording branches, some processors can report the "from"
 * address to be that of an instruction preceding the actual branch
 * when instruction fusion occurs. If fusion is expected, attempt to
 * find the type of the first branch instruction within the next
 * MAX_INSN_SIZE bytes and if found, provide the offset between the
 * reported "from" address and the actual branch instruction address.
 */
static int get_branch_type(unsigned long from, unsigned long to, int abort,
			   bool fused, int *offset)
{
	struct insn insn;
	void *addr;
	int bytes_read, bytes_left, insn_offset;
	int ret = X86_BR_NONE;
	int to_plm, from_plm;
	u8 buf[MAX_INSN_SIZE];
	int is64 = 0;

	/* make sure we initialize offset */
	if (offset)
		*offset = 0;

	to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
	from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER;

	/*

Annotation

Implementation Notes