0001
0002
0003
0004
0005
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008
0009 #define unlikely(cond) (cond)
0010 #include <asm/insn.h>
0011 #include "../../../arch/x86/lib/inat.c"
0012 #include "../../../arch/x86/lib/insn.c"
0013
0014 #define CONFIG_64BIT 1
0015 #include <asm/nops.h>
0016
0017 #include <asm/orc_types.h>
0018 #include <objtool/check.h>
0019 #include <objtool/elf.h>
0020 #include <objtool/arch.h>
0021 #include <objtool/warn.h>
0022 #include <objtool/endianness.h>
0023 #include <objtool/builtin.h>
0024 #include <arch/elf.h>
0025
0026 static int is_x86_64(const struct elf *elf)
0027 {
0028 switch (elf->ehdr.e_machine) {
0029 case EM_X86_64:
0030 return 1;
0031 case EM_386:
0032 return 0;
0033 default:
0034 WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
0035 return -1;
0036 }
0037 }
0038
0039 bool arch_callee_saved_reg(unsigned char reg)
0040 {
0041 switch (reg) {
0042 case CFI_BP:
0043 case CFI_BX:
0044 case CFI_R12:
0045 case CFI_R13:
0046 case CFI_R14:
0047 case CFI_R15:
0048 return true;
0049
0050 case CFI_AX:
0051 case CFI_CX:
0052 case CFI_DX:
0053 case CFI_SI:
0054 case CFI_DI:
0055 case CFI_SP:
0056 case CFI_R8:
0057 case CFI_R9:
0058 case CFI_R10:
0059 case CFI_R11:
0060 case CFI_RA:
0061 default:
0062 return false;
0063 }
0064 }
0065
0066 unsigned long arch_dest_reloc_offset(int addend)
0067 {
0068 return addend + 4;
0069 }
0070
0071 unsigned long arch_jump_destination(struct instruction *insn)
0072 {
0073 return insn->offset + insn->len + insn->immediate;
0074 }
0075
0076 #define ADD_OP(op) \
0077 if (!(op = calloc(1, sizeof(*op)))) \
0078 return -1; \
0079 else for (list_add_tail(&op->list, ops_list); op; op = NULL)
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090
0091
0092
0093 #define mod_is_mem() (modrm_mod != 3)
0094 #define mod_is_reg() (modrm_mod == 3)
0095
0096 #define is_RIP() ((modrm_rm & 7) == CFI_BP && modrm_mod == 0)
0097 #define have_SIB() ((modrm_rm & 7) == CFI_SP && mod_is_mem())
0098
0099 #define rm_is(reg) (have_SIB() ? \
0100 sib_base == (reg) && sib_index == CFI_SP : \
0101 modrm_rm == (reg))
0102
0103 #define rm_is_mem(reg) (mod_is_mem() && !is_RIP() && rm_is(reg))
0104 #define rm_is_reg(reg) (mod_is_reg() && modrm_rm == (reg))
0105
0106 static bool has_notrack_prefix(struct insn *insn)
0107 {
0108 int i;
0109
0110 for (i = 0; i < insn->prefixes.nbytes; i++) {
0111 if (insn->prefixes.bytes[i] == 0x3e)
0112 return true;
0113 }
0114
0115 return false;
0116 }
0117
0118 int arch_decode_instruction(struct objtool_file *file, const struct section *sec,
0119 unsigned long offset, unsigned int maxlen,
0120 unsigned int *len, enum insn_type *type,
0121 unsigned long *immediate,
0122 struct list_head *ops_list)
0123 {
0124 const struct elf *elf = file->elf;
0125 struct insn insn;
0126 int x86_64, ret;
0127 unsigned char op1, op2, op3, prefix,
0128 rex = 0, rex_b = 0, rex_r = 0, rex_w = 0, rex_x = 0,
0129 modrm = 0, modrm_mod = 0, modrm_rm = 0, modrm_reg = 0,
0130 sib = 0, sib_index = 0, sib_base = 0;
0131 struct stack_op *op = NULL;
0132 struct symbol *sym;
0133 u64 imm;
0134
0135 x86_64 = is_x86_64(elf);
0136 if (x86_64 == -1)
0137 return -1;
0138
0139 ret = insn_decode(&insn, sec->data->d_buf + offset, maxlen,
0140 x86_64 ? INSN_MODE_64 : INSN_MODE_32);
0141 if (ret < 0) {
0142 WARN("can't decode instruction at %s:0x%lx", sec->name, offset);
0143 return -1;
0144 }
0145
0146 *len = insn.length;
0147 *type = INSN_OTHER;
0148
0149 if (insn.vex_prefix.nbytes)
0150 return 0;
0151
0152 prefix = insn.prefixes.bytes[0];
0153
0154 op1 = insn.opcode.bytes[0];
0155 op2 = insn.opcode.bytes[1];
0156 op3 = insn.opcode.bytes[2];
0157
0158 if (insn.rex_prefix.nbytes) {
0159 rex = insn.rex_prefix.bytes[0];
0160 rex_w = X86_REX_W(rex) >> 3;
0161 rex_r = X86_REX_R(rex) >> 2;
0162 rex_x = X86_REX_X(rex) >> 1;
0163 rex_b = X86_REX_B(rex);
0164 }
0165
0166 if (insn.modrm.nbytes) {
0167 modrm = insn.modrm.bytes[0];
0168 modrm_mod = X86_MODRM_MOD(modrm);
0169 modrm_reg = X86_MODRM_REG(modrm) + 8*rex_r;
0170 modrm_rm = X86_MODRM_RM(modrm) + 8*rex_b;
0171 }
0172
0173 if (insn.sib.nbytes) {
0174 sib = insn.sib.bytes[0];
0175
0176 sib_index = X86_SIB_INDEX(sib) + 8*rex_x;
0177 sib_base = X86_SIB_BASE(sib) + 8*rex_b;
0178 }
0179
0180 switch (op1) {
0181
0182 case 0x1:
0183 case 0x29:
0184 if (rex_w && rm_is_reg(CFI_SP)) {
0185
0186
0187 ADD_OP(op) {
0188 op->src.type = OP_SRC_ADD;
0189 op->src.reg = modrm_reg;
0190 op->dest.type = OP_DEST_REG;
0191 op->dest.reg = CFI_SP;
0192 }
0193 }
0194 break;
0195
0196 case 0x50 ... 0x57:
0197
0198
0199 ADD_OP(op) {
0200 op->src.type = OP_SRC_REG;
0201 op->src.reg = (op1 & 0x7) + 8*rex_b;
0202 op->dest.type = OP_DEST_PUSH;
0203 }
0204
0205 break;
0206
0207 case 0x58 ... 0x5f:
0208
0209
0210 ADD_OP(op) {
0211 op->src.type = OP_SRC_POP;
0212 op->dest.type = OP_DEST_REG;
0213 op->dest.reg = (op1 & 0x7) + 8*rex_b;
0214 }
0215
0216 break;
0217
0218 case 0x68:
0219 case 0x6a:
0220
0221 ADD_OP(op) {
0222 op->src.type = OP_SRC_CONST;
0223 op->dest.type = OP_DEST_PUSH;
0224 }
0225 break;
0226
0227 case 0x70 ... 0x7f:
0228 *type = INSN_JUMP_CONDITIONAL;
0229 break;
0230
0231 case 0x80 ... 0x83:
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 if (!rex_w)
0246 break;
0247
0248
0249 if (!rm_is_reg(CFI_SP))
0250 break;
0251
0252 imm = insn.immediate.value;
0253 if (op1 & 2) {
0254 if (op1 & 1) {
0255 imm <<= 32;
0256 imm = (s64)imm >> 32;
0257 } else {
0258 imm <<= 56;
0259 imm = (s64)imm >> 56;
0260 }
0261 }
0262
0263 switch (modrm_reg & 7) {
0264 case 5:
0265 imm = -imm;
0266
0267 case 0:
0268
0269 ADD_OP(op) {
0270 op->src.type = OP_SRC_ADD;
0271 op->src.reg = CFI_SP;
0272 op->src.offset = imm;
0273 op->dest.type = OP_DEST_REG;
0274 op->dest.reg = CFI_SP;
0275 }
0276 break;
0277
0278 case 4:
0279
0280 ADD_OP(op) {
0281 op->src.type = OP_SRC_AND;
0282 op->src.reg = CFI_SP;
0283 op->src.offset = insn.immediate.value;
0284 op->dest.type = OP_DEST_REG;
0285 op->dest.reg = CFI_SP;
0286 }
0287 break;
0288
0289 default:
0290
0291 break;
0292 }
0293
0294 break;
0295
0296 case 0x89:
0297 if (!rex_w)
0298 break;
0299
0300 if (modrm_reg == CFI_SP) {
0301
0302 if (mod_is_reg()) {
0303
0304 ADD_OP(op) {
0305 op->src.type = OP_SRC_REG;
0306 op->src.reg = CFI_SP;
0307 op->dest.type = OP_DEST_REG;
0308 op->dest.reg = modrm_rm;
0309 }
0310 break;
0311
0312 } else {
0313
0314 if (is_RIP())
0315 break;
0316
0317
0318 if (have_SIB()) {
0319 modrm_rm = sib_base;
0320 if (sib_index != CFI_SP)
0321 break;
0322 }
0323
0324
0325 ADD_OP(op) {
0326 op->src.type = OP_SRC_REG;
0327 op->src.reg = CFI_SP;
0328 op->dest.type = OP_DEST_REG_INDIRECT;
0329 op->dest.reg = modrm_rm;
0330 op->dest.offset = insn.displacement.value;
0331 }
0332 break;
0333 }
0334
0335 break;
0336 }
0337
0338 if (rm_is_reg(CFI_SP)) {
0339
0340
0341 ADD_OP(op) {
0342 op->src.type = OP_SRC_REG;
0343 op->src.reg = modrm_reg;
0344 op->dest.type = OP_DEST_REG;
0345 op->dest.reg = CFI_SP;
0346 }
0347 break;
0348 }
0349
0350
0351 case 0x88:
0352 if (!rex_w)
0353 break;
0354
0355 if (rm_is_mem(CFI_BP)) {
0356
0357
0358 ADD_OP(op) {
0359 op->src.type = OP_SRC_REG;
0360 op->src.reg = modrm_reg;
0361 op->dest.type = OP_DEST_REG_INDIRECT;
0362 op->dest.reg = CFI_BP;
0363 op->dest.offset = insn.displacement.value;
0364 }
0365 break;
0366 }
0367
0368 if (rm_is_mem(CFI_SP)) {
0369
0370
0371 ADD_OP(op) {
0372 op->src.type = OP_SRC_REG;
0373 op->src.reg = modrm_reg;
0374 op->dest.type = OP_DEST_REG_INDIRECT;
0375 op->dest.reg = CFI_SP;
0376 op->dest.offset = insn.displacement.value;
0377 }
0378 break;
0379 }
0380
0381 break;
0382
0383 case 0x8b:
0384 if (!rex_w)
0385 break;
0386
0387 if (rm_is_mem(CFI_BP)) {
0388
0389
0390 ADD_OP(op) {
0391 op->src.type = OP_SRC_REG_INDIRECT;
0392 op->src.reg = CFI_BP;
0393 op->src.offset = insn.displacement.value;
0394 op->dest.type = OP_DEST_REG;
0395 op->dest.reg = modrm_reg;
0396 }
0397 break;
0398 }
0399
0400 if (rm_is_mem(CFI_SP)) {
0401
0402
0403 ADD_OP(op) {
0404 op->src.type = OP_SRC_REG_INDIRECT;
0405 op->src.reg = CFI_SP;
0406 op->src.offset = insn.displacement.value;
0407 op->dest.type = OP_DEST_REG;
0408 op->dest.reg = modrm_reg;
0409 }
0410 break;
0411 }
0412
0413 break;
0414
0415 case 0x8d:
0416 if (mod_is_reg()) {
0417 WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset);
0418 break;
0419 }
0420
0421
0422 if (!rex_w)
0423 break;
0424
0425
0426 if (is_RIP())
0427 break;
0428
0429
0430 if (have_SIB()) {
0431 modrm_rm = sib_base;
0432 if (sib_index != CFI_SP)
0433 break;
0434 }
0435
0436
0437 ADD_OP(op) {
0438 op->src.offset = insn.displacement.value;
0439 if (!op->src.offset) {
0440
0441 op->src.type = OP_SRC_REG;
0442 } else {
0443
0444 op->src.type = OP_SRC_ADD;
0445 }
0446 op->src.reg = modrm_rm;
0447 op->dest.type = OP_DEST_REG;
0448 op->dest.reg = modrm_reg;
0449 }
0450 break;
0451
0452 case 0x8f:
0453
0454 ADD_OP(op) {
0455 op->src.type = OP_SRC_POP;
0456 op->dest.type = OP_DEST_MEM;
0457 }
0458 break;
0459
0460 case 0x90:
0461 *type = INSN_NOP;
0462 break;
0463
0464 case 0x9c:
0465
0466 ADD_OP(op) {
0467 op->src.type = OP_SRC_CONST;
0468 op->dest.type = OP_DEST_PUSHF;
0469 }
0470 break;
0471
0472 case 0x9d:
0473
0474 ADD_OP(op) {
0475 op->src.type = OP_SRC_POPF;
0476 op->dest.type = OP_DEST_MEM;
0477 }
0478 break;
0479
0480 case 0x0f:
0481
0482 if (op2 == 0x01) {
0483
0484 if (modrm == 0xca)
0485 *type = INSN_CLAC;
0486 else if (modrm == 0xcb)
0487 *type = INSN_STAC;
0488
0489 } else if (op2 >= 0x80 && op2 <= 0x8f) {
0490
0491 *type = INSN_JUMP_CONDITIONAL;
0492
0493 } else if (op2 == 0x05 || op2 == 0x07 || op2 == 0x34 ||
0494 op2 == 0x35) {
0495
0496
0497 *type = INSN_CONTEXT_SWITCH;
0498
0499 } else if (op2 == 0x0b || op2 == 0xb9) {
0500
0501
0502 *type = INSN_BUG;
0503
0504 } else if (op2 == 0x0d || op2 == 0x1f) {
0505
0506
0507 *type = INSN_NOP;
0508
0509 } else if (op2 == 0x1e) {
0510
0511 if (prefix == 0xf3 && (modrm == 0xfa || modrm == 0xfb))
0512 *type = INSN_ENDBR;
0513
0514
0515 } else if (op2 == 0x38 && op3 == 0xf8) {
0516 if (insn.prefixes.nbytes == 1 &&
0517 insn.prefixes.bytes[0] == 0xf2) {
0518
0519 WARN("ENQCMD instruction at %s:%lx", sec->name,
0520 offset);
0521 }
0522
0523 } else if (op2 == 0xa0 || op2 == 0xa8) {
0524
0525
0526 ADD_OP(op) {
0527 op->src.type = OP_SRC_CONST;
0528 op->dest.type = OP_DEST_PUSH;
0529 }
0530
0531 } else if (op2 == 0xa1 || op2 == 0xa9) {
0532
0533
0534 ADD_OP(op) {
0535 op->src.type = OP_SRC_POP;
0536 op->dest.type = OP_DEST_MEM;
0537 }
0538 }
0539
0540 break;
0541
0542 case 0xc9:
0543
0544
0545
0546
0547
0548
0549
0550 ADD_OP(op) {
0551 op->src.type = OP_SRC_REG;
0552 op->src.reg = CFI_BP;
0553 op->dest.type = OP_DEST_REG;
0554 op->dest.reg = CFI_SP;
0555 }
0556 ADD_OP(op) {
0557 op->src.type = OP_SRC_POP;
0558 op->dest.type = OP_DEST_REG;
0559 op->dest.reg = CFI_BP;
0560 }
0561 break;
0562
0563 case 0xcc:
0564
0565 *type = INSN_TRAP;
0566 break;
0567
0568 case 0xe3:
0569
0570 *type = INSN_JUMP_CONDITIONAL;
0571 break;
0572
0573 case 0xe9:
0574 case 0xeb:
0575 *type = INSN_JUMP_UNCONDITIONAL;
0576 break;
0577
0578 case 0xc2:
0579 case 0xc3:
0580 *type = INSN_RETURN;
0581 break;
0582
0583 case 0xc7:
0584 if (!opts.noinstr)
0585 break;
0586
0587 if (insn.length == 3+4+4 && !strncmp(sec->name, ".init.text", 10)) {
0588 struct reloc *immr, *disp;
0589 struct symbol *func;
0590 int idx;
0591
0592 immr = find_reloc_by_dest(elf, (void *)sec, offset+3);
0593 disp = find_reloc_by_dest(elf, (void *)sec, offset+7);
0594
0595 if (!immr || strcmp(immr->sym->name, "pv_ops"))
0596 break;
0597
0598 idx = (immr->addend + 8) / sizeof(void *);
0599
0600 func = disp->sym;
0601 if (disp->sym->type == STT_SECTION)
0602 func = find_symbol_by_offset(disp->sym->sec, disp->addend);
0603 if (!func) {
0604 WARN("no func for pv_ops[]");
0605 return -1;
0606 }
0607
0608 objtool_pv_add(file, idx, func);
0609 }
0610
0611 break;
0612
0613 case 0xcf:
0614
0615
0616
0617
0618 sym = find_symbol_containing(sec, offset);
0619 if (sym && sym->type == STT_FUNC) {
0620 ADD_OP(op) {
0621
0622 op->src.type = OP_SRC_ADD;
0623 op->src.reg = CFI_SP;
0624 op->src.offset = 5*8;
0625 op->dest.type = OP_DEST_REG;
0626 op->dest.reg = CFI_SP;
0627 }
0628 break;
0629 }
0630
0631
0632
0633 case 0xca:
0634 case 0xcb:
0635 *type = INSN_CONTEXT_SWITCH;
0636 break;
0637
0638 case 0xe8:
0639 *type = INSN_CALL;
0640
0641
0642
0643
0644 ADD_OP(op) {
0645 op->src.type = OP_SRC_CONST;
0646 op->dest.type = OP_DEST_PUSH;
0647 }
0648 break;
0649
0650 case 0xfc:
0651 *type = INSN_CLD;
0652 break;
0653
0654 case 0xfd:
0655 *type = INSN_STD;
0656 break;
0657
0658 case 0xff:
0659 if (modrm_reg == 2 || modrm_reg == 3) {
0660
0661 *type = INSN_CALL_DYNAMIC;
0662 if (has_notrack_prefix(&insn))
0663 WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
0664
0665 } else if (modrm_reg == 4) {
0666
0667 *type = INSN_JUMP_DYNAMIC;
0668 if (has_notrack_prefix(&insn))
0669 WARN("notrack prefix found at %s:0x%lx", sec->name, offset);
0670
0671 } else if (modrm_reg == 5) {
0672
0673
0674 *type = INSN_CONTEXT_SWITCH;
0675
0676 } else if (modrm_reg == 6) {
0677
0678
0679 ADD_OP(op) {
0680 op->src.type = OP_SRC_CONST;
0681 op->dest.type = OP_DEST_PUSH;
0682 }
0683 }
0684
0685 break;
0686
0687 default:
0688 break;
0689 }
0690
0691 *immediate = insn.immediate.nbytes ? insn.immediate.value : 0;
0692
0693 return 0;
0694 }
0695
0696 void arch_initial_func_cfi_state(struct cfi_init_state *state)
0697 {
0698 int i;
0699
0700 for (i = 0; i < CFI_NUM_REGS; i++) {
0701 state->regs[i].base = CFI_UNDEFINED;
0702 state->regs[i].offset = 0;
0703 }
0704
0705
0706 state->cfa.base = CFI_SP;
0707 state->cfa.offset = 8;
0708
0709
0710 state->regs[CFI_RA].base = CFI_CFA;
0711 state->regs[CFI_RA].offset = -8;
0712 }
0713
0714 const char *arch_nop_insn(int len)
0715 {
0716 static const char nops[5][5] = {
0717 { BYTES_NOP1 },
0718 { BYTES_NOP2 },
0719 { BYTES_NOP3 },
0720 { BYTES_NOP4 },
0721 { BYTES_NOP5 },
0722 };
0723
0724 if (len < 1 || len > 5) {
0725 WARN("invalid NOP size: %d\n", len);
0726 return NULL;
0727 }
0728
0729 return nops[len-1];
0730 }
0731
0732 #define BYTE_RET 0xC3
0733
0734 const char *arch_ret_insn(int len)
0735 {
0736 static const char ret[5][5] = {
0737 { BYTE_RET },
0738 { BYTE_RET, 0xcc },
0739 { BYTE_RET, 0xcc, BYTES_NOP1 },
0740 { BYTE_RET, 0xcc, BYTES_NOP2 },
0741 { BYTE_RET, 0xcc, BYTES_NOP3 },
0742 };
0743
0744 if (len < 1 || len > 5) {
0745 WARN("invalid RET size: %d\n", len);
0746 return NULL;
0747 }
0748
0749 return ret[len-1];
0750 }
0751
0752 int arch_decode_hint_reg(u8 sp_reg, int *base)
0753 {
0754 switch (sp_reg) {
0755 case ORC_REG_UNDEFINED:
0756 *base = CFI_UNDEFINED;
0757 break;
0758 case ORC_REG_SP:
0759 *base = CFI_SP;
0760 break;
0761 case ORC_REG_BP:
0762 *base = CFI_BP;
0763 break;
0764 case ORC_REG_SP_INDIRECT:
0765 *base = CFI_SP_INDIRECT;
0766 break;
0767 case ORC_REG_R10:
0768 *base = CFI_R10;
0769 break;
0770 case ORC_REG_R13:
0771 *base = CFI_R13;
0772 break;
0773 case ORC_REG_DI:
0774 *base = CFI_DI;
0775 break;
0776 case ORC_REG_DX:
0777 *base = CFI_DX;
0778 break;
0779 default:
0780 return -1;
0781 }
0782
0783 return 0;
0784 }
0785
0786 bool arch_is_retpoline(struct symbol *sym)
0787 {
0788 return !strncmp(sym->name, "__x86_indirect_", 15);
0789 }
0790
0791 bool arch_is_rethunk(struct symbol *sym)
0792 {
0793 return !strcmp(sym->name, "__x86_return_thunk");
0794 }