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.

Merge tag 'perf-tools-fixes-for-v6.14-2025-01-30' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools

Pull perf tools fixes from Namhyung Kim:
"An early round of random fixes in perf tools for this cycle.

perf trace:
- Fix loading of BPF program on certain clang versions
- Fix out-of-bound access in syscalls with 6 arguments
- Skip syscall enum test if landlock syscall is not available

perf annotate:
- Fix segfaults due to invalid access in disasm arrays

perf stat:
- Fix error handling in topology parsing"

* tag 'perf-tools-fixes-for-v6.14-2025-01-30' of git://git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools:
perf cpumap: Fix die and cluster IDs
perf test: Skip syscall enum test if no landlock syscall
perf trace: Fix runtime error of index out of bounds
perf annotate: Use an array for the disassembler preference
perf trace: Fix BPF loading failure (-E2BIG)

+113 -90
+5 -1
tools/perf/builtin-trace.c
··· 2107 2107 return PTR_ERR(sc->tp_format); 2108 2108 } 2109 2109 2110 + /* 2111 + * The tracepoint format contains __syscall_nr field, so it's one more 2112 + * than the actual number of syscall arguments. 2113 + */ 2110 2114 if (syscall__alloc_arg_fmts(sc, IS_ERR(sc->tp_format) ? 2111 - RAW_SYSCALL_ARGS_NUM : sc->tp_format->format.nr_fields)) 2115 + RAW_SYSCALL_ARGS_NUM : sc->tp_format->format.nr_fields - 1)) 2112 2116 return -ENOMEM; 2113 2117 2114 2118 sc->args = sc->tp_format->format.fields;
+6 -2
tools/perf/tests/shell/trace_btf_enum.sh
··· 26 26 trace_landlock() { 27 27 echo "Tracing syscall ${syscall}" 28 28 29 - # test flight just to see if landlock_add_rule and libbpf are available 30 - $TESTPROG 29 + # test flight just to see if landlock_add_rule is available 30 + if ! perf trace $TESTPROG 2>&1 | grep -q landlock 31 + then 32 + echo "No landlock system call found, skipping to non-syscall tracing." 33 + return 34 + fi 31 35 32 36 if perf trace -e $syscall $TESTPROG 2>&1 | \ 33 37 grep -q -E ".*landlock_add_rule\(ruleset_fd: 11, rule_type: (LANDLOCK_RULE_PATH_BENEATH|LANDLOCK_RULE_NET_PORT), rule_attr: 0x[a-f0-9]+, flags: 45\) = -1.*"
+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
+4 -7
tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c
··· 431 431 static int augment_sys_enter(void *ctx, struct syscall_enter_args *args) 432 432 { 433 433 bool augmented, do_output = false; 434 - int zero = 0, size, aug_size, index, 435 - value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value); 434 + int zero = 0, index, value_size = sizeof(struct augmented_arg) - offsetof(struct augmented_arg, value); 436 435 u64 output = 0; /* has to be u64, otherwise it won't pass the verifier */ 436 + s64 aug_size, size; 437 437 unsigned int nr, *beauty_map; 438 438 struct beauty_payload_enter *payload; 439 439 void *arg, *payload_offset; ··· 484 484 } else if (size > 0 && size <= value_size) { /* struct */ 485 485 if (!bpf_probe_read_user(((struct augmented_arg *)payload_offset)->value, size, arg)) 486 486 augmented = true; 487 - } else if (size < 0 && size >= -6) { /* buffer */ 487 + } else if ((int)size < 0 && size >= -6) { /* buffer */ 488 488 index = -(size + 1); 489 489 barrier_var(index); // Prevent clang (noticed with v18) from removing the &= 7 trick. 490 490 index &= 7; // Satisfy the bounds checking with the verifier in some kernels. 491 - aug_size = args->args[index]; 492 - 493 - if (aug_size > TRACE_AUG_MAX_BUF) 494 - aug_size = TRACE_AUG_MAX_BUF; 491 + aug_size = args->args[index] > TRACE_AUG_MAX_BUF ? TRACE_AUG_MAX_BUF : args->args[index]; 495 492 496 493 if (aug_size > 0) { 497 494 if (!bpf_probe_read_user(((struct augmented_arg *)payload_offset)->value, aug_size, arg))
+2 -2
tools/perf/util/cpumap.c
··· 293 293 294 294 die = cpu__get_die_id(cpu); 295 295 /* There is no die_id on legacy system. */ 296 - if (die == -1) 296 + if (die < 0) 297 297 die = 0; 298 298 299 299 /* ··· 322 322 struct aggr_cpu_id id; 323 323 324 324 /* There is no cluster_id on legacy system. */ 325 - if (cluster == -1) 325 + if (cluster < 0) 326 326 cluster = 0; 327 327 328 328 id = aggr_cpu_id__die(cpu, data);
+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)