intel-pt-insn-decoder.c 7.7 KB

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