brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 47cf357 Raw
322 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * intel_pt_insn_decoder.c: Intel Processor Trace support4 * Copyright (c) 2013-2014, Intel Corporation.5 */6 7#include <linux/kernel.h>8#include <stdio.h>9#include <string.h>10#include <endian.h>11#include <byteswap.h>12#include "../../../arch/x86/include/asm/insn.h"13 14#include "../../../arch/x86/lib/inat.c"15#include "../../../arch/x86/lib/insn.c"16 17#include "event.h"18 19#include "intel-pt-insn-decoder.h"20#include "dump-insn.h"21#include "util/sample.h"22 23#if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN24#error Instruction buffer size too small25#endif26 27/* Based on branch_type() from arch/x86/events/intel/lbr.c */28static void intel_pt_insn_decoder(struct insn *insn,29				  struct intel_pt_insn *intel_pt_insn)30{31	enum intel_pt_insn_op op = INTEL_PT_OP_OTHER;32	enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;33	int ext;34 35	intel_pt_insn->rel = 0;36	intel_pt_insn->emulated_ptwrite = false;37 38	if (insn_is_avx(insn)) {39		intel_pt_insn->op = INTEL_PT_OP_OTHER;40		intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;41		intel_pt_insn->length = insn->length;42		return;43	}44 45	switch (insn->opcode.bytes[0]) {46	case 0xf:47		switch (insn->opcode.bytes[1]) {48		case 0x01:49			switch (insn->modrm.bytes[0]) {50			case 0xc2: /* vmlaunch */51			case 0xc3: /* vmresume */52				op = INTEL_PT_OP_VMENTRY;53				branch = INTEL_PT_BR_INDIRECT;54				break;55			case 0xca:56				switch (insn->prefixes.bytes[3]) {57				case 0xf2: /* erets */58					op = INTEL_PT_OP_ERETS;59					branch = INTEL_PT_BR_INDIRECT;60					break;61				case 0xf3: /* eretu */62					op = INTEL_PT_OP_ERETU;63					branch = INTEL_PT_BR_INDIRECT;64					break;65				default:66					break;67				}68				break;69			default:70				break;71			}72			break;73		case 0x05: /* syscall */74		case 0x34: /* sysenter */75			op = INTEL_PT_OP_SYSCALL;76			branch = INTEL_PT_BR_INDIRECT;77			break;78		case 0x07: /* sysret */79		case 0x35: /* sysexit */80			op = INTEL_PT_OP_SYSRET;81			branch = INTEL_PT_BR_INDIRECT;82			break;83		case 0x80 ... 0x8f: /* jcc */84			op = INTEL_PT_OP_JCC;85			branch = INTEL_PT_BR_CONDITIONAL;86			break;87		default:88			break;89		}90		break;91	case 0x70 ... 0x7f: /* jcc */92		op = INTEL_PT_OP_JCC;93		branch = INTEL_PT_BR_CONDITIONAL;94		break;95	case 0xa1:96		if (insn_is_rex2(insn)) { /* jmpabs */97			intel_pt_insn->op = INTEL_PT_OP_JMP;98			/* jmpabs causes a TIP packet like an indirect branch */99			intel_pt_insn->branch = INTEL_PT_BR_INDIRECT;100			intel_pt_insn->length = insn->length;101			return;102		}103		break;104	case 0xc2: /* near ret */105	case 0xc3: /* near ret */106	case 0xca: /* far ret */107	case 0xcb: /* far ret */108		op = INTEL_PT_OP_RET;109		branch = INTEL_PT_BR_INDIRECT;110		break;111	case 0xcf: /* iret */112		op = INTEL_PT_OP_IRET;113		branch = INTEL_PT_BR_INDIRECT;114		break;115	case 0xcc ... 0xce: /* int */116		op = INTEL_PT_OP_INT;117		branch = INTEL_PT_BR_INDIRECT;118		break;119	case 0xe8: /* call near rel */120		op = INTEL_PT_OP_CALL;121		branch = INTEL_PT_BR_UNCONDITIONAL;122		break;123	case 0x9a: /* call far absolute */124		op = INTEL_PT_OP_CALL;125		branch = INTEL_PT_BR_INDIRECT;126		break;127	case 0xe0 ... 0xe2: /* loop */128		op = INTEL_PT_OP_LOOP;129		branch = INTEL_PT_BR_CONDITIONAL;130		break;131	case 0xe3: /* jcc */132		op = INTEL_PT_OP_JCC;133		branch = INTEL_PT_BR_CONDITIONAL;134		break;135	case 0xe9: /* jmp */136	case 0xeb: /* jmp */137		op = INTEL_PT_OP_JMP;138		branch = INTEL_PT_BR_UNCONDITIONAL;139		break;140	case 0xea: /* far jmp */141		op = INTEL_PT_OP_JMP;142		branch = INTEL_PT_BR_INDIRECT;143		break;144	case 0xff: /* call near absolute, call far absolute ind */145		ext = (insn->modrm.bytes[0] >> 3) & 0x7;146		switch (ext) {147		case 2: /* near ind call */148		case 3: /* far ind call */149			op = INTEL_PT_OP_CALL;150			branch = INTEL_PT_BR_INDIRECT;151			break;152		case 4:153		case 5:154			op = INTEL_PT_OP_JMP;155			branch = INTEL_PT_BR_INDIRECT;156			break;157		default:158			break;159		}160		break;161	default:162		break;163	}164 165	intel_pt_insn->op = op;166	intel_pt_insn->branch = branch;167	intel_pt_insn->length = insn->length;168 169	if (branch == INTEL_PT_BR_CONDITIONAL ||170	    branch == INTEL_PT_BR_UNCONDITIONAL) {171#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__172		switch (insn->immediate.nbytes) {173		case 1:174			intel_pt_insn->rel = insn->immediate.value;175			break;176		case 2:177			intel_pt_insn->rel =178					bswap_16((short)insn->immediate.value);179			break;180		case 4:181			intel_pt_insn->rel = bswap_32(insn->immediate.value);182			break;183		default:184			intel_pt_insn->rel = 0;185			break;186		}187#else188		intel_pt_insn->rel = insn->immediate.value;189#endif190	}191}192 193int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,194		      struct intel_pt_insn *intel_pt_insn)195{196	struct insn insn;197	int ret;198 199	ret = insn_decode(&insn, buf, len,200			  x86_64 ? INSN_MODE_64 : INSN_MODE_32);201	if (ret < 0 || insn.length > len)202		return -1;203 204	intel_pt_insn_decoder(&insn, intel_pt_insn);205	if (insn.length < INTEL_PT_INSN_BUF_SZ)206		memcpy(intel_pt_insn->buf, buf, insn.length);207	else208		memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ);209	return 0;210}211 212int arch_is_uncond_branch(const unsigned char *buf, size_t len, int x86_64)213{214	struct intel_pt_insn in;215	if (intel_pt_get_insn(buf, len, x86_64, &in) < 0)216		return -1;217	return in.branch == INTEL_PT_BR_UNCONDITIONAL ||218	       in.branch == INTEL_PT_BR_INDIRECT;219}220 221const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,222		      u8 *inbuf, int inlen, int *lenp)223{224	struct insn insn;225	int n, i, ret;226	int left;227 228	ret = insn_decode(&insn, inbuf, inlen,229			  x->is64bit ? INSN_MODE_64 : INSN_MODE_32);230 231	if (ret < 0 || insn.length > inlen)232		return "<bad>";233	if (lenp)234		*lenp = insn.length;235	left = sizeof(x->out);236	n = snprintf(x->out, left, "insn: ");237	left -= n;238	for (i = 0; i < insn.length; i++) {239		n += snprintf(x->out + n, left, "%02x ", inbuf[i]);240		left -= n;241	}242	return x->out;243}244 245const char *branch_name[] = {246	[INTEL_PT_OP_OTHER]	= "Other",247	[INTEL_PT_OP_CALL]	= "Call",248	[INTEL_PT_OP_RET]	= "Ret",249	[INTEL_PT_OP_JCC]	= "Jcc",250	[INTEL_PT_OP_JMP]	= "Jmp",251	[INTEL_PT_OP_LOOP]	= "Loop",252	[INTEL_PT_OP_IRET]	= "IRet",253	[INTEL_PT_OP_INT]	= "Int",254	[INTEL_PT_OP_SYSCALL]	= "Syscall",255	[INTEL_PT_OP_SYSRET]	= "Sysret",256	[INTEL_PT_OP_VMENTRY]	= "VMentry",257	[INTEL_PT_OP_ERETS]	= "Erets",258	[INTEL_PT_OP_ERETU]	= "Eretu",259};260 261const char *intel_pt_insn_name(enum intel_pt_insn_op op)262{263	return branch_name[op];264}265 266int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,267		       size_t buf_len)268{269	switch (intel_pt_insn->branch) {270	case INTEL_PT_BR_CONDITIONAL:271	case INTEL_PT_BR_UNCONDITIONAL:272		return snprintf(buf, buf_len, "%s %s%d",273				intel_pt_insn_name(intel_pt_insn->op),274				intel_pt_insn->rel > 0 ? "+" : "",275				intel_pt_insn->rel);276	case INTEL_PT_BR_NO_BRANCH:277	case INTEL_PT_BR_INDIRECT:278		return snprintf(buf, buf_len, "%s",279				intel_pt_insn_name(intel_pt_insn->op));280	default:281		break;282	}283	return 0;284}285 286int intel_pt_insn_type(enum intel_pt_insn_op op)287{288	switch (op) {289	case INTEL_PT_OP_OTHER:290		return 0;291	case INTEL_PT_OP_CALL:292		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL;293	case INTEL_PT_OP_RET:294		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN;295	case INTEL_PT_OP_JCC:296		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL;297	case INTEL_PT_OP_JMP:298		return PERF_IP_FLAG_BRANCH;299	case INTEL_PT_OP_LOOP:300		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL;301	case INTEL_PT_OP_IRET:302	case INTEL_PT_OP_ERETS:303	case INTEL_PT_OP_ERETU:304		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN |305		       PERF_IP_FLAG_INTERRUPT;306	case INTEL_PT_OP_INT:307		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |308		       PERF_IP_FLAG_INTERRUPT;309	case INTEL_PT_OP_SYSCALL:310		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |311		       PERF_IP_FLAG_SYSCALLRET;312	case INTEL_PT_OP_SYSRET:313		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN |314		       PERF_IP_FLAG_SYSCALLRET;315	case INTEL_PT_OP_VMENTRY:316		return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |317		       PERF_IP_FLAG_VMENTRY;318	default:319		return 0;320	}321}322