1 // SPDX-License-Identifier: GPL-2.0 2 #include <string.h> 3 #include <linux/compiler.h> 4 #include <assert.h> 5 #include <inttypes.h> 6 #include "../annotate-data.h" 7 #include "../debug.h" 8 #include "../disasm.h" 9 #include "../dso.h" 10 #include "../map.h" 11 #include "../string2.h" // strstarts 12 #include "../symbol.h" 13 14 /* 15 * x86 instruction nmemonic table to parse disasm lines for annotate. 16 * This table is searched twice - one for exact match and another for 17 * match without a size suffix (b, w, l, q) in case of AT&T syntax. 18 * 19 * So this table should not have entries with the suffix unless it's 20 * a complete different instruction than ones without the suffix. 21 */ 22 static const struct ins x86__instructions[] = { 23 { .name = "adc", .ops = &mov_ops, }, 24 { .name = "add", .ops = &mov_ops, }, 25 { .name = "addsd", .ops = &mov_ops, }, 26 { .name = "and", .ops = &mov_ops, }, 27 { .name = "andpd", .ops = &mov_ops, }, 28 { .name = "andps", .ops = &mov_ops, }, 29 { .name = "bsr", .ops = &mov_ops, }, 30 { .name = "bt", .ops = &mov_ops, }, 31 { .name = "btr", .ops = &mov_ops, }, 32 { .name = "bts", .ops = &mov_ops, }, 33 { .name = "call", .ops = &call_ops, }, 34 { .name = "cmovae", .ops = &mov_ops, }, 35 { .name = "cmovbe", .ops = &mov_ops, }, 36 { .name = "cmove", .ops = &mov_ops, }, 37 { .name = "cmp", .ops = &mov_ops, }, 38 { .name = "cmpxch", .ops = &mov_ops, }, 39 { .name = "cmpxchg", .ops = &mov_ops, }, 40 { .name = "cs", .ops = &mov_ops, }, 41 { .name = "dec", .ops = &dec_ops, }, 42 { .name = "divsd", .ops = &mov_ops, }, 43 { .name = "divss", .ops = &mov_ops, }, 44 { .name = "gs", .ops = &mov_ops, }, 45 { .name = "imul", .ops = &mov_ops, }, 46 { .name = "inc", .ops = &dec_ops, }, 47 { .name = "ja", .ops = &jump_ops, }, 48 { .name = "jae", .ops = &jump_ops, }, 49 { .name = "jb", .ops = &jump_ops, }, 50 { .name = "jbe", .ops = &jump_ops, }, 51 { .name = "jc", .ops = &jump_ops, }, 52 { .name = "jcxz", .ops = &jump_ops, }, 53 { .name = "je", .ops = &jump_ops, }, 54 { .name = "jecxz", .ops = &jump_ops, }, 55 { .name = "jg", .ops = &jump_ops, }, 56 { .name = "jge", .ops = &jump_ops, }, 57 { .name = "jl", .ops = &jump_ops, }, 58 { .name = "jle", .ops = &jump_ops, }, 59 { .name = "jmp", .ops = &jump_ops, }, 60 { .name = "jna", .ops = &jump_ops, }, 61 { .name = "jnae", .ops = &jump_ops, }, 62 { .name = "jnb", .ops = &jump_ops, }, 63 { .name = "jnbe", .ops = &jump_ops, }, 64 { .name = "jnc", .ops = &jump_ops, }, 65 { .name = "jne", .ops = &jump_ops, }, 66 { .name = "jng", .ops = &jump_ops, }, 67 { .name = "jnge", .ops = &jump_ops, }, 68 { .name = "jnl", .ops = &jump_ops, }, 69 { .name = "jnle", .ops = &jump_ops, }, 70 { .name = "jno", .ops = &jump_ops, }, 71 { .name = "jnp", .ops = &jump_ops, }, 72 { .name = "jns", .ops = &jump_ops, }, 73 { .name = "jnz", .ops = &jump_ops, }, 74 { .name = "jo", .ops = &jump_ops, }, 75 { .name = "jp", .ops = &jump_ops, }, 76 { .name = "jpe", .ops = &jump_ops, }, 77 { .name = "jpo", .ops = &jump_ops, }, 78 { .name = "jrcxz", .ops = &jump_ops, }, 79 { .name = "js", .ops = &jump_ops, }, 80 { .name = "jz", .ops = &jump_ops, }, 81 { .name = "lea", .ops = &mov_ops, }, 82 { .name = "lock", .ops = &lock_ops, }, 83 { .name = "mov", .ops = &mov_ops, }, 84 { .name = "movapd", .ops = &mov_ops, }, 85 { .name = "movaps", .ops = &mov_ops, }, 86 { .name = "movdqa", .ops = &mov_ops, }, 87 { .name = "movdqu", .ops = &mov_ops, }, 88 { .name = "movsb", .ops = &mov_ops, }, 89 { .name = "movsd", .ops = &mov_ops, }, 90 { .name = "movsl", .ops = &mov_ops, }, 91 { .name = "movss", .ops = &mov_ops, }, 92 { .name = "movsw", .ops = &mov_ops, }, 93 { .name = "movupd", .ops = &mov_ops, }, 94 { .name = "movups", .ops = &mov_ops, }, 95 { .name = "movzb", .ops = &mov_ops, }, 96 { .name = "movzl", .ops = &mov_ops, }, 97 { .name = "movzw", .ops = &mov_ops, }, 98 { .name = "mulsd", .ops = &mov_ops, }, 99 { .name = "mulss", .ops = &mov_ops, }, 100 { .name = "nop", .ops = &nop_ops, }, 101 { .name = "or", .ops = &mov_ops, }, 102 { .name = "orps", .ops = &mov_ops, }, 103 { .name = "paddq", .ops = &mov_ops, }, 104 { .name = "pand", .ops = &mov_ops, }, 105 { .name = "pcmpeqb", .ops = &mov_ops, }, 106 { .name = "por", .ops = &mov_ops, }, 107 { .name = "rcl", .ops = &mov_ops, }, 108 { .name = "ret", .ops = &ret_ops, }, 109 { .name = "sbb", .ops = &mov_ops, }, 110 { .name = "sete", .ops = &mov_ops, }, 111 { .name = "sub", .ops = &mov_ops, }, 112 { .name = "subsd", .ops = &mov_ops, }, 113 { .name = "test", .ops = &mov_ops, }, 114 { .name = "tzcnt", .ops = &mov_ops, }, 115 { .name = "ucomisd", .ops = &mov_ops, }, 116 { .name = "ucomiss", .ops = &mov_ops, }, 117 { .name = "vaddsd", .ops = &mov_ops, }, 118 { .name = "vandpd", .ops = &mov_ops, }, 119 { .name = "vmovdqa", .ops = &mov_ops, }, 120 { .name = "vmovq", .ops = &mov_ops, }, 121 { .name = "vmovsd", .ops = &mov_ops, }, 122 { .name = "vmulsd", .ops = &mov_ops, }, 123 { .name = "vorpd", .ops = &mov_ops, }, 124 { .name = "vsubsd", .ops = &mov_ops, }, 125 { .name = "vucomisd", .ops = &mov_ops, }, 126 { .name = "xadd", .ops = &mov_ops, }, 127 { .name = "xbegin", .ops = &jump_ops, }, 128 { .name = "xchg", .ops = &mov_ops, }, 129 { .name = "xor", .ops = &mov_ops, }, 130 { .name = "xorpd", .ops = &mov_ops, }, 131 { .name = "xorps", .ops = &mov_ops, }, 132 }; 133 134 static bool amd__ins_is_fused(const struct arch *arch, const char *ins1, 135 const char *ins2) 136 { 137 if (strstr(ins2, "jmp")) 138 return false; 139 140 /* Family >= 15h supports cmp/test + branch fusion */ 141 if (arch->family >= 0x15 && (strstarts(ins1, "test") || 142 (strstarts(ins1, "cmp") && !strstr(ins1, "xchg")))) { 143 return true; 144 } 145 146 /* Family >= 19h supports some ALU + branch fusion */ 147 if (arch->family >= 0x19 && (strstarts(ins1, "add") || 148 strstarts(ins1, "sub") || strstarts(ins1, "and") || 149 strstarts(ins1, "inc") || strstarts(ins1, "dec") || 150 strstarts(ins1, "or") || strstarts(ins1, "xor"))) { 151 return true; 152 } 153 154 return false; 155 } 156 157 static bool intel__ins_is_fused(const struct arch *arch, const char *ins1, 158 const char *ins2) 159 { 160 if (arch->family != 6 || arch->model < 0x1e || strstr(ins2, "jmp")) 161 return false; 162 163 if (arch->model == 0x1e) { 164 /* Nehalem */ 165 if ((strstr(ins1, "cmp") && !strstr(ins1, "xchg")) || 166 strstr(ins1, "test")) { 167 return true; 168 } 169 } else { 170 /* Newer platform */ 171 if ((strstr(ins1, "cmp") && !strstr(ins1, "xchg")) || 172 strstr(ins1, "test") || 173 strstr(ins1, "add") || 174 strstr(ins1, "sub") || 175 strstr(ins1, "and") || 176 strstr(ins1, "inc") || 177 strstr(ins1, "dec")) { 178 return true; 179 } 180 } 181 182 return false; 183 } 184 185 static int x86__cpuid_parse(struct arch *arch, const char *cpuid) 186 { 187 unsigned int family, model, stepping; 188 int ret; 189 190 /* 191 * cpuid = "GenuineIntel,family,model,stepping" 192 */ 193 ret = sscanf(cpuid, "%*[^,],%u,%u,%u", &family, &model, &stepping); 194 if (ret == 3) { 195 arch->family = family; 196 arch->model = model; 197 arch->ins_is_fused = strstarts(cpuid, "AuthenticAMD") ? 198 amd__ins_is_fused : 199 intel__ins_is_fused; 200 return 0; 201 } 202 203 return -1; 204 } 205 206 #ifdef HAVE_LIBDW_SUPPORT 207 static void invalidate_reg_state(struct type_state_reg *reg) 208 { 209 reg->kind = TSR_KIND_INVALID; 210 reg->ok = false; 211 reg->copied_from = -1; 212 } 213 214 static void update_insn_state_x86(struct type_state *state, 215 struct data_loc_info *dloc, Dwarf_Die *cu_die, 216 struct disasm_line *dl) 217 { 218 struct annotated_insn_loc loc; 219 struct annotated_op_loc *src = &loc.ops[INSN_OP_SOURCE]; 220 struct annotated_op_loc *dst = &loc.ops[INSN_OP_TARGET]; 221 struct type_state_reg *tsr; 222 Dwarf_Die type_die; 223 u32 insn_offset = dl->al.offset; 224 int fbreg = dloc->fbreg; 225 int fboff = 0; 226 227 if (annotate_get_insn_location(dloc->arch, dl, &loc) < 0) 228 return; 229 230 if (ins__is_call(&dl->ins)) { 231 struct symbol *func = dl->ops.target.sym; 232 const char *call_name; 233 234 /* Try to resolve the call target name */ 235 if (func) 236 call_name = func->name; 237 else 238 call_name = dl->ops.target.name; 239 240 /* __fentry__ will preserve all registers */ 241 if (call_name && !strcmp(call_name, "__fentry__")) 242 return; 243 244 if (call_name) 245 pr_debug_dtp("call [%x] %s\n", insn_offset, call_name); 246 else 247 pr_debug_dtp("call [%x] <unknown>\n", insn_offset); 248 249 /* Invalidate caller-saved registers after call (ABI requirement) */ 250 for (unsigned i = 0; i < ARRAY_SIZE(state->regs); i++) { 251 if (state->regs[i].caller_saved) 252 invalidate_reg_state(&state->regs[i]); 253 } 254 255 /* Update register with the return type (if any) */ 256 if (call_name && die_find_func_rettype(cu_die, call_name, &type_die)) { 257 tsr = &state->regs[state->ret_reg]; 258 tsr->type = type_die; 259 tsr->kind = TSR_KIND_TYPE; 260 tsr->offset = 0; 261 tsr->ok = true; 262 263 pr_debug_dtp("call [%x] return -> reg%d", 264 insn_offset, state->ret_reg); 265 pr_debug_type_name(&type_die, tsr->kind); 266 } 267 return; 268 } 269 270 if (!strncmp(dl->ins.name, "add", 3)) { 271 u64 imm_value = -1ULL; 272 int offset; 273 const char *var_name = NULL; 274 struct map_symbol *ms = dloc->ms; 275 u64 ip = ms->sym->start + dl->al.offset; 276 277 if (!has_reg_type(state, dst->reg1)) 278 return; 279 280 tsr = &state->regs[dst->reg1]; 281 tsr->copied_from = -1; 282 283 if (src->imm) 284 imm_value = src->offset; 285 else if (has_reg_type(state, src->reg1) && 286 state->regs[src->reg1].kind == TSR_KIND_CONST) 287 imm_value = state->regs[src->reg1].imm_value; 288 else if (src->reg1 == DWARF_REG_PC) { 289 u64 var_addr = annotate_calc_pcrel(dloc->ms, ip, 290 src->offset, dl); 291 292 if (get_global_var_info(dloc, var_addr, 293 &var_name, &offset) && 294 !strcmp(var_name, "this_cpu_off") && 295 tsr->kind == TSR_KIND_CONST) { 296 tsr->kind = TSR_KIND_PERCPU_BASE; 297 tsr->offset = 0; 298 tsr->ok = true; 299 imm_value = tsr->imm_value; 300 } 301 } 302 else 303 return; 304 305 /* Ignore add to non-pointer or non-const types */ 306 if (tsr->kind == TSR_KIND_POINTER || 307 (dwarf_tag(&tsr->type) == DW_TAG_pointer_type && 308 src->reg1 != DWARF_REG_PC && tsr->kind == TSR_KIND_TYPE && !dst->mem_ref)) { 309 tsr->offset += imm_value; 310 pr_debug_dtp("add [%x] offset %#"PRIx64" to reg%d", 311 insn_offset, imm_value, dst->reg1); 312 pr_debug_type_name(&tsr->type, tsr->kind); 313 } 314 315 if (tsr->kind == TSR_KIND_CONST) 316 tsr->imm_value += imm_value; 317 318 if (tsr->kind != TSR_KIND_PERCPU_BASE) 319 return; 320 321 if (get_global_var_type(cu_die, dloc, ip, imm_value, &offset, 322 &type_die) && offset == 0) { 323 /* 324 * This is not a pointer type, but it should be treated 325 * as a pointer. 326 */ 327 tsr->type = type_die; 328 tsr->kind = TSR_KIND_PERCPU_POINTER; 329 tsr->offset = 0; 330 tsr->ok = true; 331 332 pr_debug_dtp("add [%x] percpu %#"PRIx64" -> reg%d", 333 insn_offset, imm_value, dst->reg1); 334 pr_debug_type_name(&tsr->type, tsr->kind); 335 } 336 return; 337 } 338 339 if (!strncmp(dl->ins.name, "sub", 3)) { 340 u64 imm_value = -1ULL; 341 342 if (!has_reg_type(state, dst->reg1)) 343 return; 344 345 tsr = &state->regs[dst->reg1]; 346 tsr->copied_from = -1; 347 348 if (src->imm) 349 imm_value = src->offset; 350 else if (has_reg_type(state, src->reg1) && 351 state->regs[src->reg1].kind == TSR_KIND_CONST) 352 imm_value = state->regs[src->reg1].imm_value; 353 354 if (tsr->kind == TSR_KIND_POINTER || 355 (dwarf_tag(&tsr->type) == DW_TAG_pointer_type && 356 src->reg1 != DWARF_REG_PC && tsr->kind == TSR_KIND_TYPE && !dst->mem_ref)) { 357 tsr->offset -= imm_value; 358 pr_debug_dtp("sub [%x] offset %#"PRIx64" to reg%d", 359 insn_offset, imm_value, dst->reg1); 360 pr_debug_type_name(&tsr->type, tsr->kind); 361 } 362 363 if (tsr->kind == TSR_KIND_CONST) 364 tsr->imm_value -= imm_value; 365 366 return; 367 } 368 369 if (!strncmp(dl->ins.name, "lea", 3)) { 370 int sreg = src->reg1; 371 struct type_state_reg src_tsr; 372 373 if (!has_reg_type(state, sreg) || 374 !has_reg_type(state, dst->reg1) || 375 !src->mem_ref) 376 return; 377 378 src_tsr = state->regs[sreg]; 379 tsr = &state->regs[dst->reg1]; 380 381 invalidate_reg_state(tsr); 382 383 /* Case 1: Based on stack pointer or frame pointer */ 384 if (sreg == fbreg || sreg == state->stack_reg) { 385 struct type_state_stack *stack; 386 int offset = src->offset - fboff; 387 388 stack = find_stack_state(state, offset); 389 if (!stack) 390 return; 391 392 tsr->type = stack->type; 393 tsr->kind = TSR_KIND_POINTER; 394 tsr->offset = offset - stack->offset; 395 tsr->ok = true; 396 397 if (sreg == fbreg) { 398 pr_debug_dtp("lea [%x] address of -%#x(stack) -> reg%d", 399 insn_offset, -src->offset, dst->reg1); 400 } else { 401 pr_debug_dtp("lea [%x] address of %#x(reg%d) -> reg%d", 402 insn_offset, src->offset, sreg, dst->reg1); 403 } 404 405 pr_debug_type_name(&tsr->type, tsr->kind); 406 } 407 /* Case 2: Based on a register holding a typed pointer */ 408 else if (src_tsr.ok && (src_tsr.kind == TSR_KIND_POINTER || 409 (dwarf_tag(&src_tsr.type) == DW_TAG_pointer_type && 410 src_tsr.kind == TSR_KIND_TYPE))) { 411 412 if (src_tsr.kind == TSR_KIND_TYPE && 413 __die_get_real_type(&state->regs[sreg].type, &type_die) == NULL) 414 return; 415 416 if (src_tsr.kind == TSR_KIND_POINTER) 417 type_die = state->regs[sreg].type; 418 419 /* Check if the target type has a member at the new offset */ 420 if (die_get_member_type(&type_die, 421 src->offset + src_tsr.offset, &type_die) == NULL) 422 return; 423 424 tsr->type = src_tsr.type; 425 tsr->kind = src_tsr.kind; 426 tsr->offset = src->offset + src_tsr.offset; 427 tsr->ok = true; 428 429 pr_debug_dtp("lea [%x] address of %s%#x(reg%d) -> reg%d", 430 insn_offset, src->offset < 0 ? "-" : "", 431 abs(src->offset), sreg, dst->reg1); 432 433 pr_debug_type_name(&tsr->type, tsr->kind); 434 } 435 return; 436 } 437 438 /* Invalidate register states for other ops which may change pointers */ 439 if (has_reg_type(state, dst->reg1) && !dst->mem_ref && 440 dwarf_tag(&state->regs[dst->reg1].type) == DW_TAG_pointer_type) { 441 if (!strncmp(dl->ins.name, "imul", 4) || !strncmp(dl->ins.name, "mul", 3) || 442 !strncmp(dl->ins.name, "idiv", 4) || !strncmp(dl->ins.name, "div", 3) || 443 !strncmp(dl->ins.name, "shl", 3) || !strncmp(dl->ins.name, "shr", 3) || 444 !strncmp(dl->ins.name, "sar", 3) || !strncmp(dl->ins.name, "and", 3) || 445 !strncmp(dl->ins.name, "or", 2) || !strncmp(dl->ins.name, "neg", 3) || 446 !strncmp(dl->ins.name, "inc", 3) || !strncmp(dl->ins.name, "dec", 3)) { 447 pr_debug_dtp("%s [%x] invalidate reg%d\n", 448 dl->ins.name, insn_offset, dst->reg1); 449 invalidate_reg_state(&state->regs[dst->reg1]); 450 return; 451 } 452 453 if (!strncmp(dl->ins.name, "xor", 3) && dst->reg1 == src->reg1) { 454 /* xor reg, reg clears the register */ 455 pr_debug_dtp("xor [%x] clear reg%d\n", 456 insn_offset, dst->reg1); 457 458 state->regs[dst->reg1].kind = TSR_KIND_CONST; 459 state->regs[dst->reg1].imm_value = 0; 460 state->regs[dst->reg1].ok = true; 461 state->regs[dst->reg1].copied_from = -1; 462 return; 463 } 464 } 465 466 if (strncmp(dl->ins.name, "mov", 3)) 467 return; 468 469 if (dloc->fb_cfa) { 470 u64 ip = dloc->ms->sym->start + dl->al.offset; 471 u64 pc = map__rip_2objdump(dloc->ms->map, ip); 472 473 if (die_get_cfa(dloc->di->dbg, pc, &fbreg, &fboff) < 0) 474 fbreg = -1; 475 } 476 477 /* Case 1. register to register or segment:offset to register transfers */ 478 if (!src->mem_ref && !dst->mem_ref) { 479 if (!has_reg_type(state, dst->reg1)) 480 return; 481 482 tsr = &state->regs[dst->reg1]; 483 tsr->copied_from = -1; 484 485 if (dso__kernel(map__dso(dloc->ms->map)) && 486 src->segment == INSN_SEG_X86_GS && src->imm) { 487 u64 ip = dloc->ms->sym->start + dl->al.offset; 488 u64 var_addr; 489 int offset; 490 491 /* 492 * In kernel, %gs points to a per-cpu region for the 493 * current CPU. Access with a constant offset should 494 * be treated as a global variable access. 495 */ 496 var_addr = src->offset; 497 498 if (var_addr == 40) { 499 tsr->kind = TSR_KIND_CANARY; 500 tsr->offset = 0; 501 tsr->ok = true; 502 503 pr_debug_dtp("mov [%x] stack canary -> reg%d\n", 504 insn_offset, dst->reg1); 505 return; 506 } 507 508 if (!get_global_var_type(cu_die, dloc, ip, var_addr, 509 &offset, &type_die) || 510 !die_get_member_type(&type_die, offset, &type_die)) { 511 invalidate_reg_state(tsr); 512 return; 513 } 514 515 tsr->type = type_die; 516 tsr->kind = TSR_KIND_TYPE; 517 tsr->offset = 0; 518 tsr->ok = true; 519 520 pr_debug_dtp("mov [%x] this-cpu addr=%#"PRIx64" -> reg%d", 521 insn_offset, var_addr, dst->reg1); 522 pr_debug_type_name(&tsr->type, tsr->kind); 523 return; 524 } 525 526 if (src->imm) { 527 tsr->kind = TSR_KIND_CONST; 528 tsr->imm_value = src->offset; 529 tsr->offset = 0; 530 tsr->ok = true; 531 532 pr_debug_dtp("mov [%x] imm=%#x -> reg%d\n", 533 insn_offset, tsr->imm_value, dst->reg1); 534 return; 535 } 536 537 if (!has_reg_type(state, src->reg1) || 538 !state->regs[src->reg1].ok) { 539 invalidate_reg_state(tsr); 540 return; 541 } 542 543 tsr->type = state->regs[src->reg1].type; 544 tsr->kind = state->regs[src->reg1].kind; 545 tsr->imm_value = state->regs[src->reg1].imm_value; 546 tsr->offset = state->regs[src->reg1].offset; 547 tsr->ok = true; 548 549 /* To copy back the variable type later (hopefully) */ 550 if (tsr->kind == TSR_KIND_TYPE || tsr->kind == TSR_KIND_POINTER) 551 tsr->copied_from = src->reg1; 552 553 pr_debug_dtp("mov [%x] reg%d -> reg%d", 554 insn_offset, src->reg1, dst->reg1); 555 pr_debug_type_name(&tsr->type, tsr->kind); 556 } 557 /* Case 2. memory to register transers */ 558 if (src->mem_ref && !dst->mem_ref) { 559 int sreg = src->reg1; 560 561 if (!has_reg_type(state, dst->reg1)) 562 return; 563 564 tsr = &state->regs[dst->reg1]; 565 tsr->copied_from = -1; 566 567 retry: 568 /* Check stack variables with offset */ 569 if (sreg == fbreg || sreg == state->stack_reg) { 570 struct type_state_stack *stack; 571 int offset = src->offset - fboff; 572 573 stack = find_stack_state(state, offset); 574 if (stack == NULL) { 575 invalidate_reg_state(tsr); 576 return; 577 } else if (!stack->compound) { 578 tsr->type = stack->type; 579 tsr->kind = stack->kind; 580 tsr->offset = stack->ptr_offset; 581 tsr->ok = true; 582 } else if (die_get_member_type(&stack->type, 583 offset - stack->offset, 584 &type_die)) { 585 tsr->type = type_die; 586 tsr->kind = TSR_KIND_TYPE; 587 tsr->offset = 0; 588 tsr->ok = true; 589 } else { 590 invalidate_reg_state(tsr); 591 return; 592 } 593 594 if (sreg == fbreg) { 595 pr_debug_dtp("mov [%x] -%#x(stack) -> reg%d", 596 insn_offset, -offset, dst->reg1); 597 } else { 598 pr_debug_dtp("mov [%x] %#x(reg%d) -> reg%d", 599 insn_offset, offset, sreg, dst->reg1); 600 } 601 pr_debug_type_name(&tsr->type, tsr->kind); 602 } 603 /* And then dereference the pointer if it has one */ 604 else if (has_reg_type(state, sreg) && state->regs[sreg].ok && 605 state->regs[sreg].kind == TSR_KIND_TYPE && 606 die_deref_ptr_type(&state->regs[sreg].type, 607 src->offset + state->regs[sreg].offset, &type_die)) { 608 tsr->type = type_die; 609 tsr->kind = TSR_KIND_TYPE; 610 tsr->offset = 0; 611 tsr->ok = true; 612 613 pr_debug_dtp("mov [%x] %#x(reg%d) -> reg%d", 614 insn_offset, src->offset, sreg, dst->reg1); 615 pr_debug_type_name(&tsr->type, tsr->kind); 616 } 617 /* Handle dereference of TSR_KIND_POINTER registers */ 618 else if (has_reg_type(state, sreg) && state->regs[sreg].ok && 619 state->regs[sreg].kind == TSR_KIND_POINTER && 620 die_get_member_type(&state->regs[sreg].type, 621 src->offset + state->regs[sreg].offset, &type_die)) { 622 tsr->type = state->regs[sreg].type; 623 tsr->kind = TSR_KIND_TYPE; 624 tsr->offset = src->offset + state->regs[sreg].offset; 625 tsr->ok = true; 626 627 pr_debug_dtp("mov [%x] addr %#x(reg%d) -> reg%d", 628 insn_offset, src->offset, sreg, dst->reg1); 629 pr_debug_type_name(&tsr->type, tsr->kind); 630 } 631 /* Or check if it's a global variable */ 632 else if (sreg == DWARF_REG_PC) { 633 struct map_symbol *ms = dloc->ms; 634 u64 ip = ms->sym->start + dl->al.offset; 635 u64 addr; 636 int offset; 637 638 addr = annotate_calc_pcrel(ms, ip, src->offset, dl); 639 640 if (!get_global_var_type(cu_die, dloc, ip, addr, &offset, 641 &type_die) || 642 !die_get_member_type(&type_die, offset, &type_die)) { 643 invalidate_reg_state(tsr); 644 return; 645 } 646 647 tsr->type = type_die; 648 tsr->kind = TSR_KIND_TYPE; 649 tsr->offset = 0; 650 tsr->ok = true; 651 652 pr_debug_dtp("mov [%x] global addr=%"PRIx64" -> reg%d", 653 insn_offset, addr, dst->reg1); 654 pr_debug_type_name(&type_die, tsr->kind); 655 } 656 /* And check percpu access with base register */ 657 else if (has_reg_type(state, sreg) && 658 state->regs[sreg].kind == TSR_KIND_PERCPU_BASE) { 659 u64 ip = dloc->ms->sym->start + dl->al.offset; 660 u64 var_addr = src->offset; 661 int offset; 662 663 if (src->multi_regs) { 664 int reg2 = (sreg == src->reg1) ? src->reg2 : src->reg1; 665 666 if (has_reg_type(state, reg2) && state->regs[reg2].ok && 667 state->regs[reg2].kind == TSR_KIND_CONST) 668 var_addr += state->regs[reg2].imm_value; 669 } 670 671 /* 672 * In kernel, %gs points to a per-cpu region for the 673 * current CPU. Access with a constant offset should 674 * be treated as a global variable access. 675 */ 676 if (get_global_var_type(cu_die, dloc, ip, var_addr, 677 &offset, &type_die) && 678 die_get_member_type(&type_die, offset, &type_die)) { 679 tsr->type = type_die; 680 tsr->kind = TSR_KIND_TYPE; 681 tsr->offset = 0; 682 tsr->ok = true; 683 684 if (src->multi_regs) { 685 pr_debug_dtp("mov [%x] percpu %#x(reg%d,reg%d) -> reg%d", 686 insn_offset, src->offset, src->reg1, 687 src->reg2, dst->reg1); 688 } else { 689 pr_debug_dtp("mov [%x] percpu %#x(reg%d) -> reg%d", 690 insn_offset, src->offset, sreg, dst->reg1); 691 } 692 pr_debug_type_name(&tsr->type, tsr->kind); 693 } else { 694 invalidate_reg_state(tsr); 695 } 696 } 697 /* And then dereference the calculated pointer if it has one */ 698 else if (has_reg_type(state, sreg) && state->regs[sreg].ok && 699 state->regs[sreg].kind == TSR_KIND_PERCPU_POINTER && 700 die_get_member_type(&state->regs[sreg].type, 701 src->offset, &type_die)) { 702 tsr->type = type_die; 703 tsr->kind = TSR_KIND_TYPE; 704 tsr->offset = 0; 705 tsr->ok = true; 706 707 pr_debug_dtp("mov [%x] pointer %#x(reg%d) -> reg%d", 708 insn_offset, src->offset, sreg, dst->reg1); 709 pr_debug_type_name(&tsr->type, tsr->kind); 710 } 711 /* Or try another register if any */ 712 else if (src->multi_regs && sreg == src->reg1 && 713 src->reg1 != src->reg2) { 714 sreg = src->reg2; 715 goto retry; 716 } 717 else { 718 int offset; 719 const char *var_name = NULL; 720 721 /* it might be per-cpu variable (in kernel) access */ 722 if (src->offset < 0) { 723 if (get_global_var_info(dloc, (s64)src->offset, 724 &var_name, &offset) && 725 !strcmp(var_name, "__per_cpu_offset")) { 726 tsr->kind = TSR_KIND_PERCPU_BASE; 727 tsr->offset = 0; 728 tsr->ok = true; 729 730 pr_debug_dtp("mov [%x] percpu base reg%d\n", 731 insn_offset, dst->reg1); 732 return; 733 } 734 } 735 736 invalidate_reg_state(tsr); 737 } 738 } 739 /* Case 3. register to memory transfers */ 740 if (!src->mem_ref && dst->mem_ref) { 741 if (!has_reg_type(state, src->reg1) || 742 !state->regs[src->reg1].ok) 743 return; 744 745 /* Check stack variables with offset */ 746 if (dst->reg1 == fbreg || dst->reg1 == state->stack_reg) { 747 struct type_state_stack *stack; 748 int offset = dst->offset - fboff; 749 750 tsr = &state->regs[src->reg1]; 751 752 stack = find_stack_state(state, offset); 753 if (stack) { 754 /* 755 * The source register is likely to hold a type 756 * of member if it's a compound type. Do not 757 * update the stack variable type since we can 758 * get the member type later by using the 759 * die_get_member_type(). 760 */ 761 if (!stack->compound) 762 set_stack_state(stack, offset, tsr->kind, 763 &tsr->type, tsr->offset); 764 } else { 765 findnew_stack_state(state, offset, tsr->kind, 766 &tsr->type, tsr->offset); 767 } 768 769 if (dst->reg1 == fbreg) { 770 pr_debug_dtp("mov [%x] reg%d -> -%#x(stack)", 771 insn_offset, src->reg1, -offset); 772 } else { 773 pr_debug_dtp("mov [%x] reg%d -> %#x(reg%d)", 774 insn_offset, src->reg1, offset, dst->reg1); 775 } 776 if (tsr->offset != 0) { 777 pr_debug_dtp(" reg%d offset %#x ->", 778 src->reg1, tsr->offset); 779 } 780 781 pr_debug_type_name(&tsr->type, tsr->kind); 782 } 783 /* 784 * Ignore other transfers since it'd set a value in a struct 785 * and won't change the type. 786 */ 787 } 788 /* Case 4. memory to memory transfers (not handled for now) */ 789 } 790 #endif 791 792 const struct arch *arch__new_x86(const struct e_machine_and_e_flags *id, const char *cpuid) 793 { 794 struct arch *arch = zalloc(sizeof(*arch)); 795 796 if (!arch) 797 return NULL; 798 799 arch->name = "x86"; 800 arch->id = *id; 801 if (cpuid) { 802 if (x86__cpuid_parse(arch, cpuid)) { 803 errno = SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING; 804 return NULL; 805 } 806 } 807 arch->instructions = x86__instructions; 808 arch->nr_instructions = ARRAY_SIZE(x86__instructions); 809 #ifndef NDEBUG 810 { 811 static bool sorted_check; 812 813 if (!sorted_check) { 814 for (size_t i = 0; i < arch->nr_instructions - 1; i++) { 815 assert(strcmp(arch->instructions[i].name, 816 arch->instructions[i + 1].name) <= 0); 817 } 818 sorted_check = true; 819 } 820 } 821 #endif 822 arch->sorted_instructions = true; 823 arch->objdump.comment_char = '#'; 824 arch->objdump.register_char = '%'; 825 arch->objdump.memory_ref_char = '('; 826 arch->objdump.imm_char = '$'; 827 arch->insn_suffix = "bwlq"; 828 #ifdef HAVE_LIBDW_SUPPORT 829 arch->update_insn_state = update_insn_state_x86; 830 #endif 831 return arch; 832 } 833