root/tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. intel_pt_insn_decoder
  2. intel_pt_get_insn
  3. arch_is_branch
  4. dump_insn
  5. intel_pt_insn_name
  6. intel_pt_insn_desc
  7. intel_pt_insn_type

   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 
   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 
  22 #if INTEL_PT_INSN_BUF_SZ < MAX_INSN_SIZE || INTEL_PT_INSN_BUF_SZ > MAX_INSN
  23 #error Instruction buffer size too small
  24 #endif
  25 
  26 /* Based on branch_type() from arch/x86/events/intel/lbr.c */
  27 static void intel_pt_insn_decoder(struct insn *insn,
  28                                   struct intel_pt_insn *intel_pt_insn)
  29 {
  30         enum intel_pt_insn_op op = INTEL_PT_OP_OTHER;
  31         enum intel_pt_insn_branch branch = INTEL_PT_BR_NO_BRANCH;
  32         int ext;
  33 
  34         intel_pt_insn->rel = 0;
  35 
  36         if (insn_is_avx(insn)) {
  37                 intel_pt_insn->op = INTEL_PT_OP_OTHER;
  38                 intel_pt_insn->branch = INTEL_PT_BR_NO_BRANCH;
  39                 intel_pt_insn->length = insn->length;
  40                 return;
  41         }
  42 
  43         switch (insn->opcode.bytes[0]) {
  44         case 0xf:
  45                 switch (insn->opcode.bytes[1]) {
  46                 case 0x05: /* syscall */
  47                 case 0x34: /* sysenter */
  48                         op = INTEL_PT_OP_SYSCALL;
  49                         branch = INTEL_PT_BR_INDIRECT;
  50                         break;
  51                 case 0x07: /* sysret */
  52                 case 0x35: /* sysexit */
  53                         op = INTEL_PT_OP_SYSRET;
  54                         branch = INTEL_PT_BR_INDIRECT;
  55                         break;
  56                 case 0x80 ... 0x8f: /* jcc */
  57                         op = INTEL_PT_OP_JCC;
  58                         branch = INTEL_PT_BR_CONDITIONAL;
  59                         break;
  60                 default:
  61                         break;
  62                 }
  63                 break;
  64         case 0x70 ... 0x7f: /* jcc */
  65                 op = INTEL_PT_OP_JCC;
  66                 branch = INTEL_PT_BR_CONDITIONAL;
  67                 break;
  68         case 0xc2: /* near ret */
  69         case 0xc3: /* near ret */
  70         case 0xca: /* far ret */
  71         case 0xcb: /* far ret */
  72                 op = INTEL_PT_OP_RET;
  73                 branch = INTEL_PT_BR_INDIRECT;
  74                 break;
  75         case 0xcf: /* iret */
  76                 op = INTEL_PT_OP_IRET;
  77                 branch = INTEL_PT_BR_INDIRECT;
  78                 break;
  79         case 0xcc ... 0xce: /* int */
  80                 op = INTEL_PT_OP_INT;
  81                 branch = INTEL_PT_BR_INDIRECT;
  82                 break;
  83         case 0xe8: /* call near rel */
  84                 op = INTEL_PT_OP_CALL;
  85                 branch = INTEL_PT_BR_UNCONDITIONAL;
  86                 break;
  87         case 0x9a: /* call far absolute */
  88                 op = INTEL_PT_OP_CALL;
  89                 branch = INTEL_PT_BR_INDIRECT;
  90                 break;
  91         case 0xe0 ... 0xe2: /* loop */
  92                 op = INTEL_PT_OP_LOOP;
  93                 branch = INTEL_PT_BR_CONDITIONAL;
  94                 break;
  95         case 0xe3: /* jcc */
  96                 op = INTEL_PT_OP_JCC;
  97                 branch = INTEL_PT_BR_CONDITIONAL;
  98                 break;
  99         case 0xe9: /* jmp */
 100         case 0xeb: /* jmp */
 101                 op = INTEL_PT_OP_JMP;
 102                 branch = INTEL_PT_BR_UNCONDITIONAL;
 103                 break;
 104         case 0xea: /* far jmp */
 105                 op = INTEL_PT_OP_JMP;
 106                 branch = INTEL_PT_BR_INDIRECT;
 107                 break;
 108         case 0xff: /* call near absolute, call far absolute ind */
 109                 ext = (insn->modrm.bytes[0] >> 3) & 0x7;
 110                 switch (ext) {
 111                 case 2: /* near ind call */
 112                 case 3: /* far ind call */
 113                         op = INTEL_PT_OP_CALL;
 114                         branch = INTEL_PT_BR_INDIRECT;
 115                         break;
 116                 case 4:
 117                 case 5:
 118                         op = INTEL_PT_OP_JMP;
 119                         branch = INTEL_PT_BR_INDIRECT;
 120                         break;
 121                 default:
 122                         break;
 123                 }
 124                 break;
 125         default:
 126                 break;
 127         }
 128 
 129         intel_pt_insn->op = op;
 130         intel_pt_insn->branch = branch;
 131         intel_pt_insn->length = insn->length;
 132 
 133         if (branch == INTEL_PT_BR_CONDITIONAL ||
 134             branch == INTEL_PT_BR_UNCONDITIONAL) {
 135 #if __BYTE_ORDER == __BIG_ENDIAN
 136                 switch (insn->immediate.nbytes) {
 137                 case 1:
 138                         intel_pt_insn->rel = insn->immediate.value;
 139                         break;
 140                 case 2:
 141                         intel_pt_insn->rel =
 142                                         bswap_16((short)insn->immediate.value);
 143                         break;
 144                 case 4:
 145                         intel_pt_insn->rel = bswap_32(insn->immediate.value);
 146                         break;
 147                 default:
 148                         intel_pt_insn->rel = 0;
 149                         break;
 150                 }
 151 #else
 152                 intel_pt_insn->rel = insn->immediate.value;
 153 #endif
 154         }
 155 }
 156 
 157 int intel_pt_get_insn(const unsigned char *buf, size_t len, int x86_64,
 158                       struct intel_pt_insn *intel_pt_insn)
 159 {
 160         struct insn insn;
 161 
 162         insn_init(&insn, buf, len, x86_64);
 163         insn_get_length(&insn);
 164         if (!insn_complete(&insn) || insn.length > len)
 165                 return -1;
 166         intel_pt_insn_decoder(&insn, intel_pt_insn);
 167         if (insn.length < INTEL_PT_INSN_BUF_SZ)
 168                 memcpy(intel_pt_insn->buf, buf, insn.length);
 169         else
 170                 memcpy(intel_pt_insn->buf, buf, INTEL_PT_INSN_BUF_SZ);
 171         return 0;
 172 }
 173 
 174 int arch_is_branch(const unsigned char *buf, size_t len, int x86_64)
 175 {
 176         struct intel_pt_insn in;
 177         if (intel_pt_get_insn(buf, len, x86_64, &in) < 0)
 178                 return -1;
 179         return in.branch != INTEL_PT_BR_NO_BRANCH;
 180 }
 181 
 182 const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,
 183                       u8 *inbuf, int inlen, int *lenp)
 184 {
 185         struct insn insn;
 186         int n, i;
 187         int left;
 188 
 189         insn_init(&insn, inbuf, inlen, x->is64bit);
 190         insn_get_length(&insn);
 191         if (!insn_complete(&insn) || insn.length > inlen)
 192                 return "<bad>";
 193         if (lenp)
 194                 *lenp = insn.length;
 195         left = sizeof(x->out);
 196         n = snprintf(x->out, left, "insn: ");
 197         left -= n;
 198         for (i = 0; i < insn.length; i++) {
 199                 n += snprintf(x->out + n, left, "%02x ", inbuf[i]);
 200                 left -= n;
 201         }
 202         return x->out;
 203 }
 204 
 205 const char *branch_name[] = {
 206         [INTEL_PT_OP_OTHER]     = "Other",
 207         [INTEL_PT_OP_CALL]      = "Call",
 208         [INTEL_PT_OP_RET]       = "Ret",
 209         [INTEL_PT_OP_JCC]       = "Jcc",
 210         [INTEL_PT_OP_JMP]       = "Jmp",
 211         [INTEL_PT_OP_LOOP]      = "Loop",
 212         [INTEL_PT_OP_IRET]      = "IRet",
 213         [INTEL_PT_OP_INT]       = "Int",
 214         [INTEL_PT_OP_SYSCALL]   = "Syscall",
 215         [INTEL_PT_OP_SYSRET]    = "Sysret",
 216 };
 217 
 218 const char *intel_pt_insn_name(enum intel_pt_insn_op op)
 219 {
 220         return branch_name[op];
 221 }
 222 
 223 int intel_pt_insn_desc(const struct intel_pt_insn *intel_pt_insn, char *buf,
 224                        size_t buf_len)
 225 {
 226         switch (intel_pt_insn->branch) {
 227         case INTEL_PT_BR_CONDITIONAL:
 228         case INTEL_PT_BR_UNCONDITIONAL:
 229                 return snprintf(buf, buf_len, "%s %s%d",
 230                                 intel_pt_insn_name(intel_pt_insn->op),
 231                                 intel_pt_insn->rel > 0 ? "+" : "",
 232                                 intel_pt_insn->rel);
 233         case INTEL_PT_BR_NO_BRANCH:
 234         case INTEL_PT_BR_INDIRECT:
 235                 return snprintf(buf, buf_len, "%s",
 236                                 intel_pt_insn_name(intel_pt_insn->op));
 237         default:
 238                 break;
 239         }
 240         return 0;
 241 }
 242 
 243 int intel_pt_insn_type(enum intel_pt_insn_op op)
 244 {
 245         switch (op) {
 246         case INTEL_PT_OP_OTHER:
 247                 return 0;
 248         case INTEL_PT_OP_CALL:
 249                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL;
 250         case INTEL_PT_OP_RET:
 251                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN;
 252         case INTEL_PT_OP_JCC:
 253                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL;
 254         case INTEL_PT_OP_JMP:
 255                 return PERF_IP_FLAG_BRANCH;
 256         case INTEL_PT_OP_LOOP:
 257                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL;
 258         case INTEL_PT_OP_IRET:
 259                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN |
 260                        PERF_IP_FLAG_INTERRUPT;
 261         case INTEL_PT_OP_INT:
 262                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |
 263                        PERF_IP_FLAG_INTERRUPT;
 264         case INTEL_PT_OP_SYSCALL:
 265                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL |
 266                        PERF_IP_FLAG_SYSCALLRET;
 267         case INTEL_PT_OP_SYSRET:
 268                 return PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN |
 269                        PERF_IP_FLAG_SYSCALLRET;
 270         default:
 271                 return 0;
 272         }
 273 }

/* [<][>][^][v][top][bottom][index][help] */