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

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 <getcwd+0x6e0>
134ce0: ac 00 8e 40 bne cr3,134d8c <getcwd+0x1cc>
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 <Tejas.Manhas1@ibm.com>
Signed-off-by: Athira Rajeev <atrajeev@linux.ibm.com>
Tested-By: Venkat Rao Bagalkote <venkat88@linux.ibm.com>
Link: https://lore.kernel.org/r/20250304154114.62093-1-atrajeev@linux.ibm.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Athira Rajeev and committed by
Namhyung Kim
dab8c32e b0920abe

+14 -9
+1
tools/perf/util/annotate.h
··· 58 58 full_addr; 59 59 u8 offset_level; 60 60 u8 disassemblers[MAX_DISASSEMBLERS]; 61 + u8 disassembler_used; 61 62 int min_pcnt; 62 63 int max_lines; 63 64 int context;
+13 -9
tools/perf/util/disasm.c
··· 48 48 49 49 static void ins__sort(struct arch *arch); 50 50 static int disasm_line__parse(char *line, const char **namep, char **rawp); 51 - static int disasm_line__parse_powerpc(struct disasm_line *dl); 51 + static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annotate_args *args); 52 52 static char *expand_tabs(char *line, char **storage, size_t *storage_len); 53 53 54 54 static __attribute__((constructor)) void symbol__init_regexpr(void) ··· 968 968 #define PPC_OP(op) (((op) >> 26) & 0x3F) 969 969 #define RAW_BYTES 11 970 970 971 - static int disasm_line__parse_powerpc(struct disasm_line *dl) 971 + static int disasm_line__parse_powerpc(struct disasm_line *dl, struct annotate_args *args) 972 972 { 973 973 char *line = dl->al.line; 974 974 const char **namep = &dl->ins.name; 975 975 char **rawp = &dl->ops.raw; 976 976 char *tmp_raw_insn, *name_raw_insn = skip_spaces(line); 977 977 char *name = skip_spaces(name_raw_insn + RAW_BYTES); 978 - int objdump = 0; 978 + int disasm = 0; 979 979 980 - if (strlen(line) > RAW_BYTES) 981 - objdump = 1; 980 + if (args->options->disassembler_used) 981 + disasm = 1; 982 982 983 983 if (name_raw_insn[0] == '\0') 984 984 return -1; 985 985 986 - if (objdump) { 986 + if (disasm) 987 987 disasm_line__parse(name, namep, rawp); 988 - } else 988 + else 989 989 *namep = ""; 990 990 991 991 tmp_raw_insn = strndup(name_raw_insn, 11); ··· 995 995 remove_spaces(tmp_raw_insn); 996 996 997 997 sscanf(tmp_raw_insn, "%x", &dl->raw.raw_insn); 998 - if (objdump) 998 + if (disasm) 999 999 dl->raw.raw_insn = be32_to_cpu(dl->raw.raw_insn); 1000 1000 1001 1001 return 0; ··· 1054 1054 1055 1055 if (args->offset != -1) { 1056 1056 if (arch__is(args->arch, "powerpc")) { 1057 - if (disasm_line__parse_powerpc(dl) < 0) 1057 + if (disasm_line__parse_powerpc(dl, args) < 0) 1058 1058 goto out_free_line; 1059 1059 } else if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0) 1060 1060 goto out_free_line; ··· 2289 2289 2290 2290 switch (dis) { 2291 2291 case PERF_DISASM_LLVM: 2292 + args->options->disassembler_used = PERF_DISASM_LLVM; 2292 2293 err = symbol__disassemble_llvm(symfs_filename, sym, args); 2293 2294 break; 2294 2295 case PERF_DISASM_CAPSTONE: 2296 + args->options->disassembler_used = PERF_DISASM_CAPSTONE; 2295 2297 err = symbol__disassemble_capstone(symfs_filename, sym, args); 2296 2298 break; 2297 2299 case PERF_DISASM_OBJDUMP: 2300 + args->options->disassembler_used = PERF_DISASM_OBJDUMP; 2298 2301 err = symbol__disassemble_objdump(symfs_filename, sym, args); 2299 2302 break; 2300 2303 case PERF_DISASM_UNKNOWN: /* End of disassemblers. */ 2301 2304 default: 2305 + args->options->disassembler_used = PERF_DISASM_UNKNOWN; 2302 2306 goto out_remove_tmp; 2303 2307 } 2304 2308 if (err == 0)