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