root/tools/objtool/arch/x86/decode.c

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

DEFINITIONS

This source file includes following definitions.
  1. is_x86_64
  2. arch_callee_saved_reg
  3. arch_decode_instruction
  4. arch_initial_func_cfi_state

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * Copyright (C) 2015 Josh Poimboeuf <jpoimboe@redhat.com>
   4  */
   5 
   6 #include <stdio.h>
   7 #include <stdlib.h>
   8 
   9 #define unlikely(cond) (cond)
  10 #include <asm/insn.h>
  11 #include "../../../arch/x86/lib/inat.c"
  12 #include "../../../arch/x86/lib/insn.c"
  13 
  14 #include "../../elf.h"
  15 #include "../../arch.h"
  16 #include "../../warn.h"
  17 
  18 static unsigned char op_to_cfi_reg[][2] = {
  19         {CFI_AX, CFI_R8},
  20         {CFI_CX, CFI_R9},
  21         {CFI_DX, CFI_R10},
  22         {CFI_BX, CFI_R11},
  23         {CFI_SP, CFI_R12},
  24         {CFI_BP, CFI_R13},
  25         {CFI_SI, CFI_R14},
  26         {CFI_DI, CFI_R15},
  27 };
  28 
  29 static int is_x86_64(struct elf *elf)
  30 {
  31         switch (elf->ehdr.e_machine) {
  32         case EM_X86_64:
  33                 return 1;
  34         case EM_386:
  35                 return 0;
  36         default:
  37                 WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
  38                 return -1;
  39         }
  40 }
  41 
  42 bool arch_callee_saved_reg(unsigned char reg)
  43 {
  44         switch (reg) {
  45         case CFI_BP:
  46         case CFI_BX:
  47         case CFI_R12:
  48         case CFI_R13:
  49         case CFI_R14:
  50         case CFI_R15:
  51                 return true;
  52 
  53         case CFI_AX:
  54         case CFI_CX:
  55         case CFI_DX:
  56         case CFI_SI:
  57         case CFI_DI:
  58         case CFI_SP:
  59         case CFI_R8:
  60         case CFI_R9:
  61         case CFI_R10:
  62         case CFI_R11:
  63         case CFI_RA:
  64         default:
  65                 return false;
  66         }
  67 }
  68 
  69 int arch_decode_instruction(struct elf *elf, struct section *sec,
  70                             unsigned long offset, unsigned int maxlen,
  71                             unsigned int *len, enum insn_type *type,
  72                             unsigned long *immediate, struct stack_op *op)
  73 {
  74         struct insn insn;
  75         int x86_64, sign;
  76         unsigned char op1, op2, rex = 0, rex_b = 0, rex_r = 0, rex_w = 0,
  77                       rex_x = 0, modrm = 0, modrm_mod = 0, modrm_rm = 0,
  78                       modrm_reg = 0, sib = 0;
  79 
  80         x86_64 = is_x86_64(elf);
  81         if (x86_64 == -1)
  82                 return -1;
  83 
  84         insn_init(&insn, sec->data->d_buf + offset, maxlen, x86_64);
  85         insn_get_length(&insn);
  86 
  87         if (!insn_complete(&insn)) {
  88                 WARN_FUNC("can't decode instruction", sec, offset);
  89                 return -1;
  90         }
  91 
  92         *len = insn.length;
  93         *type = INSN_OTHER;
  94 
  95         if (insn.vex_prefix.nbytes)
  96                 return 0;
  97 
  98         op1 = insn.opcode.bytes[0];
  99         op2 = insn.opcode.bytes[1];
 100 
 101         if (insn.rex_prefix.nbytes) {
 102                 rex = insn.rex_prefix.bytes[0];
 103                 rex_w = X86_REX_W(rex) >> 3;
 104                 rex_r = X86_REX_R(rex) >> 2;
 105                 rex_x = X86_REX_X(rex) >> 1;
 106                 rex_b = X86_REX_B(rex);
 107         }
 108 
 109         if (insn.modrm.nbytes) {
 110                 modrm = insn.modrm.bytes[0];
 111                 modrm_mod = X86_MODRM_MOD(modrm);
 112                 modrm_reg = X86_MODRM_REG(modrm);
 113                 modrm_rm = X86_MODRM_RM(modrm);
 114         }
 115 
 116         if (insn.sib.nbytes)
 117                 sib = insn.sib.bytes[0];
 118 
 119         switch (op1) {
 120 
 121         case 0x1:
 122         case 0x29:
 123                 if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
 124 
 125                         /* add/sub reg, %rsp */
 126                         *type = INSN_STACK;
 127                         op->src.type = OP_SRC_ADD;
 128                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 129                         op->dest.type = OP_DEST_REG;
 130                         op->dest.reg = CFI_SP;
 131                 }
 132                 break;
 133 
 134         case 0x50 ... 0x57:
 135 
 136                 /* push reg */
 137                 *type = INSN_STACK;
 138                 op->src.type = OP_SRC_REG;
 139                 op->src.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
 140                 op->dest.type = OP_DEST_PUSH;
 141 
 142                 break;
 143 
 144         case 0x58 ... 0x5f:
 145 
 146                 /* pop reg */
 147                 *type = INSN_STACK;
 148                 op->src.type = OP_SRC_POP;
 149                 op->dest.type = OP_DEST_REG;
 150                 op->dest.reg = op_to_cfi_reg[op1 & 0x7][rex_b];
 151 
 152                 break;
 153 
 154         case 0x68:
 155         case 0x6a:
 156                 /* push immediate */
 157                 *type = INSN_STACK;
 158                 op->src.type = OP_SRC_CONST;
 159                 op->dest.type = OP_DEST_PUSH;
 160                 break;
 161 
 162         case 0x70 ... 0x7f:
 163                 *type = INSN_JUMP_CONDITIONAL;
 164                 break;
 165 
 166         case 0x81:
 167         case 0x83:
 168                 if (rex != 0x48)
 169                         break;
 170 
 171                 if (modrm == 0xe4) {
 172                         /* and imm, %rsp */
 173                         *type = INSN_STACK;
 174                         op->src.type = OP_SRC_AND;
 175                         op->src.reg = CFI_SP;
 176                         op->src.offset = insn.immediate.value;
 177                         op->dest.type = OP_DEST_REG;
 178                         op->dest.reg = CFI_SP;
 179                         break;
 180                 }
 181 
 182                 if (modrm == 0xc4)
 183                         sign = 1;
 184                 else if (modrm == 0xec)
 185                         sign = -1;
 186                 else
 187                         break;
 188 
 189                 /* add/sub imm, %rsp */
 190                 *type = INSN_STACK;
 191                 op->src.type = OP_SRC_ADD;
 192                 op->src.reg = CFI_SP;
 193                 op->src.offset = insn.immediate.value * sign;
 194                 op->dest.type = OP_DEST_REG;
 195                 op->dest.reg = CFI_SP;
 196                 break;
 197 
 198         case 0x89:
 199                 if (rex_w && !rex_r && modrm_mod == 3 && modrm_reg == 4) {
 200 
 201                         /* mov %rsp, reg */
 202                         *type = INSN_STACK;
 203                         op->src.type = OP_SRC_REG;
 204                         op->src.reg = CFI_SP;
 205                         op->dest.type = OP_DEST_REG;
 206                         op->dest.reg = op_to_cfi_reg[modrm_rm][rex_b];
 207                         break;
 208                 }
 209 
 210                 if (rex_w && !rex_b && modrm_mod == 3 && modrm_rm == 4) {
 211 
 212                         /* mov reg, %rsp */
 213                         *type = INSN_STACK;
 214                         op->src.type = OP_SRC_REG;
 215                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 216                         op->dest.type = OP_DEST_REG;
 217                         op->dest.reg = CFI_SP;
 218                         break;
 219                 }
 220 
 221                 /* fallthrough */
 222         case 0x88:
 223                 if (!rex_b &&
 224                     (modrm_mod == 1 || modrm_mod == 2) && modrm_rm == 5) {
 225 
 226                         /* mov reg, disp(%rbp) */
 227                         *type = INSN_STACK;
 228                         op->src.type = OP_SRC_REG;
 229                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 230                         op->dest.type = OP_DEST_REG_INDIRECT;
 231                         op->dest.reg = CFI_BP;
 232                         op->dest.offset = insn.displacement.value;
 233 
 234                 } else if (rex_w && !rex_b && modrm_rm == 4 && sib == 0x24) {
 235 
 236                         /* mov reg, disp(%rsp) */
 237                         *type = INSN_STACK;
 238                         op->src.type = OP_SRC_REG;
 239                         op->src.reg = op_to_cfi_reg[modrm_reg][rex_r];
 240                         op->dest.type = OP_DEST_REG_INDIRECT;
 241                         op->dest.reg = CFI_SP;
 242                         op->dest.offset = insn.displacement.value;
 243                 }
 244 
 245                 break;
 246 
 247         case 0x8b:
 248                 if (rex_w && !rex_b && modrm_mod == 1 && modrm_rm == 5) {
 249 
 250                         /* mov disp(%rbp), reg */
 251                         *type = INSN_STACK;
 252                         op->src.type = OP_SRC_REG_INDIRECT;
 253                         op->src.reg = CFI_BP;
 254                         op->src.offset = insn.displacement.value;
 255                         op->dest.type = OP_DEST_REG;
 256                         op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 257 
 258                 } else if (rex_w && !rex_b && sib == 0x24 &&
 259                            modrm_mod != 3 && modrm_rm == 4) {
 260 
 261                         /* mov disp(%rsp), reg */
 262                         *type = INSN_STACK;
 263                         op->src.type = OP_SRC_REG_INDIRECT;
 264                         op->src.reg = CFI_SP;
 265                         op->src.offset = insn.displacement.value;
 266                         op->dest.type = OP_DEST_REG;
 267                         op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 268                 }
 269 
 270                 break;
 271 
 272         case 0x8d:
 273                 if (sib == 0x24 && rex_w && !rex_b && !rex_x) {
 274 
 275                         *type = INSN_STACK;
 276                         if (!insn.displacement.value) {
 277                                 /* lea (%rsp), reg */
 278                                 op->src.type = OP_SRC_REG;
 279                         } else {
 280                                 /* lea disp(%rsp), reg */
 281                                 op->src.type = OP_SRC_ADD;
 282                                 op->src.offset = insn.displacement.value;
 283                         }
 284                         op->src.reg = CFI_SP;
 285                         op->dest.type = OP_DEST_REG;
 286                         op->dest.reg = op_to_cfi_reg[modrm_reg][rex_r];
 287 
 288                 } else if (rex == 0x48 && modrm == 0x65) {
 289 
 290                         /* lea disp(%rbp), %rsp */
 291                         *type = INSN_STACK;
 292                         op->src.type = OP_SRC_ADD;
 293                         op->src.reg = CFI_BP;
 294                         op->src.offset = insn.displacement.value;
 295                         op->dest.type = OP_DEST_REG;
 296                         op->dest.reg = CFI_SP;
 297 
 298                 } else if (rex == 0x49 && modrm == 0x62 &&
 299                            insn.displacement.value == -8) {
 300 
 301                         /*
 302                          * lea -0x8(%r10), %rsp
 303                          *
 304                          * Restoring rsp back to its original value after a
 305                          * stack realignment.
 306                          */
 307                         *type = INSN_STACK;
 308                         op->src.type = OP_SRC_ADD;
 309                         op->src.reg = CFI_R10;
 310                         op->src.offset = -8;
 311                         op->dest.type = OP_DEST_REG;
 312                         op->dest.reg = CFI_SP;
 313 
 314                 } else if (rex == 0x49 && modrm == 0x65 &&
 315                            insn.displacement.value == -16) {
 316 
 317                         /*
 318                          * lea -0x10(%r13), %rsp
 319                          *
 320                          * Restoring rsp back to its original value after a
 321                          * stack realignment.
 322                          */
 323                         *type = INSN_STACK;
 324                         op->src.type = OP_SRC_ADD;
 325                         op->src.reg = CFI_R13;
 326                         op->src.offset = -16;
 327                         op->dest.type = OP_DEST_REG;
 328                         op->dest.reg = CFI_SP;
 329                 }
 330 
 331                 break;
 332 
 333         case 0x8f:
 334                 /* pop to mem */
 335                 *type = INSN_STACK;
 336                 op->src.type = OP_SRC_POP;
 337                 op->dest.type = OP_DEST_MEM;
 338                 break;
 339 
 340         case 0x90:
 341                 *type = INSN_NOP;
 342                 break;
 343 
 344         case 0x9c:
 345                 /* pushf */
 346                 *type = INSN_STACK;
 347                 op->src.type = OP_SRC_CONST;
 348                 op->dest.type = OP_DEST_PUSHF;
 349                 break;
 350 
 351         case 0x9d:
 352                 /* popf */
 353                 *type = INSN_STACK;
 354                 op->src.type = OP_SRC_POPF;
 355                 op->dest.type = OP_DEST_MEM;
 356                 break;
 357 
 358         case 0x0f:
 359 
 360                 if (op2 == 0x01) {
 361 
 362                         if (modrm == 0xca)
 363                                 *type = INSN_CLAC;
 364                         else if (modrm == 0xcb)
 365                                 *type = INSN_STAC;
 366 
 367                 } else if (op2 >= 0x80 && op2 <= 0x8f) {
 368 
 369                         *type = INSN_JUMP_CONDITIONAL;
 370 
 371                 } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
 372                            op2 == 0x35) {
 373 
 374                         /* sysenter, sysret */
 375                         *type = INSN_CONTEXT_SWITCH;
 376 
 377                 } else if (op2 == 0x0b || op2 == 0xb9) {
 378 
 379                         /* ud2 */
 380                         *type = INSN_BUG;
 381 
 382                 } else if (op2 == 0x0d || op2 == 0x1f) {
 383 
 384                         /* nopl/nopw */
 385                         *type = INSN_NOP;
 386 
 387                 } else if (op2 == 0xa0 || op2 == 0xa8) {
 388 
 389                         /* push fs/gs */
 390                         *type = INSN_STACK;
 391                         op->src.type = OP_SRC_CONST;
 392                         op->dest.type = OP_DEST_PUSH;
 393 
 394                 } else if (op2 == 0xa1 || op2 == 0xa9) {
 395 
 396                         /* pop fs/gs */
 397                         *type = INSN_STACK;
 398                         op->src.type = OP_SRC_POP;
 399                         op->dest.type = OP_DEST_MEM;
 400                 }
 401 
 402                 break;
 403 
 404         case 0xc9:
 405                 /*
 406                  * leave
 407                  *
 408                  * equivalent to:
 409                  * mov bp, sp
 410                  * pop bp
 411                  */
 412                 *type = INSN_STACK;
 413                 op->dest.type = OP_DEST_LEAVE;
 414 
 415                 break;
 416 
 417         case 0xe3:
 418                 /* jecxz/jrcxz */
 419                 *type = INSN_JUMP_CONDITIONAL;
 420                 break;
 421 
 422         case 0xe9:
 423         case 0xeb:
 424                 *type = INSN_JUMP_UNCONDITIONAL;
 425                 break;
 426 
 427         case 0xc2:
 428         case 0xc3:
 429                 *type = INSN_RETURN;
 430                 break;
 431 
 432         case 0xca: /* retf */
 433         case 0xcb: /* retf */
 434         case 0xcf: /* iret */
 435                 *type = INSN_CONTEXT_SWITCH;
 436                 break;
 437 
 438         case 0xe8:
 439                 *type = INSN_CALL;
 440                 break;
 441 
 442         case 0xfc:
 443                 *type = INSN_CLD;
 444                 break;
 445 
 446         case 0xfd:
 447                 *type = INSN_STD;
 448                 break;
 449 
 450         case 0xff:
 451                 if (modrm_reg == 2 || modrm_reg == 3)
 452 
 453                         *type = INSN_CALL_DYNAMIC;
 454 
 455                 else if (modrm_reg == 4)
 456 
 457                         *type = INSN_JUMP_DYNAMIC;
 458 
 459                 else if (modrm_reg == 5)
 460 
 461                         /* jmpf */
 462                         *type = INSN_CONTEXT_SWITCH;
 463 
 464                 else if (modrm_reg == 6) {
 465 
 466                         /* push from mem */
 467                         *type = INSN_STACK;
 468                         op->src.type = OP_SRC_CONST;
 469                         op->dest.type = OP_DEST_PUSH;
 470                 }
 471 
 472                 break;
 473 
 474         default:
 475                 break;
 476         }
 477 
 478         *immediate = insn.immediate.nbytes ? insn.immediate.value : 0;
 479 
 480         return 0;
 481 }
 482 
 483 void arch_initial_func_cfi_state(struct cfi_state *state)
 484 {
 485         int i;
 486 
 487         for (i = 0; i < CFI_NUM_REGS; i++) {
 488                 state->regs[i].base = CFI_UNDEFINED;
 489                 state->regs[i].offset = 0;
 490         }
 491 
 492         /* initial CFA (call frame address) */
 493         state->cfa.base = CFI_SP;
 494         state->cfa.offset = 8;
 495 
 496         /* initial RA (return address) */
 497         state->regs[16].base = CFI_CFA;
 498         state->regs[16].offset = -8;
 499 }

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