linux/tools/objtool/arch/x86/decode.c
<<
>>
Prefs
   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
  18static 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
  29static 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
  42bool 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
  69int 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
 483void 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}
 500