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