Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

perf annotate: Split out util/disasm.c

The util/annotate.c code has both disassembly and sample annotation
related codes. Factor out the disasm part so that it can be handled
more easily.

No functional changes intended.

Committer notes:

Add missing include env.h, util.h, bpf-event.h and bpf-util.h to
disasm.c, to fix things like:

util/disasm.c: In function ‘symbol__disassemble_bpf’:
util/disasm.c:1203:9: error: implicit declaration of function ‘perf_exe’ [-Werror=implicit-function-declaration]
1203 | perf_exe(tpath, sizeof(tpath));
| ^~~~~~~~

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Tested-by: Ian Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240329215812.537846-4-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
98f69a57 10adbf77

+1709 -1657
+1
tools/perf/util/Build
··· 12 12 perf-y += copyfile.o 13 13 perf-y += ctype.o 14 14 perf-y += db-export.o 15 + perf-y += disasm.o 15 16 perf-y += env.o 16 17 perf-y += event.o 17 18 perf-y += evlist.o
+2 -1600
tools/perf/util/annotate.c
··· 16 16 #include "build-id.h" 17 17 #include "color.h" 18 18 #include "config.h" 19 + #include "disasm.h" 19 20 #include "dso.h" 20 21 #include "env.h" 21 22 #include "map.h" ··· 65 64 /* global annotation options */ 66 65 struct annotation_options annotate_opts; 67 66 68 - static regex_t file_lineno; 69 - 70 - static struct ins_ops *ins__find(struct arch *arch, const char *name); 71 - static void ins__sort(struct arch *arch); 72 - static int disasm_line__parse(char *line, const char **namep, char **rawp); 73 - static int call__scnprintf(struct ins *ins, char *bf, size_t size, 74 - struct ins_operands *ops, int max_ins_name); 75 - static int jump__scnprintf(struct ins *ins, char *bf, size_t size, 76 - struct ins_operands *ops, int max_ins_name); 77 - 78 - struct arch { 79 - const char *name; 80 - struct ins *instructions; 81 - size_t nr_instructions; 82 - size_t nr_instructions_allocated; 83 - struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); 84 - bool sorted_instructions; 85 - bool initialized; 86 - const char *insn_suffix; 87 - void *priv; 88 - unsigned int model; 89 - unsigned int family; 90 - int (*init)(struct arch *arch, char *cpuid); 91 - bool (*ins_is_fused)(struct arch *arch, const char *ins1, 92 - const char *ins2); 93 - struct { 94 - char comment_char; 95 - char skip_functions_char; 96 - char register_char; 97 - char memory_ref_char; 98 - char imm_char; 99 - } objdump; 100 - }; 101 - 102 - static struct ins_ops call_ops; 103 - static struct ins_ops dec_ops; 104 - static struct ins_ops jump_ops; 105 - static struct ins_ops mov_ops; 106 - static struct ins_ops nop_ops; 107 - static struct ins_ops lock_ops; 108 - static struct ins_ops ret_ops; 109 - 110 67 /* Data type collection debug statistics */ 111 68 struct annotated_data_stat ann_data_stat; 112 69 LIST_HEAD(ann_insn_stat); ··· 83 124 .children = LIST_HEAD_INIT(canary_type.self.children), 84 125 }, 85 126 }; 86 - 87 - static int arch__grow_instructions(struct arch *arch) 88 - { 89 - struct ins *new_instructions; 90 - size_t new_nr_allocated; 91 - 92 - if (arch->nr_instructions_allocated == 0 && arch->instructions) 93 - goto grow_from_non_allocated_table; 94 - 95 - new_nr_allocated = arch->nr_instructions_allocated + 128; 96 - new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); 97 - if (new_instructions == NULL) 98 - return -1; 99 - 100 - out_update_instructions: 101 - arch->instructions = new_instructions; 102 - arch->nr_instructions_allocated = new_nr_allocated; 103 - return 0; 104 - 105 - grow_from_non_allocated_table: 106 - new_nr_allocated = arch->nr_instructions + 128; 107 - new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); 108 - if (new_instructions == NULL) 109 - return -1; 110 - 111 - memcpy(new_instructions, arch->instructions, arch->nr_instructions); 112 - goto out_update_instructions; 113 - } 114 - 115 - static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops) 116 - { 117 - struct ins *ins; 118 - 119 - if (arch->nr_instructions == arch->nr_instructions_allocated && 120 - arch__grow_instructions(arch)) 121 - return -1; 122 - 123 - ins = &arch->instructions[arch->nr_instructions]; 124 - ins->name = strdup(name); 125 - if (!ins->name) 126 - return -1; 127 - 128 - ins->ops = ops; 129 - arch->nr_instructions++; 130 - 131 - ins__sort(arch); 132 - return 0; 133 - } 134 - 135 - #include "arch/arc/annotate/instructions.c" 136 - #include "arch/arm/annotate/instructions.c" 137 - #include "arch/arm64/annotate/instructions.c" 138 - #include "arch/csky/annotate/instructions.c" 139 - #include "arch/loongarch/annotate/instructions.c" 140 - #include "arch/mips/annotate/instructions.c" 141 - #include "arch/x86/annotate/instructions.c" 142 - #include "arch/powerpc/annotate/instructions.c" 143 - #include "arch/riscv64/annotate/instructions.c" 144 - #include "arch/s390/annotate/instructions.c" 145 - #include "arch/sparc/annotate/instructions.c" 146 - 147 - static struct arch architectures[] = { 148 - { 149 - .name = "arc", 150 - .init = arc__annotate_init, 151 - }, 152 - { 153 - .name = "arm", 154 - .init = arm__annotate_init, 155 - }, 156 - { 157 - .name = "arm64", 158 - .init = arm64__annotate_init, 159 - }, 160 - { 161 - .name = "csky", 162 - .init = csky__annotate_init, 163 - }, 164 - { 165 - .name = "mips", 166 - .init = mips__annotate_init, 167 - .objdump = { 168 - .comment_char = '#', 169 - }, 170 - }, 171 - { 172 - .name = "x86", 173 - .init = x86__annotate_init, 174 - .instructions = x86__instructions, 175 - .nr_instructions = ARRAY_SIZE(x86__instructions), 176 - .insn_suffix = "bwlq", 177 - .objdump = { 178 - .comment_char = '#', 179 - .register_char = '%', 180 - .memory_ref_char = '(', 181 - .imm_char = '$', 182 - }, 183 - }, 184 - { 185 - .name = "powerpc", 186 - .init = powerpc__annotate_init, 187 - }, 188 - { 189 - .name = "riscv64", 190 - .init = riscv64__annotate_init, 191 - }, 192 - { 193 - .name = "s390", 194 - .init = s390__annotate_init, 195 - .objdump = { 196 - .comment_char = '#', 197 - }, 198 - }, 199 - { 200 - .name = "sparc", 201 - .init = sparc__annotate_init, 202 - .objdump = { 203 - .comment_char = '#', 204 - }, 205 - }, 206 - { 207 - .name = "loongarch", 208 - .init = loongarch__annotate_init, 209 - .objdump = { 210 - .comment_char = '#', 211 - }, 212 - }, 213 - }; 214 - 215 - static void ins__delete(struct ins_operands *ops) 216 - { 217 - if (ops == NULL) 218 - return; 219 - zfree(&ops->source.raw); 220 - zfree(&ops->source.name); 221 - zfree(&ops->target.raw); 222 - zfree(&ops->target.name); 223 - } 224 - 225 - static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, 226 - struct ins_operands *ops, int max_ins_name) 227 - { 228 - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); 229 - } 230 - 231 - int ins__scnprintf(struct ins *ins, char *bf, size_t size, 232 - struct ins_operands *ops, int max_ins_name) 233 - { 234 - if (ins->ops->scnprintf) 235 - return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); 236 - 237 - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 238 - } 239 - 240 - bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) 241 - { 242 - if (!arch || !arch->ins_is_fused) 243 - return false; 244 - 245 - return arch->ins_is_fused(arch, ins1, ins2); 246 - } 247 - 248 - static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) 249 - { 250 - char *endptr, *tok, *name; 251 - struct map *map = ms->map; 252 - struct addr_map_symbol target = { 253 - .ms = { .map = map, }, 254 - }; 255 - 256 - ops->target.addr = strtoull(ops->raw, &endptr, 16); 257 - 258 - name = strchr(endptr, '<'); 259 - if (name == NULL) 260 - goto indirect_call; 261 - 262 - name++; 263 - 264 - if (arch->objdump.skip_functions_char && 265 - strchr(name, arch->objdump.skip_functions_char)) 266 - return -1; 267 - 268 - tok = strchr(name, '>'); 269 - if (tok == NULL) 270 - return -1; 271 - 272 - *tok = '\0'; 273 - ops->target.name = strdup(name); 274 - *tok = '>'; 275 - 276 - if (ops->target.name == NULL) 277 - return -1; 278 - find_target: 279 - target.addr = map__objdump_2mem(map, ops->target.addr); 280 - 281 - if (maps__find_ams(ms->maps, &target) == 0 && 282 - map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) 283 - ops->target.sym = target.ms.sym; 284 - 285 - return 0; 286 - 287 - indirect_call: 288 - tok = strchr(endptr, '*'); 289 - if (tok != NULL) { 290 - endptr++; 291 - 292 - /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). 293 - * Do not parse such instruction. */ 294 - if (strstr(endptr, "(%r") == NULL) 295 - ops->target.addr = strtoull(endptr, NULL, 16); 296 - } 297 - goto find_target; 298 - } 299 - 300 - static int call__scnprintf(struct ins *ins, char *bf, size_t size, 301 - struct ins_operands *ops, int max_ins_name) 302 - { 303 - if (ops->target.sym) 304 - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); 305 - 306 - if (ops->target.addr == 0) 307 - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 308 - 309 - if (ops->target.name) 310 - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); 311 - 312 - return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); 313 - } 314 - 315 - static struct ins_ops call_ops = { 316 - .parse = call__parse, 317 - .scnprintf = call__scnprintf, 318 - }; 319 - 320 - bool ins__is_call(const struct ins *ins) 321 - { 322 - return ins->ops == &call_ops || ins->ops == &s390_call_ops || ins->ops == &loongarch_call_ops; 323 - } 324 - 325 - /* 326 - * Prevents from matching commas in the comment section, e.g.: 327 - * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast 328 - * 329 - * and skip comma as part of function arguments, e.g.: 330 - * 1d8b4ac <linemap_lookup(line_maps const*, unsigned int)+0xcc> 331 - */ 332 - static inline const char *validate_comma(const char *c, struct ins_operands *ops) 333 - { 334 - if (ops->jump.raw_comment && c > ops->jump.raw_comment) 335 - return NULL; 336 - 337 - if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) 338 - return NULL; 339 - 340 - return c; 341 - } 342 - 343 - static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) 344 - { 345 - struct map *map = ms->map; 346 - struct symbol *sym = ms->sym; 347 - struct addr_map_symbol target = { 348 - .ms = { .map = map, }, 349 - }; 350 - const char *c = strchr(ops->raw, ','); 351 - u64 start, end; 352 - 353 - ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); 354 - ops->jump.raw_func_start = strchr(ops->raw, '<'); 355 - 356 - c = validate_comma(c, ops); 357 - 358 - /* 359 - * Examples of lines to parse for the _cpp_lex_token@@Base 360 - * function: 361 - * 362 - * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> 363 - * 1159e8b: jne c469be <cpp_named_operator2name@@Base+0xa72> 364 - * 365 - * The first is a jump to an offset inside the same function, 366 - * the second is to another function, i.e. that 0xa72 is an 367 - * offset in the cpp_named_operator2name@@base function. 368 - */ 369 - /* 370 - * skip over possible up to 2 operands to get to address, e.g.: 371 - * tbnz w0, #26, ffff0000083cd190 <security_file_permission+0xd0> 372 - */ 373 - if (c++ != NULL) { 374 - ops->target.addr = strtoull(c, NULL, 16); 375 - if (!ops->target.addr) { 376 - c = strchr(c, ','); 377 - c = validate_comma(c, ops); 378 - if (c++ != NULL) 379 - ops->target.addr = strtoull(c, NULL, 16); 380 - } 381 - } else { 382 - ops->target.addr = strtoull(ops->raw, NULL, 16); 383 - } 384 - 385 - target.addr = map__objdump_2mem(map, ops->target.addr); 386 - start = map__unmap_ip(map, sym->start); 387 - end = map__unmap_ip(map, sym->end); 388 - 389 - ops->target.outside = target.addr < start || target.addr > end; 390 - 391 - /* 392 - * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): 393 - 394 - cpp_named_operator2name@@Base+0xa72 395 - 396 - * Point to a place that is after the cpp_named_operator2name 397 - * boundaries, i.e. in the ELF symbol table for cc1 398 - * cpp_named_operator2name is marked as being 32-bytes long, but it in 399 - * fact is much larger than that, so we seem to need a symbols__find() 400 - * routine that looks for >= current->start and < next_symbol->start, 401 - * possibly just for C++ objects? 402 - * 403 - * For now lets just make some progress by marking jumps to outside the 404 - * current function as call like. 405 - * 406 - * Actual navigation will come next, with further understanding of how 407 - * the symbol searching and disassembly should be done. 408 - */ 409 - if (maps__find_ams(ms->maps, &target) == 0 && 410 - map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) 411 - ops->target.sym = target.ms.sym; 412 - 413 - if (!ops->target.outside) { 414 - ops->target.offset = target.addr - start; 415 - ops->target.offset_avail = true; 416 - } else { 417 - ops->target.offset_avail = false; 418 - } 419 - 420 - return 0; 421 - } 422 - 423 - static int jump__scnprintf(struct ins *ins, char *bf, size_t size, 424 - struct ins_operands *ops, int max_ins_name) 425 - { 426 - const char *c; 427 - 428 - if (!ops->target.addr || ops->target.offset < 0) 429 - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 430 - 431 - if (ops->target.outside && ops->target.sym != NULL) 432 - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); 433 - 434 - c = strchr(ops->raw, ','); 435 - c = validate_comma(c, ops); 436 - 437 - if (c != NULL) { 438 - const char *c2 = strchr(c + 1, ','); 439 - 440 - c2 = validate_comma(c2, ops); 441 - /* check for 3-op insn */ 442 - if (c2 != NULL) 443 - c = c2; 444 - c++; 445 - 446 - /* mirror arch objdump's space-after-comma style */ 447 - if (*c == ' ') 448 - c++; 449 - } 450 - 451 - return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, 452 - ins->name, c ? c - ops->raw : 0, ops->raw, 453 - ops->target.offset); 454 - } 455 - 456 - static void jump__delete(struct ins_operands *ops __maybe_unused) 457 - { 458 - /* 459 - * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the 460 - * raw string, don't free them. 461 - */ 462 - } 463 - 464 - static struct ins_ops jump_ops = { 465 - .free = jump__delete, 466 - .parse = jump__parse, 467 - .scnprintf = jump__scnprintf, 468 - }; 469 - 470 - bool ins__is_jump(const struct ins *ins) 471 - { 472 - return ins->ops == &jump_ops || ins->ops == &loongarch_jump_ops; 473 - } 474 - 475 - static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) 476 - { 477 - char *endptr, *name, *t; 478 - 479 - if (strstr(raw, "(%rip)") == NULL) 480 - return 0; 481 - 482 - *addrp = strtoull(comment, &endptr, 16); 483 - if (endptr == comment) 484 - return 0; 485 - name = strchr(endptr, '<'); 486 - if (name == NULL) 487 - return -1; 488 - 489 - name++; 490 - 491 - t = strchr(name, '>'); 492 - if (t == NULL) 493 - return 0; 494 - 495 - *t = '\0'; 496 - *namep = strdup(name); 497 - *t = '>'; 498 - 499 - return 0; 500 - } 501 - 502 - static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) 503 - { 504 - ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); 505 - if (ops->locked.ops == NULL) 506 - return 0; 507 - 508 - if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) 509 - goto out_free_ops; 510 - 511 - ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); 512 - 513 - if (ops->locked.ins.ops == NULL) 514 - goto out_free_ops; 515 - 516 - if (ops->locked.ins.ops->parse && 517 - ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) 518 - goto out_free_ops; 519 - 520 - return 0; 521 - 522 - out_free_ops: 523 - zfree(&ops->locked.ops); 524 - return 0; 525 - } 526 - 527 - static int lock__scnprintf(struct ins *ins, char *bf, size_t size, 528 - struct ins_operands *ops, int max_ins_name) 529 - { 530 - int printed; 531 - 532 - if (ops->locked.ins.ops == NULL) 533 - return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 534 - 535 - printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name); 536 - return printed + ins__scnprintf(&ops->locked.ins, bf + printed, 537 - size - printed, ops->locked.ops, max_ins_name); 538 - } 539 - 540 - static void lock__delete(struct ins_operands *ops) 541 - { 542 - struct ins *ins = &ops->locked.ins; 543 - 544 - if (ins->ops && ins->ops->free) 545 - ins->ops->free(ops->locked.ops); 546 - else 547 - ins__delete(ops->locked.ops); 548 - 549 - zfree(&ops->locked.ops); 550 - zfree(&ops->target.raw); 551 - zfree(&ops->target.name); 552 - } 553 - 554 - static struct ins_ops lock_ops = { 555 - .free = lock__delete, 556 - .parse = lock__parse, 557 - .scnprintf = lock__scnprintf, 558 - }; 559 - 560 - /* 561 - * Check if the operand has more than one registers like x86 SIB addressing: 562 - * 0x1234(%rax, %rbx, 8) 563 - * 564 - * But it doesn't care segment selectors like %gs:0x5678(%rcx), so just check 565 - * the input string after 'memory_ref_char' if exists. 566 - */ 567 - static bool check_multi_regs(struct arch *arch, const char *op) 568 - { 569 - int count = 0; 570 - 571 - if (arch->objdump.register_char == 0) 572 - return false; 573 - 574 - if (arch->objdump.memory_ref_char) { 575 - op = strchr(op, arch->objdump.memory_ref_char); 576 - if (op == NULL) 577 - return false; 578 - } 579 - 580 - while ((op = strchr(op, arch->objdump.register_char)) != NULL) { 581 - count++; 582 - op++; 583 - } 584 - 585 - return count > 1; 586 - } 587 - 588 - static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) 589 - { 590 - char *s = strchr(ops->raw, ','), *target, *comment, prev; 591 - 592 - if (s == NULL) 593 - return -1; 594 - 595 - *s = '\0'; 596 - 597 - /* 598 - * x86 SIB addressing has something like 0x8(%rax, %rcx, 1) 599 - * then it needs to have the closing parenthesis. 600 - */ 601 - if (strchr(ops->raw, '(')) { 602 - *s = ','; 603 - s = strchr(ops->raw, ')'); 604 - if (s == NULL || s[1] != ',') 605 - return -1; 606 - *++s = '\0'; 607 - } 608 - 609 - ops->source.raw = strdup(ops->raw); 610 - *s = ','; 611 - 612 - if (ops->source.raw == NULL) 613 - return -1; 614 - 615 - ops->source.multi_regs = check_multi_regs(arch, ops->source.raw); 616 - 617 - target = skip_spaces(++s); 618 - comment = strchr(s, arch->objdump.comment_char); 619 - 620 - if (comment != NULL) 621 - s = comment - 1; 622 - else 623 - s = strchr(s, '\0') - 1; 624 - 625 - while (s > target && isspace(s[0])) 626 - --s; 627 - s++; 628 - prev = *s; 629 - *s = '\0'; 630 - 631 - ops->target.raw = strdup(target); 632 - *s = prev; 633 - 634 - if (ops->target.raw == NULL) 635 - goto out_free_source; 636 - 637 - ops->target.multi_regs = check_multi_regs(arch, ops->target.raw); 638 - 639 - if (comment == NULL) 640 - return 0; 641 - 642 - comment = skip_spaces(comment); 643 - comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name); 644 - comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); 645 - 646 - return 0; 647 - 648 - out_free_source: 649 - zfree(&ops->source.raw); 650 - return -1; 651 - } 652 - 653 - static int mov__scnprintf(struct ins *ins, char *bf, size_t size, 654 - struct ins_operands *ops, int max_ins_name) 655 - { 656 - return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name, 657 - ops->source.name ?: ops->source.raw, 658 - ops->target.name ?: ops->target.raw); 659 - } 660 - 661 - static struct ins_ops mov_ops = { 662 - .parse = mov__parse, 663 - .scnprintf = mov__scnprintf, 664 - }; 665 - 666 - static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) 667 - { 668 - char *target, *comment, *s, prev; 669 - 670 - target = s = ops->raw; 671 - 672 - while (s[0] != '\0' && !isspace(s[0])) 673 - ++s; 674 - prev = *s; 675 - *s = '\0'; 676 - 677 - ops->target.raw = strdup(target); 678 - *s = prev; 679 - 680 - if (ops->target.raw == NULL) 681 - return -1; 682 - 683 - comment = strchr(s, arch->objdump.comment_char); 684 - if (comment == NULL) 685 - return 0; 686 - 687 - comment = skip_spaces(comment); 688 - comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); 689 - 690 - return 0; 691 - } 692 - 693 - static int dec__scnprintf(struct ins *ins, char *bf, size_t size, 694 - struct ins_operands *ops, int max_ins_name) 695 - { 696 - return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, 697 - ops->target.name ?: ops->target.raw); 698 - } 699 - 700 - static struct ins_ops dec_ops = { 701 - .parse = dec__parse, 702 - .scnprintf = dec__scnprintf, 703 - }; 704 - 705 - static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, 706 - struct ins_operands *ops __maybe_unused, int max_ins_name) 707 - { 708 - return scnprintf(bf, size, "%-*s", max_ins_name, "nop"); 709 - } 710 - 711 - static struct ins_ops nop_ops = { 712 - .scnprintf = nop__scnprintf, 713 - }; 714 - 715 - static struct ins_ops ret_ops = { 716 - .scnprintf = ins__raw_scnprintf, 717 - }; 718 - 719 - bool ins__is_nop(const struct ins *ins) 720 - { 721 - return ins->ops == &nop_ops; 722 - } 723 - 724 - bool ins__is_ret(const struct ins *ins) 725 - { 726 - return ins->ops == &ret_ops; 727 - } 728 - 729 - bool ins__is_lock(const struct ins *ins) 730 - { 731 - return ins->ops == &lock_ops; 732 - } 733 - 734 - static int ins__key_cmp(const void *name, const void *insp) 735 - { 736 - const struct ins *ins = insp; 737 - 738 - return strcmp(name, ins->name); 739 - } 740 - 741 - static int ins__cmp(const void *a, const void *b) 742 - { 743 - const struct ins *ia = a; 744 - const struct ins *ib = b; 745 - 746 - return strcmp(ia->name, ib->name); 747 - } 748 - 749 - static void ins__sort(struct arch *arch) 750 - { 751 - const int nmemb = arch->nr_instructions; 752 - 753 - qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); 754 - } 755 - 756 - static struct ins_ops *__ins__find(struct arch *arch, const char *name) 757 - { 758 - struct ins *ins; 759 - const int nmemb = arch->nr_instructions; 760 - 761 - if (!arch->sorted_instructions) { 762 - ins__sort(arch); 763 - arch->sorted_instructions = true; 764 - } 765 - 766 - ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); 767 - if (ins) 768 - return ins->ops; 769 - 770 - if (arch->insn_suffix) { 771 - char tmp[32]; 772 - char suffix; 773 - size_t len = strlen(name); 774 - 775 - if (len == 0 || len >= sizeof(tmp)) 776 - return NULL; 777 - 778 - suffix = name[len - 1]; 779 - if (strchr(arch->insn_suffix, suffix) == NULL) 780 - return NULL; 781 - 782 - strcpy(tmp, name); 783 - tmp[len - 1] = '\0'; /* remove the suffix and check again */ 784 - 785 - ins = bsearch(tmp, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); 786 - } 787 - return ins ? ins->ops : NULL; 788 - } 789 - 790 - static struct ins_ops *ins__find(struct arch *arch, const char *name) 791 - { 792 - struct ins_ops *ops = __ins__find(arch, name); 793 - 794 - if (!ops && arch->associate_instruction_ops) 795 - ops = arch->associate_instruction_ops(arch, name); 796 - 797 - return ops; 798 - } 799 - 800 - static int arch__key_cmp(const void *name, const void *archp) 801 - { 802 - const struct arch *arch = archp; 803 - 804 - return strcmp(name, arch->name); 805 - } 806 - 807 - static int arch__cmp(const void *a, const void *b) 808 - { 809 - const struct arch *aa = a; 810 - const struct arch *ab = b; 811 - 812 - return strcmp(aa->name, ab->name); 813 - } 814 - 815 - static void arch__sort(void) 816 - { 817 - const int nmemb = ARRAY_SIZE(architectures); 818 - 819 - qsort(architectures, nmemb, sizeof(struct arch), arch__cmp); 820 - } 821 - 822 - static struct arch *arch__find(const char *name) 823 - { 824 - const int nmemb = ARRAY_SIZE(architectures); 825 - static bool sorted; 826 - 827 - if (!sorted) { 828 - arch__sort(); 829 - sorted = true; 830 - } 831 - 832 - return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); 833 - } 834 - 835 - bool arch__is(struct arch *arch, const char *name) 836 - { 837 - return !strcmp(arch->name, name); 838 - } 839 127 840 128 /* symbol histogram: key = offset << 16 | evsel->core.idx */ 841 129 static size_t sym_hist_hash(long key, void *ctx __maybe_unused) ··· 489 1283 return symbol__inc_addr_samples(&he->ms, evsel, ip, sample); 490 1284 } 491 1285 492 - static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) 493 - { 494 - dl->ins.ops = ins__find(arch, dl->ins.name); 495 - 496 - if (!dl->ins.ops) 497 - return; 498 - 499 - if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0) 500 - dl->ins.ops = NULL; 501 - } 502 - 503 - static int disasm_line__parse(char *line, const char **namep, char **rawp) 504 - { 505 - char tmp, *name = skip_spaces(line); 506 - 507 - if (name[0] == '\0') 508 - return -1; 509 - 510 - *rawp = name + 1; 511 - 512 - while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) 513 - ++*rawp; 514 - 515 - tmp = (*rawp)[0]; 516 - (*rawp)[0] = '\0'; 517 - *namep = strdup(name); 518 - 519 - if (*namep == NULL) 520 - goto out; 521 - 522 - (*rawp)[0] = tmp; 523 - *rawp = strim(*rawp); 524 - 525 - return 0; 526 - 527 - out: 528 - return -1; 529 - } 530 - 531 - struct annotate_args { 532 - struct arch *arch; 533 - struct map_symbol ms; 534 - struct evsel *evsel; 535 - struct annotation_options *options; 536 - s64 offset; 537 - char *line; 538 - int line_nr; 539 - char *fileloc; 540 - }; 541 - 542 - static void annotation_line__init(struct annotation_line *al, 543 - struct annotate_args *args, 544 - int nr) 545 - { 546 - al->offset = args->offset; 547 - al->line = strdup(args->line); 548 - al->line_nr = args->line_nr; 549 - al->fileloc = args->fileloc; 550 - al->data_nr = nr; 551 - } 552 - 553 - static void annotation_line__exit(struct annotation_line *al) 554 - { 555 - zfree_srcline(&al->path); 556 - zfree(&al->line); 557 - zfree(&al->cycles); 558 - } 559 - 560 - static size_t disasm_line_size(int nr) 561 - { 562 - struct annotation_line *al; 563 - 564 - return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr)); 565 - } 566 - 567 - /* 568 - * Allocating the disasm annotation line data with 569 - * following structure: 570 - * 571 - * ------------------------------------------- 572 - * struct disasm_line | struct annotation_line 573 - * ------------------------------------------- 574 - * 575 - * We have 'struct annotation_line' member as last member 576 - * of 'struct disasm_line' to have an easy access. 577 - */ 578 - static struct disasm_line *disasm_line__new(struct annotate_args *args) 579 - { 580 - struct disasm_line *dl = NULL; 581 - int nr = 1; 582 - 583 - if (evsel__is_group_event(args->evsel)) 584 - nr = args->evsel->core.nr_members; 585 - 586 - dl = zalloc(disasm_line_size(nr)); 587 - if (!dl) 588 - return NULL; 589 - 590 - annotation_line__init(&dl->al, args, nr); 591 - if (dl->al.line == NULL) 592 - goto out_delete; 593 - 594 - if (args->offset != -1) { 595 - if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) 596 - goto out_free_line; 597 - 598 - disasm_line__init_ins(dl, args->arch, &args->ms); 599 - } 600 - 601 - return dl; 602 - 603 - out_free_line: 604 - zfree(&dl->al.line); 605 - out_delete: 606 - free(dl); 607 - return NULL; 608 - } 609 - 610 - void disasm_line__free(struct disasm_line *dl) 611 - { 612 - if (dl->ins.ops && dl->ins.ops->free) 613 - dl->ins.ops->free(&dl->ops); 614 - else 615 - ins__delete(&dl->ops); 616 - zfree(&dl->ins.name); 617 - annotation_line__exit(&dl->al); 618 - free(dl); 619 - } 620 - 621 - int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name) 622 - { 623 - if (raw || !dl->ins.ops) 624 - return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw); 625 - 626 - return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name); 627 - } 628 1286 629 1287 void annotation__exit(struct annotation *notes) 630 1288 { ··· 548 1478 return mutex_trylock(mutex); 549 1479 } 550 1480 551 - 552 - static void annotation_line__add(struct annotation_line *al, struct list_head *head) 1481 + void annotation_line__add(struct annotation_line *al, struct list_head *head) 553 1482 { 554 1483 list_add_tail(&al->node, head); 555 1484 } ··· 756 1687 } 757 1688 758 1689 return 0; 759 - } 760 - 761 - /* 762 - * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) 763 - * which looks like following 764 - * 765 - * 0000000000415500 <_init>: 766 - * 415500: sub $0x8,%rsp 767 - * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> 768 - * 41550b: test %rax,%rax 769 - * 41550e: je 415515 <_init+0x15> 770 - * 415510: callq 416e70 <__gmon_start__@plt> 771 - * 415515: add $0x8,%rsp 772 - * 415519: retq 773 - * 774 - * it will be parsed and saved into struct disasm_line as 775 - * <offset> <name> <ops.raw> 776 - * 777 - * The offset will be a relative offset from the start of the symbol and -1 778 - * means that it's not a disassembly line so should be treated differently. 779 - * The ops.raw part will be parsed further according to type of the instruction. 780 - */ 781 - static int symbol__parse_objdump_line(struct symbol *sym, 782 - struct annotate_args *args, 783 - char *parsed_line, int *line_nr, char **fileloc) 784 - { 785 - struct map *map = args->ms.map; 786 - struct annotation *notes = symbol__annotation(sym); 787 - struct disasm_line *dl; 788 - char *tmp; 789 - s64 line_ip, offset = -1; 790 - regmatch_t match[2]; 791 - 792 - /* /filename:linenr ? Save line number and ignore. */ 793 - if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { 794 - *line_nr = atoi(parsed_line + match[1].rm_so); 795 - free(*fileloc); 796 - *fileloc = strdup(parsed_line); 797 - return 0; 798 - } 799 - 800 - /* Process hex address followed by ':'. */ 801 - line_ip = strtoull(parsed_line, &tmp, 16); 802 - if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') { 803 - u64 start = map__rip_2objdump(map, sym->start), 804 - end = map__rip_2objdump(map, sym->end); 805 - 806 - offset = line_ip - start; 807 - if ((u64)line_ip < start || (u64)line_ip >= end) 808 - offset = -1; 809 - else 810 - parsed_line = tmp + 1; 811 - } 812 - 813 - args->offset = offset; 814 - args->line = parsed_line; 815 - args->line_nr = *line_nr; 816 - args->fileloc = *fileloc; 817 - args->ms.sym = sym; 818 - 819 - dl = disasm_line__new(args); 820 - (*line_nr)++; 821 - 822 - if (dl == NULL) 823 - return -1; 824 - 825 - if (!disasm_line__has_local_offset(dl)) { 826 - dl->ops.target.offset = dl->ops.target.addr - 827 - map__rip_2objdump(map, sym->start); 828 - dl->ops.target.offset_avail = true; 829 - } 830 - 831 - /* kcore has no symbols, so add the call target symbol */ 832 - if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) { 833 - struct addr_map_symbol target = { 834 - .addr = dl->ops.target.addr, 835 - .ms = { .map = map, }, 836 - }; 837 - 838 - if (!maps__find_ams(args->ms.maps, &target) && 839 - target.ms.sym->start == target.al_addr) 840 - dl->ops.target.sym = target.ms.sym; 841 - } 842 - 843 - annotation_line__add(&dl->al, &notes->src->source); 844 - return 0; 845 - } 846 - 847 - static __attribute__((constructor)) void symbol__init_regexpr(void) 848 - { 849 - regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED); 850 - } 851 - 852 - static void delete_last_nop(struct symbol *sym) 853 - { 854 - struct annotation *notes = symbol__annotation(sym); 855 - struct list_head *list = &notes->src->source; 856 - struct disasm_line *dl; 857 - 858 - while (!list_empty(list)) { 859 - dl = list_entry(list->prev, struct disasm_line, al.node); 860 - 861 - if (dl->ins.ops) { 862 - if (!ins__is_nop(&dl->ins)) 863 - return; 864 - } else { 865 - if (!strstr(dl->al.line, " nop ") && 866 - !strstr(dl->al.line, " nopl ") && 867 - !strstr(dl->al.line, " nopw ")) 868 - return; 869 - } 870 - 871 - list_del_init(&dl->al.node); 872 - disasm_line__free(dl); 873 - } 874 - } 875 - 876 - int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen) 877 - { 878 - struct dso *dso = map__dso(ms->map); 879 - 880 - BUG_ON(buflen == 0); 881 - 882 - if (errnum >= 0) { 883 - str_error_r(errnum, buf, buflen); 884 - return 0; 885 - } 886 - 887 - switch (errnum) { 888 - case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: { 889 - char bf[SBUILD_ID_SIZE + 15] = " with build id "; 890 - char *build_id_msg = NULL; 891 - 892 - if (dso->has_build_id) { 893 - build_id__sprintf(&dso->bid, bf + 15); 894 - build_id_msg = bf; 895 - } 896 - scnprintf(buf, buflen, 897 - "No vmlinux file%s\nwas found in the path.\n\n" 898 - "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n" 899 - "Please use:\n\n" 900 - " perf buildid-cache -vu vmlinux\n\n" 901 - "or:\n\n" 902 - " --vmlinux vmlinux\n", build_id_msg ?: ""); 903 - } 904 - break; 905 - case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF: 906 - scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation"); 907 - break; 908 - case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP: 909 - scnprintf(buf, buflen, "Problems with arch specific instruction name regular expressions."); 910 - break; 911 - case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING: 912 - scnprintf(buf, buflen, "Problems while parsing the CPUID in the arch specific initialization."); 913 - break; 914 - case SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE: 915 - scnprintf(buf, buflen, "Invalid BPF file: %s.", dso->long_name); 916 - break; 917 - case SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF: 918 - scnprintf(buf, buflen, "The %s BPF file has no BTF section, compile with -g or use pahole -J.", 919 - dso->long_name); 920 - break; 921 - default: 922 - scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum); 923 - break; 924 - } 925 - 926 - return 0; 927 - } 928 - 929 - static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size) 930 - { 931 - char linkname[PATH_MAX]; 932 - char *build_id_filename; 933 - char *build_id_path = NULL; 934 - char *pos; 935 - int len; 936 - 937 - if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && 938 - !dso__is_kcore(dso)) 939 - return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; 940 - 941 - build_id_filename = dso__build_id_filename(dso, NULL, 0, false); 942 - if (build_id_filename) { 943 - __symbol__join_symfs(filename, filename_size, build_id_filename); 944 - free(build_id_filename); 945 - } else { 946 - if (dso->has_build_id) 947 - return ENOMEM; 948 - goto fallback; 949 - } 950 - 951 - build_id_path = strdup(filename); 952 - if (!build_id_path) 953 - return ENOMEM; 954 - 955 - /* 956 - * old style build-id cache has name of XX/XXXXXXX.. while 957 - * new style has XX/XXXXXXX../{elf,kallsyms,vdso}. 958 - * extract the build-id part of dirname in the new style only. 959 - */ 960 - pos = strrchr(build_id_path, '/'); 961 - if (pos && strlen(pos) < SBUILD_ID_SIZE - 2) 962 - dirname(build_id_path); 963 - 964 - if (dso__is_kcore(dso)) 965 - goto fallback; 966 - 967 - len = readlink(build_id_path, linkname, sizeof(linkname) - 1); 968 - if (len < 0) 969 - goto fallback; 970 - 971 - linkname[len] = '\0'; 972 - if (strstr(linkname, DSO__NAME_KALLSYMS) || 973 - access(filename, R_OK)) { 974 - fallback: 975 - /* 976 - * If we don't have build-ids or the build-id file isn't in the 977 - * cache, or is just a kallsyms file, well, lets hope that this 978 - * DSO is the same as when 'perf record' ran. 979 - */ 980 - if (dso->kernel && dso->long_name[0] == '/') 981 - snprintf(filename, filename_size, "%s", dso->long_name); 982 - else 983 - __symbol__join_symfs(filename, filename_size, dso->long_name); 984 - 985 - mutex_lock(&dso->lock); 986 - if (access(filename, R_OK) && errno == ENOENT && dso->nsinfo) { 987 - char *new_name = dso__filename_with_chroot(dso, filename); 988 - if (new_name) { 989 - strlcpy(filename, new_name, filename_size); 990 - free(new_name); 991 - } 992 - } 993 - mutex_unlock(&dso->lock); 994 - } 995 - 996 - free(build_id_path); 997 - return 0; 998 - } 999 - 1000 - #if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1001 - #define PACKAGE "perf" 1002 - #include <bfd.h> 1003 - #include <dis-asm.h> 1004 - #include <bpf/bpf.h> 1005 - #include <bpf/btf.h> 1006 - #include <bpf/libbpf.h> 1007 - #include <linux/btf.h> 1008 - #include <tools/dis-asm-compat.h> 1009 - 1010 - static int symbol__disassemble_bpf(struct symbol *sym, 1011 - struct annotate_args *args) 1012 - { 1013 - struct annotation *notes = symbol__annotation(sym); 1014 - struct bpf_prog_linfo *prog_linfo = NULL; 1015 - struct bpf_prog_info_node *info_node; 1016 - int len = sym->end - sym->start; 1017 - disassembler_ftype disassemble; 1018 - struct map *map = args->ms.map; 1019 - struct perf_bpil *info_linear; 1020 - struct disassemble_info info; 1021 - struct dso *dso = map__dso(map); 1022 - int pc = 0, count, sub_id; 1023 - struct btf *btf = NULL; 1024 - char tpath[PATH_MAX]; 1025 - size_t buf_size; 1026 - int nr_skip = 0; 1027 - char *buf; 1028 - bfd *bfdf; 1029 - int ret; 1030 - FILE *s; 1031 - 1032 - if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) 1033 - return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; 1034 - 1035 - pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__, 1036 - sym->name, sym->start, sym->end - sym->start); 1037 - 1038 - memset(tpath, 0, sizeof(tpath)); 1039 - perf_exe(tpath, sizeof(tpath)); 1040 - 1041 - bfdf = bfd_openr(tpath, NULL); 1042 - if (bfdf == NULL) 1043 - abort(); 1044 - 1045 - if (!bfd_check_format(bfdf, bfd_object)) 1046 - abort(); 1047 - 1048 - s = open_memstream(&buf, &buf_size); 1049 - if (!s) { 1050 - ret = errno; 1051 - goto out; 1052 - } 1053 - init_disassemble_info_compat(&info, s, 1054 - (fprintf_ftype) fprintf, 1055 - fprintf_styled); 1056 - info.arch = bfd_get_arch(bfdf); 1057 - info.mach = bfd_get_mach(bfdf); 1058 - 1059 - info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, 1060 - dso->bpf_prog.id); 1061 - if (!info_node) { 1062 - ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; 1063 - goto out; 1064 - } 1065 - info_linear = info_node->info_linear; 1066 - sub_id = dso->bpf_prog.sub_id; 1067 - 1068 - info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns); 1069 - info.buffer_length = info_linear->info.jited_prog_len; 1070 - 1071 - if (info_linear->info.nr_line_info) 1072 - prog_linfo = bpf_prog_linfo__new(&info_linear->info); 1073 - 1074 - if (info_linear->info.btf_id) { 1075 - struct btf_node *node; 1076 - 1077 - node = perf_env__find_btf(dso->bpf_prog.env, 1078 - info_linear->info.btf_id); 1079 - if (node) 1080 - btf = btf__new((__u8 *)(node->data), 1081 - node->data_size); 1082 - } 1083 - 1084 - disassemble_init_for_target(&info); 1085 - 1086 - #ifdef DISASM_FOUR_ARGS_SIGNATURE 1087 - disassemble = disassembler(info.arch, 1088 - bfd_big_endian(bfdf), 1089 - info.mach, 1090 - bfdf); 1091 - #else 1092 - disassemble = disassembler(bfdf); 1093 - #endif 1094 - if (disassemble == NULL) 1095 - abort(); 1096 - 1097 - fflush(s); 1098 - do { 1099 - const struct bpf_line_info *linfo = NULL; 1100 - struct disasm_line *dl; 1101 - size_t prev_buf_size; 1102 - const char *srcline; 1103 - u64 addr; 1104 - 1105 - addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id]; 1106 - count = disassemble(pc, &info); 1107 - 1108 - if (prog_linfo) 1109 - linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, 1110 - addr, sub_id, 1111 - nr_skip); 1112 - 1113 - if (linfo && btf) { 1114 - srcline = btf__name_by_offset(btf, linfo->line_off); 1115 - nr_skip++; 1116 - } else 1117 - srcline = NULL; 1118 - 1119 - fprintf(s, "\n"); 1120 - prev_buf_size = buf_size; 1121 - fflush(s); 1122 - 1123 - if (!annotate_opts.hide_src_code && srcline) { 1124 - args->offset = -1; 1125 - args->line = strdup(srcline); 1126 - args->line_nr = 0; 1127 - args->fileloc = NULL; 1128 - args->ms.sym = sym; 1129 - dl = disasm_line__new(args); 1130 - if (dl) { 1131 - annotation_line__add(&dl->al, 1132 - &notes->src->source); 1133 - } 1134 - } 1135 - 1136 - args->offset = pc; 1137 - args->line = buf + prev_buf_size; 1138 - args->line_nr = 0; 1139 - args->fileloc = NULL; 1140 - args->ms.sym = sym; 1141 - dl = disasm_line__new(args); 1142 - if (dl) 1143 - annotation_line__add(&dl->al, &notes->src->source); 1144 - 1145 - pc += count; 1146 - } while (count > 0 && pc < len); 1147 - 1148 - ret = 0; 1149 - out: 1150 - free(prog_linfo); 1151 - btf__free(btf); 1152 - fclose(s); 1153 - bfd_close(bfdf); 1154 - return ret; 1155 - } 1156 - #else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1157 - static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, 1158 - struct annotate_args *args __maybe_unused) 1159 - { 1160 - return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; 1161 - } 1162 - #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1163 - 1164 - static int 1165 - symbol__disassemble_bpf_image(struct symbol *sym, 1166 - struct annotate_args *args) 1167 - { 1168 - struct annotation *notes = symbol__annotation(sym); 1169 - struct disasm_line *dl; 1170 - 1171 - args->offset = -1; 1172 - args->line = strdup("to be implemented"); 1173 - args->line_nr = 0; 1174 - args->fileloc = NULL; 1175 - dl = disasm_line__new(args); 1176 - if (dl) 1177 - annotation_line__add(&dl->al, &notes->src->source); 1178 - 1179 - zfree(&args->line); 1180 - return 0; 1181 - } 1182 - 1183 - /* 1184 - * Possibly create a new version of line with tabs expanded. Returns the 1185 - * existing or new line, storage is updated if a new line is allocated. If 1186 - * allocation fails then NULL is returned. 1187 - */ 1188 - static char *expand_tabs(char *line, char **storage, size_t *storage_len) 1189 - { 1190 - size_t i, src, dst, len, new_storage_len, num_tabs; 1191 - char *new_line; 1192 - size_t line_len = strlen(line); 1193 - 1194 - for (num_tabs = 0, i = 0; i < line_len; i++) 1195 - if (line[i] == '\t') 1196 - num_tabs++; 1197 - 1198 - if (num_tabs == 0) 1199 - return line; 1200 - 1201 - /* 1202 - * Space for the line and '\0', less the leading and trailing 1203 - * spaces. Each tab may introduce 7 additional spaces. 1204 - */ 1205 - new_storage_len = line_len + 1 + (num_tabs * 7); 1206 - 1207 - new_line = malloc(new_storage_len); 1208 - if (new_line == NULL) { 1209 - pr_err("Failure allocating memory for tab expansion\n"); 1210 - return NULL; 1211 - } 1212 - 1213 - /* 1214 - * Copy regions starting at src and expand tabs. If there are two 1215 - * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces 1216 - * are inserted. 1217 - */ 1218 - for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) { 1219 - if (line[i] == '\t') { 1220 - len = i - src; 1221 - memcpy(&new_line[dst], &line[src], len); 1222 - dst += len; 1223 - new_line[dst++] = ' '; 1224 - while (dst % 8 != 0) 1225 - new_line[dst++] = ' '; 1226 - src = i + 1; 1227 - num_tabs--; 1228 - } 1229 - } 1230 - 1231 - /* Expand the last region. */ 1232 - len = line_len - src; 1233 - memcpy(&new_line[dst], &line[src], len); 1234 - dst += len; 1235 - new_line[dst] = '\0'; 1236 - 1237 - free(*storage); 1238 - *storage = new_line; 1239 - *storage_len = new_storage_len; 1240 - return new_line; 1241 - 1242 - } 1243 - 1244 - static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) 1245 - { 1246 - struct annotation_options *opts = &annotate_opts; 1247 - struct map *map = args->ms.map; 1248 - struct dso *dso = map__dso(map); 1249 - char *command; 1250 - FILE *file; 1251 - char symfs_filename[PATH_MAX]; 1252 - struct kcore_extract kce; 1253 - bool delete_extract = false; 1254 - bool decomp = false; 1255 - int lineno = 0; 1256 - char *fileloc = NULL; 1257 - int nline; 1258 - char *line; 1259 - size_t line_len; 1260 - const char *objdump_argv[] = { 1261 - "/bin/sh", 1262 - "-c", 1263 - NULL, /* Will be the objdump command to run. */ 1264 - "--", 1265 - NULL, /* Will be the symfs path. */ 1266 - NULL, 1267 - }; 1268 - struct child_process objdump_process; 1269 - int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); 1270 - 1271 - if (err) 1272 - return err; 1273 - 1274 - pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 1275 - symfs_filename, sym->name, map__unmap_ip(map, sym->start), 1276 - map__unmap_ip(map, sym->end)); 1277 - 1278 - pr_debug("annotating [%p] %30s : [%p] %30s\n", 1279 - dso, dso->long_name, sym, sym->name); 1280 - 1281 - if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { 1282 - return symbol__disassemble_bpf(sym, args); 1283 - } else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) { 1284 - return symbol__disassemble_bpf_image(sym, args); 1285 - } else if (dso__is_kcore(dso)) { 1286 - kce.kcore_filename = symfs_filename; 1287 - kce.addr = map__rip_2objdump(map, sym->start); 1288 - kce.offs = sym->start; 1289 - kce.len = sym->end - sym->start; 1290 - if (!kcore_extract__create(&kce)) { 1291 - delete_extract = true; 1292 - strlcpy(symfs_filename, kce.extract_filename, 1293 - sizeof(symfs_filename)); 1294 - } 1295 - } else if (dso__needs_decompress(dso)) { 1296 - char tmp[KMOD_DECOMP_LEN]; 1297 - 1298 - if (dso__decompress_kmodule_path(dso, symfs_filename, 1299 - tmp, sizeof(tmp)) < 0) 1300 - return -1; 1301 - 1302 - decomp = true; 1303 - strcpy(symfs_filename, tmp); 1304 - } 1305 - 1306 - err = asprintf(&command, 1307 - "%s %s%s --start-address=0x%016" PRIx64 1308 - " --stop-address=0x%016" PRIx64 1309 - " %s -d %s %s %s %c%s%c %s%s -C \"$1\"", 1310 - opts->objdump_path ?: "objdump", 1311 - opts->disassembler_style ? "-M " : "", 1312 - opts->disassembler_style ?: "", 1313 - map__rip_2objdump(map, sym->start), 1314 - map__rip_2objdump(map, sym->end), 1315 - opts->show_linenr ? "-l" : "", 1316 - opts->show_asm_raw ? "" : "--no-show-raw-insn", 1317 - opts->annotate_src ? "-S" : "", 1318 - opts->prefix ? "--prefix " : "", 1319 - opts->prefix ? '"' : ' ', 1320 - opts->prefix ?: "", 1321 - opts->prefix ? '"' : ' ', 1322 - opts->prefix_strip ? "--prefix-strip=" : "", 1323 - opts->prefix_strip ?: ""); 1324 - 1325 - if (err < 0) { 1326 - pr_err("Failure allocating memory for the command to run\n"); 1327 - goto out_remove_tmp; 1328 - } 1329 - 1330 - pr_debug("Executing: %s\n", command); 1331 - 1332 - objdump_argv[2] = command; 1333 - objdump_argv[4] = symfs_filename; 1334 - 1335 - /* Create a pipe to read from for stdout */ 1336 - memset(&objdump_process, 0, sizeof(objdump_process)); 1337 - objdump_process.argv = objdump_argv; 1338 - objdump_process.out = -1; 1339 - objdump_process.err = -1; 1340 - objdump_process.no_stderr = 1; 1341 - if (start_command(&objdump_process)) { 1342 - pr_err("Failure starting to run %s\n", command); 1343 - err = -1; 1344 - goto out_free_command; 1345 - } 1346 - 1347 - file = fdopen(objdump_process.out, "r"); 1348 - if (!file) { 1349 - pr_err("Failure creating FILE stream for %s\n", command); 1350 - /* 1351 - * If we were using debug info should retry with 1352 - * original binary. 1353 - */ 1354 - err = -1; 1355 - goto out_close_stdout; 1356 - } 1357 - 1358 - /* Storage for getline. */ 1359 - line = NULL; 1360 - line_len = 0; 1361 - 1362 - nline = 0; 1363 - while (!feof(file)) { 1364 - const char *match; 1365 - char *expanded_line; 1366 - 1367 - if (getline(&line, &line_len, file) < 0 || !line) 1368 - break; 1369 - 1370 - /* Skip lines containing "filename:" */ 1371 - match = strstr(line, symfs_filename); 1372 - if (match && match[strlen(symfs_filename)] == ':') 1373 - continue; 1374 - 1375 - expanded_line = strim(line); 1376 - expanded_line = expand_tabs(expanded_line, &line, &line_len); 1377 - if (!expanded_line) 1378 - break; 1379 - 1380 - /* 1381 - * The source code line number (lineno) needs to be kept in 1382 - * across calls to symbol__parse_objdump_line(), so that it 1383 - * can associate it with the instructions till the next one. 1384 - * See disasm_line__new() and struct disasm_line::line_nr. 1385 - */ 1386 - if (symbol__parse_objdump_line(sym, args, expanded_line, 1387 - &lineno, &fileloc) < 0) 1388 - break; 1389 - nline++; 1390 - } 1391 - free(line); 1392 - free(fileloc); 1393 - 1394 - err = finish_command(&objdump_process); 1395 - if (err) 1396 - pr_err("Error running %s\n", command); 1397 - 1398 - if (nline == 0) { 1399 - err = -1; 1400 - pr_err("No output from %s\n", command); 1401 - } 1402 - 1403 - /* 1404 - * kallsyms does not have symbol sizes so there may a nop at the end. 1405 - * Remove it. 1406 - */ 1407 - if (dso__is_kcore(dso)) 1408 - delete_last_nop(sym); 1409 - 1410 - fclose(file); 1411 - 1412 - out_close_stdout: 1413 - close(objdump_process.out); 1414 - 1415 - out_free_command: 1416 - free(command); 1417 - 1418 - out_remove_tmp: 1419 - if (decomp) 1420 - unlink(symfs_filename); 1421 - 1422 - if (delete_extract) 1423 - kcore_extract__delete(&kce); 1424 - 1425 - return err; 1426 1690 } 1427 1691 1428 1692 static void calc_percent(struct annotation *notes,
+3 -57
tools/perf/util/annotate.h
··· 13 13 #include "mutex.h" 14 14 #include "spark.h" 15 15 #include "hashmap.h" 16 + #include "disasm.h" 16 17 17 18 struct hist_browser_timer; 18 19 struct hist_entry; 19 - struct ins_ops; 20 20 struct map; 21 21 struct map_symbol; 22 22 struct addr_map_symbol; ··· 25 25 struct evsel; 26 26 struct symbol; 27 27 struct annotated_data_type; 28 - 29 - struct ins { 30 - const char *name; 31 - struct ins_ops *ops; 32 - }; 33 - 34 - struct ins_operands { 35 - char *raw; 36 - struct { 37 - char *raw; 38 - char *name; 39 - struct symbol *sym; 40 - u64 addr; 41 - s64 offset; 42 - bool offset_avail; 43 - bool outside; 44 - bool multi_regs; 45 - } target; 46 - union { 47 - struct { 48 - char *raw; 49 - char *name; 50 - u64 addr; 51 - bool multi_regs; 52 - } source; 53 - struct { 54 - struct ins ins; 55 - struct ins_operands *ops; 56 - } locked; 57 - struct { 58 - char *raw_comment; 59 - char *raw_func_start; 60 - } jump; 61 - }; 62 - }; 63 - 64 - struct arch; 65 - 66 - bool arch__is(struct arch *arch, const char *name); 67 - 68 - struct ins_ops { 69 - void (*free)(struct ins_operands *ops); 70 - int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); 71 - int (*scnprintf)(struct ins *ins, char *bf, size_t size, 72 - struct ins_operands *ops, int max_ins_name); 73 - }; 74 - 75 - bool ins__is_jump(const struct ins *ins); 76 - bool ins__is_call(const struct ins *ins); 77 - bool ins__is_nop(const struct ins *ins); 78 - bool ins__is_ret(const struct ins *ins); 79 - bool ins__is_lock(const struct ins *ins); 80 - int ins__scnprintf(struct ins *ins, char *bf, size_t size, struct ins_operands *ops, int max_ins_name); 81 - bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); 82 28 83 29 #define ANNOTATION__IPC_WIDTH 6 84 30 #define ANNOTATION__CYCLES_WIDTH 6 ··· 118 172 struct annotation_line al; 119 173 }; 120 174 175 + void annotation_line__add(struct annotation_line *al, struct list_head *head); 176 + 121 177 static inline double annotation_data__percent(struct annotation_data *data, 122 178 unsigned int which) 123 179 { ··· 161 213 */ 162 214 bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym); 163 215 164 - void disasm_line__free(struct disasm_line *dl); 165 216 struct annotation_line * 166 217 annotation_line__next(struct annotation_line *pos, struct list_head *head); 167 218 ··· 183 236 struct evsel *evsel, 184 237 bool show_freq); 185 238 186 - int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name); 187 239 size_t disasm__fprintf(struct list_head *head, FILE *fp); 188 240 void symbol__calc_percent(struct symbol *sym, struct evsel *evsel); 189 241
+1591
tools/perf/util/disasm.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + #include <ctype.h> 3 + #include <errno.h> 4 + #include <inttypes.h> 5 + #include <libgen.h> 6 + #include <regex.h> 7 + #include <stdlib.h> 8 + #include <unistd.h> 9 + 10 + #include <linux/string.h> 11 + #include <subcmd/run-command.h> 12 + 13 + #include "annotate.h" 14 + #include "build-id.h" 15 + #include "debug.h" 16 + #include "disasm.h" 17 + #include "dso.h" 18 + #include "env.h" 19 + #include "evsel.h" 20 + #include "map.h" 21 + #include "maps.h" 22 + #include "srcline.h" 23 + #include "symbol.h" 24 + #include "util.h" 25 + 26 + static regex_t file_lineno; 27 + 28 + /* These can be referred from the arch-dependent code */ 29 + static struct ins_ops call_ops; 30 + static struct ins_ops dec_ops; 31 + static struct ins_ops jump_ops; 32 + static struct ins_ops mov_ops; 33 + static struct ins_ops nop_ops; 34 + static struct ins_ops lock_ops; 35 + static struct ins_ops ret_ops; 36 + 37 + static int jump__scnprintf(struct ins *ins, char *bf, size_t size, 38 + struct ins_operands *ops, int max_ins_name); 39 + static int call__scnprintf(struct ins *ins, char *bf, size_t size, 40 + struct ins_operands *ops, int max_ins_name); 41 + 42 + static void ins__sort(struct arch *arch); 43 + static int disasm_line__parse(char *line, const char **namep, char **rawp); 44 + 45 + static __attribute__((constructor)) void symbol__init_regexpr(void) 46 + { 47 + regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED); 48 + } 49 + 50 + static int arch__grow_instructions(struct arch *arch) 51 + { 52 + struct ins *new_instructions; 53 + size_t new_nr_allocated; 54 + 55 + if (arch->nr_instructions_allocated == 0 && arch->instructions) 56 + goto grow_from_non_allocated_table; 57 + 58 + new_nr_allocated = arch->nr_instructions_allocated + 128; 59 + new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins)); 60 + if (new_instructions == NULL) 61 + return -1; 62 + 63 + out_update_instructions: 64 + arch->instructions = new_instructions; 65 + arch->nr_instructions_allocated = new_nr_allocated; 66 + return 0; 67 + 68 + grow_from_non_allocated_table: 69 + new_nr_allocated = arch->nr_instructions + 128; 70 + new_instructions = calloc(new_nr_allocated, sizeof(struct ins)); 71 + if (new_instructions == NULL) 72 + return -1; 73 + 74 + memcpy(new_instructions, arch->instructions, arch->nr_instructions); 75 + goto out_update_instructions; 76 + } 77 + 78 + static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops) 79 + { 80 + struct ins *ins; 81 + 82 + if (arch->nr_instructions == arch->nr_instructions_allocated && 83 + arch__grow_instructions(arch)) 84 + return -1; 85 + 86 + ins = &arch->instructions[arch->nr_instructions]; 87 + ins->name = strdup(name); 88 + if (!ins->name) 89 + return -1; 90 + 91 + ins->ops = ops; 92 + arch->nr_instructions++; 93 + 94 + ins__sort(arch); 95 + return 0; 96 + } 97 + 98 + #include "arch/arc/annotate/instructions.c" 99 + #include "arch/arm/annotate/instructions.c" 100 + #include "arch/arm64/annotate/instructions.c" 101 + #include "arch/csky/annotate/instructions.c" 102 + #include "arch/loongarch/annotate/instructions.c" 103 + #include "arch/mips/annotate/instructions.c" 104 + #include "arch/x86/annotate/instructions.c" 105 + #include "arch/powerpc/annotate/instructions.c" 106 + #include "arch/riscv64/annotate/instructions.c" 107 + #include "arch/s390/annotate/instructions.c" 108 + #include "arch/sparc/annotate/instructions.c" 109 + 110 + static struct arch architectures[] = { 111 + { 112 + .name = "arc", 113 + .init = arc__annotate_init, 114 + }, 115 + { 116 + .name = "arm", 117 + .init = arm__annotate_init, 118 + }, 119 + { 120 + .name = "arm64", 121 + .init = arm64__annotate_init, 122 + }, 123 + { 124 + .name = "csky", 125 + .init = csky__annotate_init, 126 + }, 127 + { 128 + .name = "mips", 129 + .init = mips__annotate_init, 130 + .objdump = { 131 + .comment_char = '#', 132 + }, 133 + }, 134 + { 135 + .name = "x86", 136 + .init = x86__annotate_init, 137 + .instructions = x86__instructions, 138 + .nr_instructions = ARRAY_SIZE(x86__instructions), 139 + .insn_suffix = "bwlq", 140 + .objdump = { 141 + .comment_char = '#', 142 + .register_char = '%', 143 + .memory_ref_char = '(', 144 + .imm_char = '$', 145 + }, 146 + }, 147 + { 148 + .name = "powerpc", 149 + .init = powerpc__annotate_init, 150 + }, 151 + { 152 + .name = "riscv64", 153 + .init = riscv64__annotate_init, 154 + }, 155 + { 156 + .name = "s390", 157 + .init = s390__annotate_init, 158 + .objdump = { 159 + .comment_char = '#', 160 + }, 161 + }, 162 + { 163 + .name = "sparc", 164 + .init = sparc__annotate_init, 165 + .objdump = { 166 + .comment_char = '#', 167 + }, 168 + }, 169 + { 170 + .name = "loongarch", 171 + .init = loongarch__annotate_init, 172 + .objdump = { 173 + .comment_char = '#', 174 + }, 175 + }, 176 + }; 177 + 178 + static int arch__key_cmp(const void *name, const void *archp) 179 + { 180 + const struct arch *arch = archp; 181 + 182 + return strcmp(name, arch->name); 183 + } 184 + 185 + static int arch__cmp(const void *a, const void *b) 186 + { 187 + const struct arch *aa = a; 188 + const struct arch *ab = b; 189 + 190 + return strcmp(aa->name, ab->name); 191 + } 192 + 193 + static void arch__sort(void) 194 + { 195 + const int nmemb = ARRAY_SIZE(architectures); 196 + 197 + qsort(architectures, nmemb, sizeof(struct arch), arch__cmp); 198 + } 199 + 200 + struct arch *arch__find(const char *name) 201 + { 202 + const int nmemb = ARRAY_SIZE(architectures); 203 + static bool sorted; 204 + 205 + if (!sorted) { 206 + arch__sort(); 207 + sorted = true; 208 + } 209 + 210 + return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); 211 + } 212 + 213 + bool arch__is(struct arch *arch, const char *name) 214 + { 215 + return !strcmp(arch->name, name); 216 + } 217 + 218 + static void ins_ops__delete(struct ins_operands *ops) 219 + { 220 + if (ops == NULL) 221 + return; 222 + zfree(&ops->source.raw); 223 + zfree(&ops->source.name); 224 + zfree(&ops->target.raw); 225 + zfree(&ops->target.name); 226 + } 227 + 228 + static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, 229 + struct ins_operands *ops, int max_ins_name) 230 + { 231 + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw); 232 + } 233 + 234 + int ins__scnprintf(struct ins *ins, char *bf, size_t size, 235 + struct ins_operands *ops, int max_ins_name) 236 + { 237 + if (ins->ops->scnprintf) 238 + return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name); 239 + 240 + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 241 + } 242 + 243 + bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2) 244 + { 245 + if (!arch || !arch->ins_is_fused) 246 + return false; 247 + 248 + return arch->ins_is_fused(arch, ins1, ins2); 249 + } 250 + 251 + static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) 252 + { 253 + char *endptr, *tok, *name; 254 + struct map *map = ms->map; 255 + struct addr_map_symbol target = { 256 + .ms = { .map = map, }, 257 + }; 258 + 259 + ops->target.addr = strtoull(ops->raw, &endptr, 16); 260 + 261 + name = strchr(endptr, '<'); 262 + if (name == NULL) 263 + goto indirect_call; 264 + 265 + name++; 266 + 267 + if (arch->objdump.skip_functions_char && 268 + strchr(name, arch->objdump.skip_functions_char)) 269 + return -1; 270 + 271 + tok = strchr(name, '>'); 272 + if (tok == NULL) 273 + return -1; 274 + 275 + *tok = '\0'; 276 + ops->target.name = strdup(name); 277 + *tok = '>'; 278 + 279 + if (ops->target.name == NULL) 280 + return -1; 281 + find_target: 282 + target.addr = map__objdump_2mem(map, ops->target.addr); 283 + 284 + if (maps__find_ams(ms->maps, &target) == 0 && 285 + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) 286 + ops->target.sym = target.ms.sym; 287 + 288 + return 0; 289 + 290 + indirect_call: 291 + tok = strchr(endptr, '*'); 292 + if (tok != NULL) { 293 + endptr++; 294 + 295 + /* Indirect call can use a non-rip register and offset: callq *0x8(%rbx). 296 + * Do not parse such instruction. */ 297 + if (strstr(endptr, "(%r") == NULL) 298 + ops->target.addr = strtoull(endptr, NULL, 16); 299 + } 300 + goto find_target; 301 + } 302 + 303 + static int call__scnprintf(struct ins *ins, char *bf, size_t size, 304 + struct ins_operands *ops, int max_ins_name) 305 + { 306 + if (ops->target.sym) 307 + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); 308 + 309 + if (ops->target.addr == 0) 310 + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 311 + 312 + if (ops->target.name) 313 + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name); 314 + 315 + return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr); 316 + } 317 + 318 + static struct ins_ops call_ops = { 319 + .parse = call__parse, 320 + .scnprintf = call__scnprintf, 321 + }; 322 + 323 + bool ins__is_call(const struct ins *ins) 324 + { 325 + return ins->ops == &call_ops || ins->ops == &s390_call_ops || ins->ops == &loongarch_call_ops; 326 + } 327 + 328 + /* 329 + * Prevents from matching commas in the comment section, e.g.: 330 + * ffff200008446e70: b.cs ffff2000084470f4 <generic_exec_single+0x314> // b.hs, b.nlast 331 + * 332 + * and skip comma as part of function arguments, e.g.: 333 + * 1d8b4ac <linemap_lookup(line_maps const*, unsigned int)+0xcc> 334 + */ 335 + static inline const char *validate_comma(const char *c, struct ins_operands *ops) 336 + { 337 + if (ops->jump.raw_comment && c > ops->jump.raw_comment) 338 + return NULL; 339 + 340 + if (ops->jump.raw_func_start && c > ops->jump.raw_func_start) 341 + return NULL; 342 + 343 + return c; 344 + } 345 + 346 + static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) 347 + { 348 + struct map *map = ms->map; 349 + struct symbol *sym = ms->sym; 350 + struct addr_map_symbol target = { 351 + .ms = { .map = map, }, 352 + }; 353 + const char *c = strchr(ops->raw, ','); 354 + u64 start, end; 355 + 356 + ops->jump.raw_comment = strchr(ops->raw, arch->objdump.comment_char); 357 + ops->jump.raw_func_start = strchr(ops->raw, '<'); 358 + 359 + c = validate_comma(c, ops); 360 + 361 + /* 362 + * Examples of lines to parse for the _cpp_lex_token@@Base 363 + * function: 364 + * 365 + * 1159e6c: jne 115aa32 <_cpp_lex_token@@Base+0xf92> 366 + * 1159e8b: jne c469be <cpp_named_operator2name@@Base+0xa72> 367 + * 368 + * The first is a jump to an offset inside the same function, 369 + * the second is to another function, i.e. that 0xa72 is an 370 + * offset in the cpp_named_operator2name@@base function. 371 + */ 372 + /* 373 + * skip over possible up to 2 operands to get to address, e.g.: 374 + * tbnz w0, #26, ffff0000083cd190 <security_file_permission+0xd0> 375 + */ 376 + if (c++ != NULL) { 377 + ops->target.addr = strtoull(c, NULL, 16); 378 + if (!ops->target.addr) { 379 + c = strchr(c, ','); 380 + c = validate_comma(c, ops); 381 + if (c++ != NULL) 382 + ops->target.addr = strtoull(c, NULL, 16); 383 + } 384 + } else { 385 + ops->target.addr = strtoull(ops->raw, NULL, 16); 386 + } 387 + 388 + target.addr = map__objdump_2mem(map, ops->target.addr); 389 + start = map__unmap_ip(map, sym->start); 390 + end = map__unmap_ip(map, sym->end); 391 + 392 + ops->target.outside = target.addr < start || target.addr > end; 393 + 394 + /* 395 + * FIXME: things like this in _cpp_lex_token (gcc's cc1 program): 396 + 397 + cpp_named_operator2name@@Base+0xa72 398 + 399 + * Point to a place that is after the cpp_named_operator2name 400 + * boundaries, i.e. in the ELF symbol table for cc1 401 + * cpp_named_operator2name is marked as being 32-bytes long, but it in 402 + * fact is much larger than that, so we seem to need a symbols__find() 403 + * routine that looks for >= current->start and < next_symbol->start, 404 + * possibly just for C++ objects? 405 + * 406 + * For now lets just make some progress by marking jumps to outside the 407 + * current function as call like. 408 + * 409 + * Actual navigation will come next, with further understanding of how 410 + * the symbol searching and disassembly should be done. 411 + */ 412 + if (maps__find_ams(ms->maps, &target) == 0 && 413 + map__rip_2objdump(target.ms.map, map__map_ip(target.ms.map, target.addr)) == ops->target.addr) 414 + ops->target.sym = target.ms.sym; 415 + 416 + if (!ops->target.outside) { 417 + ops->target.offset = target.addr - start; 418 + ops->target.offset_avail = true; 419 + } else { 420 + ops->target.offset_avail = false; 421 + } 422 + 423 + return 0; 424 + } 425 + 426 + static int jump__scnprintf(struct ins *ins, char *bf, size_t size, 427 + struct ins_operands *ops, int max_ins_name) 428 + { 429 + const char *c; 430 + 431 + if (!ops->target.addr || ops->target.offset < 0) 432 + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 433 + 434 + if (ops->target.outside && ops->target.sym != NULL) 435 + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name); 436 + 437 + c = strchr(ops->raw, ','); 438 + c = validate_comma(c, ops); 439 + 440 + if (c != NULL) { 441 + const char *c2 = strchr(c + 1, ','); 442 + 443 + c2 = validate_comma(c2, ops); 444 + /* check for 3-op insn */ 445 + if (c2 != NULL) 446 + c = c2; 447 + c++; 448 + 449 + /* mirror arch objdump's space-after-comma style */ 450 + if (*c == ' ') 451 + c++; 452 + } 453 + 454 + return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name, 455 + ins->name, c ? c - ops->raw : 0, ops->raw, 456 + ops->target.offset); 457 + } 458 + 459 + static void jump__delete(struct ins_operands *ops __maybe_unused) 460 + { 461 + /* 462 + * The ops->jump.raw_comment and ops->jump.raw_func_start belong to the 463 + * raw string, don't free them. 464 + */ 465 + } 466 + 467 + static struct ins_ops jump_ops = { 468 + .free = jump__delete, 469 + .parse = jump__parse, 470 + .scnprintf = jump__scnprintf, 471 + }; 472 + 473 + bool ins__is_jump(const struct ins *ins) 474 + { 475 + return ins->ops == &jump_ops || ins->ops == &loongarch_jump_ops; 476 + } 477 + 478 + static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) 479 + { 480 + char *endptr, *name, *t; 481 + 482 + if (strstr(raw, "(%rip)") == NULL) 483 + return 0; 484 + 485 + *addrp = strtoull(comment, &endptr, 16); 486 + if (endptr == comment) 487 + return 0; 488 + name = strchr(endptr, '<'); 489 + if (name == NULL) 490 + return -1; 491 + 492 + name++; 493 + 494 + t = strchr(name, '>'); 495 + if (t == NULL) 496 + return 0; 497 + 498 + *t = '\0'; 499 + *namep = strdup(name); 500 + *t = '>'; 501 + 502 + return 0; 503 + } 504 + 505 + static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms) 506 + { 507 + ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); 508 + if (ops->locked.ops == NULL) 509 + return 0; 510 + 511 + if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0) 512 + goto out_free_ops; 513 + 514 + ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name); 515 + 516 + if (ops->locked.ins.ops == NULL) 517 + goto out_free_ops; 518 + 519 + if (ops->locked.ins.ops->parse && 520 + ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0) 521 + goto out_free_ops; 522 + 523 + return 0; 524 + 525 + out_free_ops: 526 + zfree(&ops->locked.ops); 527 + return 0; 528 + } 529 + 530 + static int lock__scnprintf(struct ins *ins, char *bf, size_t size, 531 + struct ins_operands *ops, int max_ins_name) 532 + { 533 + int printed; 534 + 535 + if (ops->locked.ins.ops == NULL) 536 + return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name); 537 + 538 + printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name); 539 + return printed + ins__scnprintf(&ops->locked.ins, bf + printed, 540 + size - printed, ops->locked.ops, max_ins_name); 541 + } 542 + 543 + static void lock__delete(struct ins_operands *ops) 544 + { 545 + struct ins *ins = &ops->locked.ins; 546 + 547 + if (ins->ops && ins->ops->free) 548 + ins->ops->free(ops->locked.ops); 549 + else 550 + ins_ops__delete(ops->locked.ops); 551 + 552 + zfree(&ops->locked.ops); 553 + zfree(&ops->target.raw); 554 + zfree(&ops->target.name); 555 + } 556 + 557 + static struct ins_ops lock_ops = { 558 + .free = lock__delete, 559 + .parse = lock__parse, 560 + .scnprintf = lock__scnprintf, 561 + }; 562 + 563 + /* 564 + * Check if the operand has more than one registers like x86 SIB addressing: 565 + * 0x1234(%rax, %rbx, 8) 566 + * 567 + * But it doesn't care segment selectors like %gs:0x5678(%rcx), so just check 568 + * the input string after 'memory_ref_char' if exists. 569 + */ 570 + static bool check_multi_regs(struct arch *arch, const char *op) 571 + { 572 + int count = 0; 573 + 574 + if (arch->objdump.register_char == 0) 575 + return false; 576 + 577 + if (arch->objdump.memory_ref_char) { 578 + op = strchr(op, arch->objdump.memory_ref_char); 579 + if (op == NULL) 580 + return false; 581 + } 582 + 583 + while ((op = strchr(op, arch->objdump.register_char)) != NULL) { 584 + count++; 585 + op++; 586 + } 587 + 588 + return count > 1; 589 + } 590 + 591 + static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) 592 + { 593 + char *s = strchr(ops->raw, ','), *target, *comment, prev; 594 + 595 + if (s == NULL) 596 + return -1; 597 + 598 + *s = '\0'; 599 + 600 + /* 601 + * x86 SIB addressing has something like 0x8(%rax, %rcx, 1) 602 + * then it needs to have the closing parenthesis. 603 + */ 604 + if (strchr(ops->raw, '(')) { 605 + *s = ','; 606 + s = strchr(ops->raw, ')'); 607 + if (s == NULL || s[1] != ',') 608 + return -1; 609 + *++s = '\0'; 610 + } 611 + 612 + ops->source.raw = strdup(ops->raw); 613 + *s = ','; 614 + 615 + if (ops->source.raw == NULL) 616 + return -1; 617 + 618 + ops->source.multi_regs = check_multi_regs(arch, ops->source.raw); 619 + 620 + target = skip_spaces(++s); 621 + comment = strchr(s, arch->objdump.comment_char); 622 + 623 + if (comment != NULL) 624 + s = comment - 1; 625 + else 626 + s = strchr(s, '\0') - 1; 627 + 628 + while (s > target && isspace(s[0])) 629 + --s; 630 + s++; 631 + prev = *s; 632 + *s = '\0'; 633 + 634 + ops->target.raw = strdup(target); 635 + *s = prev; 636 + 637 + if (ops->target.raw == NULL) 638 + goto out_free_source; 639 + 640 + ops->target.multi_regs = check_multi_regs(arch, ops->target.raw); 641 + 642 + if (comment == NULL) 643 + return 0; 644 + 645 + comment = skip_spaces(comment); 646 + comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name); 647 + comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); 648 + 649 + return 0; 650 + 651 + out_free_source: 652 + zfree(&ops->source.raw); 653 + return -1; 654 + } 655 + 656 + static int mov__scnprintf(struct ins *ins, char *bf, size_t size, 657 + struct ins_operands *ops, int max_ins_name) 658 + { 659 + return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name, 660 + ops->source.name ?: ops->source.raw, 661 + ops->target.name ?: ops->target.raw); 662 + } 663 + 664 + static struct ins_ops mov_ops = { 665 + .parse = mov__parse, 666 + .scnprintf = mov__scnprintf, 667 + }; 668 + 669 + static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused) 670 + { 671 + char *target, *comment, *s, prev; 672 + 673 + target = s = ops->raw; 674 + 675 + while (s[0] != '\0' && !isspace(s[0])) 676 + ++s; 677 + prev = *s; 678 + *s = '\0'; 679 + 680 + ops->target.raw = strdup(target); 681 + *s = prev; 682 + 683 + if (ops->target.raw == NULL) 684 + return -1; 685 + 686 + comment = strchr(s, arch->objdump.comment_char); 687 + if (comment == NULL) 688 + return 0; 689 + 690 + comment = skip_spaces(comment); 691 + comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name); 692 + 693 + return 0; 694 + } 695 + 696 + static int dec__scnprintf(struct ins *ins, char *bf, size_t size, 697 + struct ins_operands *ops, int max_ins_name) 698 + { 699 + return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, 700 + ops->target.name ?: ops->target.raw); 701 + } 702 + 703 + static struct ins_ops dec_ops = { 704 + .parse = dec__parse, 705 + .scnprintf = dec__scnprintf, 706 + }; 707 + 708 + static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, 709 + struct ins_operands *ops __maybe_unused, int max_ins_name) 710 + { 711 + return scnprintf(bf, size, "%-*s", max_ins_name, "nop"); 712 + } 713 + 714 + static struct ins_ops nop_ops = { 715 + .scnprintf = nop__scnprintf, 716 + }; 717 + 718 + static struct ins_ops ret_ops = { 719 + .scnprintf = ins__raw_scnprintf, 720 + }; 721 + 722 + bool ins__is_nop(const struct ins *ins) 723 + { 724 + return ins->ops == &nop_ops; 725 + } 726 + 727 + bool ins__is_ret(const struct ins *ins) 728 + { 729 + return ins->ops == &ret_ops; 730 + } 731 + 732 + bool ins__is_lock(const struct ins *ins) 733 + { 734 + return ins->ops == &lock_ops; 735 + } 736 + 737 + static int ins__key_cmp(const void *name, const void *insp) 738 + { 739 + const struct ins *ins = insp; 740 + 741 + return strcmp(name, ins->name); 742 + } 743 + 744 + static int ins__cmp(const void *a, const void *b) 745 + { 746 + const struct ins *ia = a; 747 + const struct ins *ib = b; 748 + 749 + return strcmp(ia->name, ib->name); 750 + } 751 + 752 + static void ins__sort(struct arch *arch) 753 + { 754 + const int nmemb = arch->nr_instructions; 755 + 756 + qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp); 757 + } 758 + 759 + static struct ins_ops *__ins__find(struct arch *arch, const char *name) 760 + { 761 + struct ins *ins; 762 + const int nmemb = arch->nr_instructions; 763 + 764 + if (!arch->sorted_instructions) { 765 + ins__sort(arch); 766 + arch->sorted_instructions = true; 767 + } 768 + 769 + ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); 770 + if (ins) 771 + return ins->ops; 772 + 773 + if (arch->insn_suffix) { 774 + char tmp[32]; 775 + char suffix; 776 + size_t len = strlen(name); 777 + 778 + if (len == 0 || len >= sizeof(tmp)) 779 + return NULL; 780 + 781 + suffix = name[len - 1]; 782 + if (strchr(arch->insn_suffix, suffix) == NULL) 783 + return NULL; 784 + 785 + strcpy(tmp, name); 786 + tmp[len - 1] = '\0'; /* remove the suffix and check again */ 787 + 788 + ins = bsearch(tmp, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp); 789 + } 790 + return ins ? ins->ops : NULL; 791 + } 792 + 793 + struct ins_ops *ins__find(struct arch *arch, const char *name) 794 + { 795 + struct ins_ops *ops = __ins__find(arch, name); 796 + 797 + if (!ops && arch->associate_instruction_ops) 798 + ops = arch->associate_instruction_ops(arch, name); 799 + 800 + return ops; 801 + } 802 + 803 + static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) 804 + { 805 + dl->ins.ops = ins__find(arch, dl->ins.name); 806 + 807 + if (!dl->ins.ops) 808 + return; 809 + 810 + if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0) 811 + dl->ins.ops = NULL; 812 + } 813 + 814 + static int disasm_line__parse(char *line, const char **namep, char **rawp) 815 + { 816 + char tmp, *name = skip_spaces(line); 817 + 818 + if (name[0] == '\0') 819 + return -1; 820 + 821 + *rawp = name + 1; 822 + 823 + while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) 824 + ++*rawp; 825 + 826 + tmp = (*rawp)[0]; 827 + (*rawp)[0] = '\0'; 828 + *namep = strdup(name); 829 + 830 + if (*namep == NULL) 831 + goto out; 832 + 833 + (*rawp)[0] = tmp; 834 + *rawp = strim(*rawp); 835 + 836 + return 0; 837 + 838 + out: 839 + return -1; 840 + } 841 + 842 + static void annotation_line__init(struct annotation_line *al, 843 + struct annotate_args *args, 844 + int nr) 845 + { 846 + al->offset = args->offset; 847 + al->line = strdup(args->line); 848 + al->line_nr = args->line_nr; 849 + al->fileloc = args->fileloc; 850 + al->data_nr = nr; 851 + } 852 + 853 + static void annotation_line__exit(struct annotation_line *al) 854 + { 855 + zfree_srcline(&al->path); 856 + zfree(&al->line); 857 + zfree(&al->cycles); 858 + } 859 + 860 + static size_t disasm_line_size(int nr) 861 + { 862 + struct annotation_line *al; 863 + 864 + return (sizeof(struct disasm_line) + (sizeof(al->data[0]) * nr)); 865 + } 866 + 867 + /* 868 + * Allocating the disasm annotation line data with 869 + * following structure: 870 + * 871 + * ------------------------------------------- 872 + * struct disasm_line | struct annotation_line 873 + * ------------------------------------------- 874 + * 875 + * We have 'struct annotation_line' member as last member 876 + * of 'struct disasm_line' to have an easy access. 877 + */ 878 + struct disasm_line *disasm_line__new(struct annotate_args *args) 879 + { 880 + struct disasm_line *dl = NULL; 881 + int nr = 1; 882 + 883 + if (evsel__is_group_event(args->evsel)) 884 + nr = args->evsel->core.nr_members; 885 + 886 + dl = zalloc(disasm_line_size(nr)); 887 + if (!dl) 888 + return NULL; 889 + 890 + annotation_line__init(&dl->al, args, nr); 891 + if (dl->al.line == NULL) 892 + goto out_delete; 893 + 894 + if (args->offset != -1) { 895 + if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) 896 + goto out_free_line; 897 + 898 + disasm_line__init_ins(dl, args->arch, &args->ms); 899 + } 900 + 901 + return dl; 902 + 903 + out_free_line: 904 + zfree(&dl->al.line); 905 + out_delete: 906 + free(dl); 907 + return NULL; 908 + } 909 + 910 + void disasm_line__free(struct disasm_line *dl) 911 + { 912 + if (dl->ins.ops && dl->ins.ops->free) 913 + dl->ins.ops->free(&dl->ops); 914 + else 915 + ins_ops__delete(&dl->ops); 916 + zfree(&dl->ins.name); 917 + annotation_line__exit(&dl->al); 918 + free(dl); 919 + } 920 + 921 + int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name) 922 + { 923 + if (raw || !dl->ins.ops) 924 + return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw); 925 + 926 + return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name); 927 + } 928 + 929 + /* 930 + * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw) 931 + * which looks like following 932 + * 933 + * 0000000000415500 <_init>: 934 + * 415500: sub $0x8,%rsp 935 + * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8> 936 + * 41550b: test %rax,%rax 937 + * 41550e: je 415515 <_init+0x15> 938 + * 415510: callq 416e70 <__gmon_start__@plt> 939 + * 415515: add $0x8,%rsp 940 + * 415519: retq 941 + * 942 + * it will be parsed and saved into struct disasm_line as 943 + * <offset> <name> <ops.raw> 944 + * 945 + * The offset will be a relative offset from the start of the symbol and -1 946 + * means that it's not a disassembly line so should be treated differently. 947 + * The ops.raw part will be parsed further according to type of the instruction. 948 + */ 949 + static int symbol__parse_objdump_line(struct symbol *sym, 950 + struct annotate_args *args, 951 + char *parsed_line, int *line_nr, char **fileloc) 952 + { 953 + struct map *map = args->ms.map; 954 + struct annotation *notes = symbol__annotation(sym); 955 + struct disasm_line *dl; 956 + char *tmp; 957 + s64 line_ip, offset = -1; 958 + regmatch_t match[2]; 959 + 960 + /* /filename:linenr ? Save line number and ignore. */ 961 + if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) { 962 + *line_nr = atoi(parsed_line + match[1].rm_so); 963 + free(*fileloc); 964 + *fileloc = strdup(parsed_line); 965 + return 0; 966 + } 967 + 968 + /* Process hex address followed by ':'. */ 969 + line_ip = strtoull(parsed_line, &tmp, 16); 970 + if (parsed_line != tmp && tmp[0] == ':' && tmp[1] != '\0') { 971 + u64 start = map__rip_2objdump(map, sym->start), 972 + end = map__rip_2objdump(map, sym->end); 973 + 974 + offset = line_ip - start; 975 + if ((u64)line_ip < start || (u64)line_ip >= end) 976 + offset = -1; 977 + else 978 + parsed_line = tmp + 1; 979 + } 980 + 981 + args->offset = offset; 982 + args->line = parsed_line; 983 + args->line_nr = *line_nr; 984 + args->fileloc = *fileloc; 985 + args->ms.sym = sym; 986 + 987 + dl = disasm_line__new(args); 988 + (*line_nr)++; 989 + 990 + if (dl == NULL) 991 + return -1; 992 + 993 + if (!disasm_line__has_local_offset(dl)) { 994 + dl->ops.target.offset = dl->ops.target.addr - 995 + map__rip_2objdump(map, sym->start); 996 + dl->ops.target.offset_avail = true; 997 + } 998 + 999 + /* kcore has no symbols, so add the call target symbol */ 1000 + if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) { 1001 + struct addr_map_symbol target = { 1002 + .addr = dl->ops.target.addr, 1003 + .ms = { .map = map, }, 1004 + }; 1005 + 1006 + if (!maps__find_ams(args->ms.maps, &target) && 1007 + target.ms.sym->start == target.al_addr) 1008 + dl->ops.target.sym = target.ms.sym; 1009 + } 1010 + 1011 + annotation_line__add(&dl->al, &notes->src->source); 1012 + return 0; 1013 + } 1014 + 1015 + static void delete_last_nop(struct symbol *sym) 1016 + { 1017 + struct annotation *notes = symbol__annotation(sym); 1018 + struct list_head *list = &notes->src->source; 1019 + struct disasm_line *dl; 1020 + 1021 + while (!list_empty(list)) { 1022 + dl = list_entry(list->prev, struct disasm_line, al.node); 1023 + 1024 + if (dl->ins.ops) { 1025 + if (!ins__is_nop(&dl->ins)) 1026 + return; 1027 + } else { 1028 + if (!strstr(dl->al.line, " nop ") && 1029 + !strstr(dl->al.line, " nopl ") && 1030 + !strstr(dl->al.line, " nopw ")) 1031 + return; 1032 + } 1033 + 1034 + list_del_init(&dl->al.node); 1035 + disasm_line__free(dl); 1036 + } 1037 + } 1038 + 1039 + int symbol__strerror_disassemble(struct map_symbol *ms, int errnum, char *buf, size_t buflen) 1040 + { 1041 + struct dso *dso = map__dso(ms->map); 1042 + 1043 + BUG_ON(buflen == 0); 1044 + 1045 + if (errnum >= 0) { 1046 + str_error_r(errnum, buf, buflen); 1047 + return 0; 1048 + } 1049 + 1050 + switch (errnum) { 1051 + case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: { 1052 + char bf[SBUILD_ID_SIZE + 15] = " with build id "; 1053 + char *build_id_msg = NULL; 1054 + 1055 + if (dso->has_build_id) { 1056 + build_id__sprintf(&dso->bid, bf + 15); 1057 + build_id_msg = bf; 1058 + } 1059 + scnprintf(buf, buflen, 1060 + "No vmlinux file%s\nwas found in the path.\n\n" 1061 + "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n" 1062 + "Please use:\n\n" 1063 + " perf buildid-cache -vu vmlinux\n\n" 1064 + "or:\n\n" 1065 + " --vmlinux vmlinux\n", build_id_msg ?: ""); 1066 + } 1067 + break; 1068 + case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF: 1069 + scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation"); 1070 + break; 1071 + case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_REGEXP: 1072 + scnprintf(buf, buflen, "Problems with arch specific instruction name regular expressions."); 1073 + break; 1074 + case SYMBOL_ANNOTATE_ERRNO__ARCH_INIT_CPUID_PARSING: 1075 + scnprintf(buf, buflen, "Problems while parsing the CPUID in the arch specific initialization."); 1076 + break; 1077 + case SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE: 1078 + scnprintf(buf, buflen, "Invalid BPF file: %s.", dso->long_name); 1079 + break; 1080 + case SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF: 1081 + scnprintf(buf, buflen, "The %s BPF file has no BTF section, compile with -g or use pahole -J.", 1082 + dso->long_name); 1083 + break; 1084 + default: 1085 + scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum); 1086 + break; 1087 + } 1088 + 1089 + return 0; 1090 + } 1091 + 1092 + static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size) 1093 + { 1094 + char linkname[PATH_MAX]; 1095 + char *build_id_filename; 1096 + char *build_id_path = NULL; 1097 + char *pos; 1098 + int len; 1099 + 1100 + if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && 1101 + !dso__is_kcore(dso)) 1102 + return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX; 1103 + 1104 + build_id_filename = dso__build_id_filename(dso, NULL, 0, false); 1105 + if (build_id_filename) { 1106 + __symbol__join_symfs(filename, filename_size, build_id_filename); 1107 + free(build_id_filename); 1108 + } else { 1109 + if (dso->has_build_id) 1110 + return ENOMEM; 1111 + goto fallback; 1112 + } 1113 + 1114 + build_id_path = strdup(filename); 1115 + if (!build_id_path) 1116 + return ENOMEM; 1117 + 1118 + /* 1119 + * old style build-id cache has name of XX/XXXXXXX.. while 1120 + * new style has XX/XXXXXXX../{elf,kallsyms,vdso}. 1121 + * extract the build-id part of dirname in the new style only. 1122 + */ 1123 + pos = strrchr(build_id_path, '/'); 1124 + if (pos && strlen(pos) < SBUILD_ID_SIZE - 2) 1125 + dirname(build_id_path); 1126 + 1127 + if (dso__is_kcore(dso)) 1128 + goto fallback; 1129 + 1130 + len = readlink(build_id_path, linkname, sizeof(linkname) - 1); 1131 + if (len < 0) 1132 + goto fallback; 1133 + 1134 + linkname[len] = '\0'; 1135 + if (strstr(linkname, DSO__NAME_KALLSYMS) || 1136 + access(filename, R_OK)) { 1137 + fallback: 1138 + /* 1139 + * If we don't have build-ids or the build-id file isn't in the 1140 + * cache, or is just a kallsyms file, well, lets hope that this 1141 + * DSO is the same as when 'perf record' ran. 1142 + */ 1143 + if (dso->kernel && dso->long_name[0] == '/') 1144 + snprintf(filename, filename_size, "%s", dso->long_name); 1145 + else 1146 + __symbol__join_symfs(filename, filename_size, dso->long_name); 1147 + 1148 + mutex_lock(&dso->lock); 1149 + if (access(filename, R_OK) && errno == ENOENT && dso->nsinfo) { 1150 + char *new_name = dso__filename_with_chroot(dso, filename); 1151 + if (new_name) { 1152 + strlcpy(filename, new_name, filename_size); 1153 + free(new_name); 1154 + } 1155 + } 1156 + mutex_unlock(&dso->lock); 1157 + } 1158 + 1159 + free(build_id_path); 1160 + return 0; 1161 + } 1162 + 1163 + #if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1164 + #define PACKAGE "perf" 1165 + #include <bfd.h> 1166 + #include <dis-asm.h> 1167 + #include <bpf/bpf.h> 1168 + #include <bpf/btf.h> 1169 + #include <bpf/libbpf.h> 1170 + #include <linux/btf.h> 1171 + #include <tools/dis-asm-compat.h> 1172 + 1173 + #include "bpf-event.h" 1174 + #include "bpf-utils.h" 1175 + 1176 + static int symbol__disassemble_bpf(struct symbol *sym, 1177 + struct annotate_args *args) 1178 + { 1179 + struct annotation *notes = symbol__annotation(sym); 1180 + struct bpf_prog_linfo *prog_linfo = NULL; 1181 + struct bpf_prog_info_node *info_node; 1182 + int len = sym->end - sym->start; 1183 + disassembler_ftype disassemble; 1184 + struct map *map = args->ms.map; 1185 + struct perf_bpil *info_linear; 1186 + struct disassemble_info info; 1187 + struct dso *dso = map__dso(map); 1188 + int pc = 0, count, sub_id; 1189 + struct btf *btf = NULL; 1190 + char tpath[PATH_MAX]; 1191 + size_t buf_size; 1192 + int nr_skip = 0; 1193 + char *buf; 1194 + bfd *bfdf; 1195 + int ret; 1196 + FILE *s; 1197 + 1198 + if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO) 1199 + return SYMBOL_ANNOTATE_ERRNO__BPF_INVALID_FILE; 1200 + 1201 + pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__, 1202 + sym->name, sym->start, sym->end - sym->start); 1203 + 1204 + memset(tpath, 0, sizeof(tpath)); 1205 + perf_exe(tpath, sizeof(tpath)); 1206 + 1207 + bfdf = bfd_openr(tpath, NULL); 1208 + if (bfdf == NULL) 1209 + abort(); 1210 + 1211 + if (!bfd_check_format(bfdf, bfd_object)) 1212 + abort(); 1213 + 1214 + s = open_memstream(&buf, &buf_size); 1215 + if (!s) { 1216 + ret = errno; 1217 + goto out; 1218 + } 1219 + init_disassemble_info_compat(&info, s, 1220 + (fprintf_ftype) fprintf, 1221 + fprintf_styled); 1222 + info.arch = bfd_get_arch(bfdf); 1223 + info.mach = bfd_get_mach(bfdf); 1224 + 1225 + info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env, 1226 + dso->bpf_prog.id); 1227 + if (!info_node) { 1228 + ret = SYMBOL_ANNOTATE_ERRNO__BPF_MISSING_BTF; 1229 + goto out; 1230 + } 1231 + info_linear = info_node->info_linear; 1232 + sub_id = dso->bpf_prog.sub_id; 1233 + 1234 + info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns); 1235 + info.buffer_length = info_linear->info.jited_prog_len; 1236 + 1237 + if (info_linear->info.nr_line_info) 1238 + prog_linfo = bpf_prog_linfo__new(&info_linear->info); 1239 + 1240 + if (info_linear->info.btf_id) { 1241 + struct btf_node *node; 1242 + 1243 + node = perf_env__find_btf(dso->bpf_prog.env, 1244 + info_linear->info.btf_id); 1245 + if (node) 1246 + btf = btf__new((__u8 *)(node->data), 1247 + node->data_size); 1248 + } 1249 + 1250 + disassemble_init_for_target(&info); 1251 + 1252 + #ifdef DISASM_FOUR_ARGS_SIGNATURE 1253 + disassemble = disassembler(info.arch, 1254 + bfd_big_endian(bfdf), 1255 + info.mach, 1256 + bfdf); 1257 + #else 1258 + disassemble = disassembler(bfdf); 1259 + #endif 1260 + if (disassemble == NULL) 1261 + abort(); 1262 + 1263 + fflush(s); 1264 + do { 1265 + const struct bpf_line_info *linfo = NULL; 1266 + struct disasm_line *dl; 1267 + size_t prev_buf_size; 1268 + const char *srcline; 1269 + u64 addr; 1270 + 1271 + addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id]; 1272 + count = disassemble(pc, &info); 1273 + 1274 + if (prog_linfo) 1275 + linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo, 1276 + addr, sub_id, 1277 + nr_skip); 1278 + 1279 + if (linfo && btf) { 1280 + srcline = btf__name_by_offset(btf, linfo->line_off); 1281 + nr_skip++; 1282 + } else 1283 + srcline = NULL; 1284 + 1285 + fprintf(s, "\n"); 1286 + prev_buf_size = buf_size; 1287 + fflush(s); 1288 + 1289 + if (!annotate_opts.hide_src_code && srcline) { 1290 + args->offset = -1; 1291 + args->line = strdup(srcline); 1292 + args->line_nr = 0; 1293 + args->fileloc = NULL; 1294 + args->ms.sym = sym; 1295 + dl = disasm_line__new(args); 1296 + if (dl) { 1297 + annotation_line__add(&dl->al, 1298 + &notes->src->source); 1299 + } 1300 + } 1301 + 1302 + args->offset = pc; 1303 + args->line = buf + prev_buf_size; 1304 + args->line_nr = 0; 1305 + args->fileloc = NULL; 1306 + args->ms.sym = sym; 1307 + dl = disasm_line__new(args); 1308 + if (dl) 1309 + annotation_line__add(&dl->al, &notes->src->source); 1310 + 1311 + pc += count; 1312 + } while (count > 0 && pc < len); 1313 + 1314 + ret = 0; 1315 + out: 1316 + free(prog_linfo); 1317 + btf__free(btf); 1318 + fclose(s); 1319 + bfd_close(bfdf); 1320 + return ret; 1321 + } 1322 + #else // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1323 + static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused, 1324 + struct annotate_args *args __maybe_unused) 1325 + { 1326 + return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF; 1327 + } 1328 + #endif // defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT) 1329 + 1330 + static int 1331 + symbol__disassemble_bpf_image(struct symbol *sym, 1332 + struct annotate_args *args) 1333 + { 1334 + struct annotation *notes = symbol__annotation(sym); 1335 + struct disasm_line *dl; 1336 + 1337 + args->offset = -1; 1338 + args->line = strdup("to be implemented"); 1339 + args->line_nr = 0; 1340 + args->fileloc = NULL; 1341 + dl = disasm_line__new(args); 1342 + if (dl) 1343 + annotation_line__add(&dl->al, &notes->src->source); 1344 + 1345 + zfree(&args->line); 1346 + return 0; 1347 + } 1348 + 1349 + /* 1350 + * Possibly create a new version of line with tabs expanded. Returns the 1351 + * existing or new line, storage is updated if a new line is allocated. If 1352 + * allocation fails then NULL is returned. 1353 + */ 1354 + static char *expand_tabs(char *line, char **storage, size_t *storage_len) 1355 + { 1356 + size_t i, src, dst, len, new_storage_len, num_tabs; 1357 + char *new_line; 1358 + size_t line_len = strlen(line); 1359 + 1360 + for (num_tabs = 0, i = 0; i < line_len; i++) 1361 + if (line[i] == '\t') 1362 + num_tabs++; 1363 + 1364 + if (num_tabs == 0) 1365 + return line; 1366 + 1367 + /* 1368 + * Space for the line and '\0', less the leading and trailing 1369 + * spaces. Each tab may introduce 7 additional spaces. 1370 + */ 1371 + new_storage_len = line_len + 1 + (num_tabs * 7); 1372 + 1373 + new_line = malloc(new_storage_len); 1374 + if (new_line == NULL) { 1375 + pr_err("Failure allocating memory for tab expansion\n"); 1376 + return NULL; 1377 + } 1378 + 1379 + /* 1380 + * Copy regions starting at src and expand tabs. If there are two 1381 + * adjacent tabs then 'src == i', the memcpy is of size 0 and the spaces 1382 + * are inserted. 1383 + */ 1384 + for (i = 0, src = 0, dst = 0; i < line_len && num_tabs; i++) { 1385 + if (line[i] == '\t') { 1386 + len = i - src; 1387 + memcpy(&new_line[dst], &line[src], len); 1388 + dst += len; 1389 + new_line[dst++] = ' '; 1390 + while (dst % 8 != 0) 1391 + new_line[dst++] = ' '; 1392 + src = i + 1; 1393 + num_tabs--; 1394 + } 1395 + } 1396 + 1397 + /* Expand the last region. */ 1398 + len = line_len - src; 1399 + memcpy(&new_line[dst], &line[src], len); 1400 + dst += len; 1401 + new_line[dst] = '\0'; 1402 + 1403 + free(*storage); 1404 + *storage = new_line; 1405 + *storage_len = new_storage_len; 1406 + return new_line; 1407 + } 1408 + 1409 + int symbol__disassemble(struct symbol *sym, struct annotate_args *args) 1410 + { 1411 + struct annotation_options *opts = &annotate_opts; 1412 + struct map *map = args->ms.map; 1413 + struct dso *dso = map__dso(map); 1414 + char *command; 1415 + FILE *file; 1416 + char symfs_filename[PATH_MAX]; 1417 + struct kcore_extract kce; 1418 + bool delete_extract = false; 1419 + bool decomp = false; 1420 + int lineno = 0; 1421 + char *fileloc = NULL; 1422 + int nline; 1423 + char *line; 1424 + size_t line_len; 1425 + const char *objdump_argv[] = { 1426 + "/bin/sh", 1427 + "-c", 1428 + NULL, /* Will be the objdump command to run. */ 1429 + "--", 1430 + NULL, /* Will be the symfs path. */ 1431 + NULL, 1432 + }; 1433 + struct child_process objdump_process; 1434 + int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); 1435 + 1436 + if (err) 1437 + return err; 1438 + 1439 + pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__, 1440 + symfs_filename, sym->name, map__unmap_ip(map, sym->start), 1441 + map__unmap_ip(map, sym->end)); 1442 + 1443 + pr_debug("annotating [%p] %30s : [%p] %30s\n", 1444 + dso, dso->long_name, sym, sym->name); 1445 + 1446 + if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) { 1447 + return symbol__disassemble_bpf(sym, args); 1448 + } else if (dso->binary_type == DSO_BINARY_TYPE__BPF_IMAGE) { 1449 + return symbol__disassemble_bpf_image(sym, args); 1450 + } else if (dso__is_kcore(dso)) { 1451 + kce.kcore_filename = symfs_filename; 1452 + kce.addr = map__rip_2objdump(map, sym->start); 1453 + kce.offs = sym->start; 1454 + kce.len = sym->end - sym->start; 1455 + if (!kcore_extract__create(&kce)) { 1456 + delete_extract = true; 1457 + strlcpy(symfs_filename, kce.extract_filename, 1458 + sizeof(symfs_filename)); 1459 + } 1460 + } else if (dso__needs_decompress(dso)) { 1461 + char tmp[KMOD_DECOMP_LEN]; 1462 + 1463 + if (dso__decompress_kmodule_path(dso, symfs_filename, 1464 + tmp, sizeof(tmp)) < 0) 1465 + return -1; 1466 + 1467 + decomp = true; 1468 + strcpy(symfs_filename, tmp); 1469 + } 1470 + 1471 + err = asprintf(&command, 1472 + "%s %s%s --start-address=0x%016" PRIx64 1473 + " --stop-address=0x%016" PRIx64 1474 + " %s -d %s %s %s %c%s%c %s%s -C \"$1\"", 1475 + opts->objdump_path ?: "objdump", 1476 + opts->disassembler_style ? "-M " : "", 1477 + opts->disassembler_style ?: "", 1478 + map__rip_2objdump(map, sym->start), 1479 + map__rip_2objdump(map, sym->end), 1480 + opts->show_linenr ? "-l" : "", 1481 + opts->show_asm_raw ? "" : "--no-show-raw-insn", 1482 + opts->annotate_src ? "-S" : "", 1483 + opts->prefix ? "--prefix " : "", 1484 + opts->prefix ? '"' : ' ', 1485 + opts->prefix ?: "", 1486 + opts->prefix ? '"' : ' ', 1487 + opts->prefix_strip ? "--prefix-strip=" : "", 1488 + opts->prefix_strip ?: ""); 1489 + 1490 + if (err < 0) { 1491 + pr_err("Failure allocating memory for the command to run\n"); 1492 + goto out_remove_tmp; 1493 + } 1494 + 1495 + pr_debug("Executing: %s\n", command); 1496 + 1497 + objdump_argv[2] = command; 1498 + objdump_argv[4] = symfs_filename; 1499 + 1500 + /* Create a pipe to read from for stdout */ 1501 + memset(&objdump_process, 0, sizeof(objdump_process)); 1502 + objdump_process.argv = objdump_argv; 1503 + objdump_process.out = -1; 1504 + objdump_process.err = -1; 1505 + objdump_process.no_stderr = 1; 1506 + if (start_command(&objdump_process)) { 1507 + pr_err("Failure starting to run %s\n", command); 1508 + err = -1; 1509 + goto out_free_command; 1510 + } 1511 + 1512 + file = fdopen(objdump_process.out, "r"); 1513 + if (!file) { 1514 + pr_err("Failure creating FILE stream for %s\n", command); 1515 + /* 1516 + * If we were using debug info should retry with 1517 + * original binary. 1518 + */ 1519 + err = -1; 1520 + goto out_close_stdout; 1521 + } 1522 + 1523 + /* Storage for getline. */ 1524 + line = NULL; 1525 + line_len = 0; 1526 + 1527 + nline = 0; 1528 + while (!feof(file)) { 1529 + const char *match; 1530 + char *expanded_line; 1531 + 1532 + if (getline(&line, &line_len, file) < 0 || !line) 1533 + break; 1534 + 1535 + /* Skip lines containing "filename:" */ 1536 + match = strstr(line, symfs_filename); 1537 + if (match && match[strlen(symfs_filename)] == ':') 1538 + continue; 1539 + 1540 + expanded_line = strim(line); 1541 + expanded_line = expand_tabs(expanded_line, &line, &line_len); 1542 + if (!expanded_line) 1543 + break; 1544 + 1545 + /* 1546 + * The source code line number (lineno) needs to be kept in 1547 + * across calls to symbol__parse_objdump_line(), so that it 1548 + * can associate it with the instructions till the next one. 1549 + * See disasm_line__new() and struct disasm_line::line_nr. 1550 + */ 1551 + if (symbol__parse_objdump_line(sym, args, expanded_line, 1552 + &lineno, &fileloc) < 0) 1553 + break; 1554 + nline++; 1555 + } 1556 + free(line); 1557 + free(fileloc); 1558 + 1559 + err = finish_command(&objdump_process); 1560 + if (err) 1561 + pr_err("Error running %s\n", command); 1562 + 1563 + if (nline == 0) { 1564 + err = -1; 1565 + pr_err("No output from %s\n", command); 1566 + } 1567 + 1568 + /* 1569 + * kallsyms does not have symbol sizes so there may a nop at the end. 1570 + * Remove it. 1571 + */ 1572 + if (dso__is_kcore(dso)) 1573 + delete_last_nop(sym); 1574 + 1575 + fclose(file); 1576 + 1577 + out_close_stdout: 1578 + close(objdump_process.out); 1579 + 1580 + out_free_command: 1581 + free(command); 1582 + 1583 + out_remove_tmp: 1584 + if (decomp) 1585 + unlink(symfs_filename); 1586 + 1587 + if (delete_extract) 1588 + kcore_extract__delete(&kce); 1589 + 1590 + return err; 1591 + }
+112
tools/perf/util/disasm.h
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + #ifndef __PERF_UTIL_DISASM_H 3 + #define __PERF_UTIL_DISASM_H 4 + 5 + #include "map_symbol.h" 6 + 7 + struct annotation_options; 8 + struct disasm_line; 9 + struct ins; 10 + struct evsel; 11 + struct symbol; 12 + 13 + struct arch { 14 + const char *name; 15 + struct ins *instructions; 16 + size_t nr_instructions; 17 + size_t nr_instructions_allocated; 18 + struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name); 19 + bool sorted_instructions; 20 + bool initialized; 21 + const char *insn_suffix; 22 + void *priv; 23 + unsigned int model; 24 + unsigned int family; 25 + int (*init)(struct arch *arch, char *cpuid); 26 + bool (*ins_is_fused)(struct arch *arch, const char *ins1, 27 + const char *ins2); 28 + struct { 29 + char comment_char; 30 + char skip_functions_char; 31 + char register_char; 32 + char memory_ref_char; 33 + char imm_char; 34 + } objdump; 35 + }; 36 + 37 + struct ins { 38 + const char *name; 39 + struct ins_ops *ops; 40 + }; 41 + 42 + struct ins_operands { 43 + char *raw; 44 + struct { 45 + char *raw; 46 + char *name; 47 + struct symbol *sym; 48 + u64 addr; 49 + s64 offset; 50 + bool offset_avail; 51 + bool outside; 52 + bool multi_regs; 53 + } target; 54 + union { 55 + struct { 56 + char *raw; 57 + char *name; 58 + u64 addr; 59 + bool multi_regs; 60 + } source; 61 + struct { 62 + struct ins ins; 63 + struct ins_operands *ops; 64 + } locked; 65 + struct { 66 + char *raw_comment; 67 + char *raw_func_start; 68 + } jump; 69 + }; 70 + }; 71 + 72 + struct ins_ops { 73 + void (*free)(struct ins_operands *ops); 74 + int (*parse)(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms); 75 + int (*scnprintf)(struct ins *ins, char *bf, size_t size, 76 + struct ins_operands *ops, int max_ins_name); 77 + }; 78 + 79 + struct annotate_args { 80 + struct arch *arch; 81 + struct map_symbol ms; 82 + struct evsel *evsel; 83 + struct annotation_options *options; 84 + s64 offset; 85 + char *line; 86 + int line_nr; 87 + char *fileloc; 88 + }; 89 + 90 + struct arch *arch__find(const char *name); 91 + bool arch__is(struct arch *arch, const char *name); 92 + 93 + struct ins_ops *ins__find(struct arch *arch, const char *name); 94 + int ins__scnprintf(struct ins *ins, char *bf, size_t size, 95 + struct ins_operands *ops, int max_ins_name); 96 + 97 + bool ins__is_call(const struct ins *ins); 98 + bool ins__is_jump(const struct ins *ins); 99 + bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2); 100 + bool ins__is_nop(const struct ins *ins); 101 + bool ins__is_ret(const struct ins *ins); 102 + bool ins__is_lock(const struct ins *ins); 103 + 104 + struct disasm_line *disasm_line__new(struct annotate_args *args); 105 + void disasm_line__free(struct disasm_line *dl); 106 + 107 + int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, 108 + bool raw, int max_ins_name); 109 + 110 + int symbol__disassemble(struct symbol *sym, struct annotate_args *args); 111 + 112 + #endif /* __PERF_UTIL_DISASM_H */