From dab8c32ece27c7d8cf01e9b68041edaf5ddd8adf Mon Sep 17 00:00:00 2001 From: Athira Rajeev Date: Tue, 4 Mar 2025 21:11:13 +0530 Subject: [PATCH] perf annotate: Add annotation_options.disassembler_used When doing "perf annotate", perf tool provides option to use specific disassembler like llvm/objdump/capstone. The order picked is to use llvm first and if that fails fallback to objdump ie to use PERF_DISASM_LLVM, PERF_DISASM_CAPSTONE and PERF_DISASM_OBJDUMP In powerpc, when using "data type" sort keys, first preferred approach is to read the raw instruction from the DSO. In objdump is specified in "--objdump" option, it picks the symbol disassemble using objdump. Currently disasm_line__parse_powerpc() function uses length of the "line" to determine if objdump is used. But there are few cases, where if objdump doesn't recognise the instruction, the disassembled string will be empty. Example: 134cdc: c4 05 82 41 beq 1352a0 134ce0: ac 00 8e 40 bne cr3,134d8c 134ce4: 0f 00 10 04 pld r9,1028308 ====>134ce8: d4 b0 20 e5 134cec: 16 00 40 39 li r10,22 134cf0: 48 01 21 ea ld r17,328(r1) So depending on length of line will give bad results. Add a new filed to annotation options structure, "struct annotation_options" to save the disassembler used. Use this info to determine if disassembly is done while parsing the disasm line. Reported-by: Tejas Manhas Signed-off-by: Athira Rajeev Tested-By: Venkat Rao Bagalkote Link: https://lore.kernel.org/r/20250304154114.62093-1-atrajeev@linux.ibm.com Signed-off-by: Namhyung Kim --- tools/perf/util/annotate.h | 1 + tools/perf/util/disasm.c | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 98db1b88daf4..30a344afd91a 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -58,6 +58,7 @@ struct annotation_options { full_addr; u8 offset_level; u8 disassemblers[MAX_DISASSEMBLERS]; + u8 disassembler_used; int min_pcnt; int max_lines; int context; diff --git a/tools/perf/util/disasm.c b/tools/perf/util/disasm.c index 50c5c206b70e..a53e8c4e5bca 100644 --- a/tools/perf/util/disasm.c +++ b/tools/perf/util/disasm.c @@ -48,7 +48,7 @@ static int call__scnprintf(struct ins *ins, char *bf, size_t size, static void ins__sort(struct arch *arch); static int disasm_line__parse(char *line, const char **namep, char **rawp); -static int disasm_line__parse_powerpc(struct disasm_line *dl); +static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annotate_args *args); static char *expand_tabs(char *line, char **storage, size_t *storage_len); static __attribute__((constructor)) void symbol__init_regexpr(void) @@ -968,24 +968,24 @@ static int disasm_line__parse(char *line, const char **namep, char **rawp) #define PPC_OP(op) (((op) >> 26) & 0x3F) #define RAW_BYTES 11 -static int disasm_line__parse_powerpc(struct disasm_line *dl) +static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annotate_args *args) { char *line = dl->al.line; const char **namep = &dl->ins.name; char **rawp = &dl->ops.raw; char *tmp_raw_insn, *name_raw_insn = skip_spaces(line); char *name = skip_spaces(name_raw_insn + RAW_BYTES); - int objdump = 0; + int disasm = 0; - if (strlen(line) > RAW_BYTES) - objdump = 1; + if (args->options->disassembler_used) + disasm = 1; if (name_raw_insn[0] == '\0') return -1; - if (objdump) { + if (disasm) disasm_line__parse(name, namep, rawp); - } else + else *namep = ""; tmp_raw_insn = strndup(name_raw_insn, 11); @@ -995,7 +995,7 @@ static int disasm_line__parse_powerpc(struct disasm_line *dl) remove_spaces(tmp_raw_insn); sscanf(tmp_raw_insn, "%x", &dl->raw.raw_insn); - if (objdump) + if (disasm) dl->raw.raw_insn = be32_to_cpu(dl->raw.raw_insn); return 0; @@ -1054,7 +1054,7 @@ struct disasm_line *disasm_line__new(struct annotate_args *args) if (args->offset != -1) { if (arch__is(args->arch, "powerpc")) { - if (disasm_line__parse_powerpc(dl) < 0) + if (disasm_line__parse_powerpc(dl, args) < 0) goto out_free_line; } else if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) goto out_free_line; @@ -2289,16 +2289,20 @@ int symbol__disassemble(struct symbol *sym, struct annotate_args *args) switch (dis) { case PERF_DISASM_LLVM: + args->options->disassembler_used = PERF_DISASM_LLVM; err = symbol__disassemble_llvm(symfs_filename, sym, args); break; case PERF_DISASM_CAPSTONE: + args->options->disassembler_used = PERF_DISASM_CAPSTONE; err = symbol__disassemble_capstone(symfs_filename, sym, args); break; case PERF_DISASM_OBJDUMP: + args->options->disassembler_used = PERF_DISASM_OBJDUMP; err = symbol__disassemble_objdump(symfs_filename, sym, args); break; case PERF_DISASM_UNKNOWN: /* End of disassemblers. */ default: + args->options->disassembler_used = PERF_DISASM_UNKNOWN; goto out_remove_tmp; } if (err == 0)