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

Configure Feed

Select the types of activity you want to include in your feed.

perf annotate: Use an array for the disassembler preference

Prior to this change a string was used which could cause issues with
an unrecognized disassembler in symbol__disassembler. Change to
initializing an array of perf_disassembler enum values. If a value
already exists then adding it a second time is ignored to avoid array
out of bounds problems present in the previous code, it also allows a
statically sized array and removes memory allocation needs. Errors in
the disassembler string are reported when the config is parsed during
perf annotate or perf top start up. If the array is uninitialized
after processing the config file the default llvm, capstone then
objdump values are added but without a need to parse a string.

Fixes: a6e8a58de629 ("perf disasm: Allow configuring what disassemblers to use")
Closes: https://lore.kernel.org/lkml/CAP-5=fUdfCyxmEiTpzS2uumUp3-SyQOseX2xZo81-dQtWXj6vA@mail.gmail.com/
Signed-off-by: Ian Rogers <irogers@google.com>
Tested-by: Namhyung Kim <namhyung@kernel.org>
Link: https://lore.kernel.org/r/20250124043856.1177264-1-irogers@google.com
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

authored by

Ian Rogers and committed by
Namhyung Kim
bde4ccfd 013eb043

+96 -78
+71 -5
tools/perf/util/annotate.c
··· 2100 2100 return 0; 2101 2101 } 2102 2102 2103 + const char * const perf_disassembler__strs[] = { 2104 + [PERF_DISASM_UNKNOWN] = "unknown", 2105 + [PERF_DISASM_LLVM] = "llvm", 2106 + [PERF_DISASM_CAPSTONE] = "capstone", 2107 + [PERF_DISASM_OBJDUMP] = "objdump", 2108 + }; 2109 + 2110 + 2111 + static void annotation_options__add_disassembler(struct annotation_options *options, 2112 + enum perf_disassembler dis) 2113 + { 2114 + for (u8 i = 0; i < ARRAY_SIZE(options->disassemblers); i++) { 2115 + if (options->disassemblers[i] == dis) { 2116 + /* Disassembler is already present then don't add again. */ 2117 + return; 2118 + } 2119 + if (options->disassemblers[i] == PERF_DISASM_UNKNOWN) { 2120 + /* Found a free slot. */ 2121 + options->disassemblers[i] = dis; 2122 + return; 2123 + } 2124 + } 2125 + pr_err("Failed to add disassembler %d\n", dis); 2126 + } 2127 + 2128 + static int annotation_options__add_disassemblers_str(struct annotation_options *options, 2129 + const char *str) 2130 + { 2131 + while (str && *str != '\0') { 2132 + const char *comma = strchr(str, ','); 2133 + int len = comma ? comma - str : (int)strlen(str); 2134 + bool match = false; 2135 + 2136 + for (u8 i = 0; i < ARRAY_SIZE(perf_disassembler__strs); i++) { 2137 + const char *dis_str = perf_disassembler__strs[i]; 2138 + 2139 + if (len == (int)strlen(dis_str) && !strncmp(str, dis_str, len)) { 2140 + annotation_options__add_disassembler(options, i); 2141 + match = true; 2142 + break; 2143 + } 2144 + } 2145 + if (!match) { 2146 + pr_err("Invalid disassembler '%.*s'\n", len, str); 2147 + return -1; 2148 + } 2149 + str = comma ? comma + 1 : NULL; 2150 + } 2151 + return 0; 2152 + } 2153 + 2103 2154 static int annotation__config(const char *var, const char *value, void *data) 2104 2155 { 2105 2156 struct annotation_options *opt = data; ··· 2166 2115 else if (opt->offset_level < ANNOTATION__MIN_OFFSET_LEVEL) 2167 2116 opt->offset_level = ANNOTATION__MIN_OFFSET_LEVEL; 2168 2117 } else if (!strcmp(var, "annotate.disassemblers")) { 2169 - opt->disassemblers_str = strdup(value); 2170 - if (!opt->disassemblers_str) { 2171 - pr_err("Not enough memory for annotate.disassemblers\n"); 2172 - return -1; 2173 - } 2118 + int err = annotation_options__add_disassemblers_str(opt, value); 2119 + 2120 + if (err) 2121 + return err; 2174 2122 } else if (!strcmp(var, "annotate.hide_src_code")) { 2175 2123 opt->hide_src_code = perf_config_bool("hide_src_code", value); 2176 2124 } else if (!strcmp(var, "annotate.jump_arrows")) { ··· 2235 2185 zfree(&annotate_opts.objdump_path); 2236 2186 } 2237 2187 2188 + static void annotation_options__default_init_disassemblers(struct annotation_options *options) 2189 + { 2190 + if (options->disassemblers[0] != PERF_DISASM_UNKNOWN) { 2191 + /* Already initialized. */ 2192 + return; 2193 + } 2194 + #ifdef HAVE_LIBLLVM_SUPPORT 2195 + annotation_options__add_disassembler(options, PERF_DISASM_LLVM); 2196 + #endif 2197 + #ifdef HAVE_LIBCAPSTONE_SUPPORT 2198 + annotation_options__add_disassembler(options, PERF_DISASM_CAPSTONE); 2199 + #endif 2200 + annotation_options__add_disassembler(options, PERF_DISASM_OBJDUMP); 2201 + } 2202 + 2238 2203 void annotation_config__init(void) 2239 2204 { 2240 2205 perf_config(annotation__config, &annotate_opts); 2206 + annotation_options__default_init_disassemblers(&annotate_opts); 2241 2207 } 2242 2208 2243 2209 static unsigned int parse_percent_type(char *str1, char *str2)
+10 -5
tools/perf/util/annotate.h
··· 34 34 #define ANNOTATION__BR_CNTR_WIDTH 30 35 35 #define ANNOTATION_DUMMY_LEN 256 36 36 37 - // llvm, capstone, objdump 38 - #define MAX_DISASSEMBLERS 3 37 + enum perf_disassembler { 38 + PERF_DISASM_UNKNOWN = 0, 39 + PERF_DISASM_LLVM, 40 + PERF_DISASM_CAPSTONE, 41 + PERF_DISASM_OBJDUMP, 42 + }; 43 + #define MAX_DISASSEMBLERS (PERF_DISASM_OBJDUMP + 1) 39 44 40 45 struct annotation_options { 41 46 bool hide_src_code, ··· 57 52 annotate_src, 58 53 full_addr; 59 54 u8 offset_level; 60 - u8 nr_disassemblers; 55 + u8 disassemblers[MAX_DISASSEMBLERS]; 61 56 int min_pcnt; 62 57 int max_lines; 63 58 int context; 64 59 char *objdump_path; 65 60 char *disassembler_style; 66 - const char *disassemblers_str; 67 - const char *disassemblers[MAX_DISASSEMBLERS]; 68 61 const char *prefix; 69 62 const char *prefix_strip; 70 63 unsigned int percent_type; ··· 136 133 /* This needs to be at the end. */ 137 134 struct annotation_line al; 138 135 }; 136 + 137 + extern const char * const perf_disassembler__strs[]; 139 138 140 139 void annotation_line__add(struct annotation_line *al, struct list_head *head); 141 140
+15 -68
tools/perf/util/disasm.c
··· 2216 2216 return err; 2217 2217 } 2218 2218 2219 - static int annotation_options__init_disassemblers(struct annotation_options *options) 2220 - { 2221 - char *disassembler; 2222 - 2223 - if (options->disassemblers_str == NULL) { 2224 - const char *default_disassemblers_str = 2225 - #ifdef HAVE_LIBLLVM_SUPPORT 2226 - "llvm," 2227 - #endif 2228 - #ifdef HAVE_LIBCAPSTONE_SUPPORT 2229 - "capstone," 2230 - #endif 2231 - "objdump"; 2232 - 2233 - options->disassemblers_str = strdup(default_disassemblers_str); 2234 - if (!options->disassemblers_str) 2235 - goto out_enomem; 2236 - } 2237 - 2238 - disassembler = strdup(options->disassemblers_str); 2239 - if (disassembler == NULL) 2240 - goto out_enomem; 2241 - 2242 - while (1) { 2243 - char *comma = strchr(disassembler, ','); 2244 - 2245 - if (comma != NULL) 2246 - *comma = '\0'; 2247 - 2248 - options->disassemblers[options->nr_disassemblers++] = strim(disassembler); 2249 - 2250 - if (comma == NULL) 2251 - break; 2252 - 2253 - disassembler = comma + 1; 2254 - 2255 - if (options->nr_disassemblers >= MAX_DISASSEMBLERS) { 2256 - pr_debug("annotate.disassemblers can have at most %d entries, ignoring \"%s\"\n", 2257 - MAX_DISASSEMBLERS, disassembler); 2258 - break; 2259 - } 2260 - } 2261 - 2262 - return 0; 2263 - 2264 - out_enomem: 2265 - pr_err("Not enough memory for annotate.disassemblers\n"); 2266 - return -1; 2267 - } 2268 - 2269 2219 int symbol__disassemble(struct symbol *sym, struct annotate_args *args) 2270 2220 { 2271 2221 struct annotation_options *options = args->options; ··· 2224 2274 char symfs_filename[PATH_MAX]; 2225 2275 bool delete_extract = false; 2226 2276 struct kcore_extract kce; 2227 - const char *disassembler; 2228 2277 bool decomp = false; 2229 2278 int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename)); 2230 2279 ··· 2283 2334 } 2284 2335 } 2285 2336 2286 - err = annotation_options__init_disassemblers(options); 2287 - if (err) 2288 - goto out_remove_tmp; 2289 - 2290 2337 err = -1; 2338 + for (u8 i = 0; i < ARRAY_SIZE(options->disassemblers) && err != 0; i++) { 2339 + enum perf_disassembler dis = options->disassemblers[i]; 2291 2340 2292 - for (int i = 0; i < options->nr_disassemblers && err != 0; ++i) { 2293 - disassembler = options->disassemblers[i]; 2294 - 2295 - if (!strcmp(disassembler, "llvm")) 2341 + switch (dis) { 2342 + case PERF_DISASM_LLVM: 2296 2343 err = symbol__disassemble_llvm(symfs_filename, sym, args); 2297 - else if (!strcmp(disassembler, "capstone")) 2344 + break; 2345 + case PERF_DISASM_CAPSTONE: 2298 2346 err = symbol__disassemble_capstone(symfs_filename, sym, args); 2299 - else if (!strcmp(disassembler, "objdump")) 2347 + break; 2348 + case PERF_DISASM_OBJDUMP: 2300 2349 err = symbol__disassemble_objdump(symfs_filename, sym, args); 2301 - else 2302 - pr_debug("Unknown disassembler %s, skipping...\n", disassembler); 2303 - } 2304 - 2305 - if (err == 0) { 2306 - pr_debug("Disassembled with %s\nannotate.disassemblers=%s\n", 2307 - disassembler, options->disassemblers_str); 2350 + break; 2351 + case PERF_DISASM_UNKNOWN: /* End of disassemblers. */ 2352 + default: 2353 + goto out_remove_tmp; 2354 + } 2355 + if (err == 0) 2356 + pr_debug("Disassembled with %s\n", perf_disassembler__strs[dis]); 2308 2357 } 2309 2358 out_remove_tmp: 2310 2359 if (decomp)