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