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

perf annotate-data: Add annotated_data_type__get_member_name()

Factor out a function to get the name of member field at the given
offset. This will be used in other places.

Also update the output of typeoff sort key a little bit. As we know
that some special types like (stack operation), (stack canary) and
(unknown) won't have fields, skip printing the offset and field.

For example, the following change is expected.

"(stack operation) +0 (no field)" ==> "(stack operation)"

Reviewed-by: Ian Rogers <irogers@google.com>
Link: https://lore.kernel.org/r/20250310224925.799005-2-namhyung@kernel.org
Signed-off-by: Namhyung Kim <namhyung@kernel.org>

+54 -32
+34
tools/perf/util/annotate-data.c
··· 314 314 } 315 315 } 316 316 317 + static int fill_member_name(char *buf, size_t sz, struct annotated_member *m, 318 + int offset, bool first) 319 + { 320 + struct annotated_member *child; 321 + 322 + if (list_empty(&m->children)) 323 + return 0; 324 + 325 + list_for_each_entry(child, &m->children, node) { 326 + int len; 327 + 328 + if (offset < child->offset || offset >= child->offset + child->size) 329 + continue; 330 + 331 + /* It can have anonymous struct/union members */ 332 + if (child->var_name) { 333 + len = scnprintf(buf, sz, "%s%s", 334 + first ? "" : ".", child->var_name); 335 + first = false; 336 + } else { 337 + len = 0; 338 + } 339 + 340 + return fill_member_name(buf + len, sz - len, child, offset, first) + len; 341 + } 342 + return 0; 343 + } 344 + 345 + int annotated_data_type__get_member_name(struct annotated_data_type *adt, 346 + char *buf, size_t sz, int member_offset) 347 + { 348 + return fill_member_name(buf, sz, &adt->self, member_offset, /*first=*/true); 349 + } 350 + 317 351 static struct annotated_data_type *dso__findnew_data_type(struct dso *dso, 318 352 Dwarf_Die *type_die) 319 353 {
+13
tools/perf/util/annotate-data.h
··· 227 227 /* Release all global variable information in the tree */ 228 228 void global_var_type__tree_delete(struct rb_root *root); 229 229 230 + /* Print data type annotation (including members) on stdout */ 230 231 int hist_entry__annotate_data_tty(struct hist_entry *he, struct evsel *evsel); 232 + 233 + /* Get name of member field at the given offset in the data type */ 234 + int annotated_data_type__get_member_name(struct annotated_data_type *adt, 235 + char *buf, size_t sz, int member_offset); 231 236 232 237 bool has_reg_type(struct type_state *state, int reg); 233 238 struct type_state_stack *findnew_stack_state(struct type_state *state, ··· 277 272 278 273 static inline int hist_entry__annotate_data_tty(struct hist_entry *he __maybe_unused, 279 274 struct evsel *evsel __maybe_unused) 275 + { 276 + return -1; 277 + } 278 + 279 + static inline int annotated_data_type__get_member_name(struct annotated_data_type *adt __maybe_unused, 280 + char *buf __maybe_unused, 281 + size_t sz __maybe_unused, 282 + int member_offset __maybe_unused) 280 283 { 281 284 return -1; 282 285 }
+7 -32
tools/perf/util/sort.c
··· 2403 2403 return left->mem_type_off - right->mem_type_off; 2404 2404 } 2405 2405 2406 - static void fill_member_name(char *buf, size_t sz, struct annotated_member *m, 2407 - int offset, bool first) 2408 - { 2409 - struct annotated_member *child; 2410 - 2411 - if (list_empty(&m->children)) 2412 - return; 2413 - 2414 - list_for_each_entry(child, &m->children, node) { 2415 - if (child->offset <= offset && offset < child->offset + child->size) { 2416 - int len = 0; 2417 - 2418 - /* It can have anonymous struct/union members */ 2419 - if (child->var_name) { 2420 - len = scnprintf(buf, sz, "%s%s", 2421 - first ? "" : ".", child->var_name); 2422 - first = false; 2423 - } 2424 - 2425 - fill_member_name(buf + len, sz - len, child, offset, first); 2426 - return; 2427 - } 2428 - } 2429 - } 2430 - 2431 2406 static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf, 2432 2407 size_t size, unsigned int width __maybe_unused) 2433 2408 { 2434 2409 struct annotated_data_type *he_type = he->mem_type; 2435 2410 char buf[4096]; 2436 2411 2437 - buf[0] = '\0'; 2438 - if (list_empty(&he_type->self.children)) 2439 - snprintf(buf, sizeof(buf), "no field"); 2440 - else 2441 - fill_member_name(buf, sizeof(buf), &he_type->self, 2442 - he->mem_type_off, true); 2443 - buf[4095] = '\0'; 2412 + if (he_type == &unknown_type || he_type == &stackop_type || 2413 + he_type == &canary_type) 2414 + return repsep_snprintf(bf, size, "%s", he_type->self.type_name); 2415 + 2416 + if (!annotated_data_type__get_member_name(he_type, buf, sizeof(buf), 2417 + he->mem_type_off)) 2418 + scnprintf(buf, sizeof(buf), "no field"); 2444 2419 2445 2420 return repsep_snprintf(bf, size, "%s +%#x (%s)", he_type->self.type_name, 2446 2421 he->mem_type_off, buf);