diff options
author | Namhyung Kim <namhyung@kernel.org> | 2024-04-12 21:33:07 +0300 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2024-04-16 16:46:08 +0300 |
commit | 2bc3cf575a162a2ca9c98262a63e95cc2b619de7 (patch) | |
tree | 68da2a73000c9d8f0619adeda9bc3b2a191c80ca /tools/perf/util/annotate-data.c | |
parent | 988052f4bfcc4ee893ea19e9d9ce888cc8578e5a (diff) | |
download | linux-2bc3cf575a162a2ca9c98262a63e95cc2b619de7.tar.xz |
perf annotate-data: Improve debug message with location info
To verify it found the correct variable, let's add the location
expression to the debug message.
$ perf --debug type-profile annotate --data-type
...
-----------------------------------------------------------
find data type for 0xaf0(reg15) at schedule+0xeb
CU for kernel/sched/core.c (die:0x1180523)
frame base: cfa=0 fbreg=6
found "rq" in scope=3/4 (die: 0x11b6a00) type_offset=0xaf0
variable location: reg15
type='struct rq' size=0xfc0 (die:0x11892e2)
-----------------------------------------------------------
find data type for 0x7bc(reg3) at tcp_get_info+0x62
CU for net/ipv4/tcp.c (die:0x7b5f516)
frame base: cfa=0 fbreg=6
offset: 1980 is bigger than size: 760
check variable "sk" failed (die: 0x7b92b2c)
variable location: reg3
type='struct sock' size=0x2f8 (die:0x7b63c3a)
-----------------------------------------------------------
...
The first case is fine. It looked up a data type in r15 with offset of
0xaf0 at schedule+0xeb. It found the CU die and the frame base info and
the variable "rq" was found in the scope 3/4. Its location is the r15
register and the type size is 0xfc0 which includes 0xaf0.
But the second case is not good. It looked up a data type in rbx (reg3)
with offset 0x7bc. It found a CU and the frame base which is good so
far. And it also found a variable "sk" but the access offset is bigger
than the type size (1980 vs. 760 or 0x7bc vs. 0x2f8). The variable has
the right location (reg3) but I need to figure out why it accesses
beyond what it's supposed to.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: https://lore.kernel.org/r/20240412183310.2518474-2-namhyung@kernel.org
[ Fix the build on 32-bit by casting Dwarf_Word to (long) in pr_debug_location() ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/annotate-data.c')
-rw-r--r-- | tools/perf/util/annotate-data.c | 99 |
1 files changed, 82 insertions, 17 deletions
diff --git a/tools/perf/util/annotate-data.c b/tools/perf/util/annotate-data.c index 1cd857400038..e53d66c46c54 100644 --- a/tools/perf/util/annotate-data.c +++ b/tools/perf/util/annotate-data.c @@ -46,6 +46,7 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) { struct strbuf sb; char *str; + Dwarf_Word size = 0; if (!debug_type_profile && verbose < 3) return; @@ -72,13 +73,67 @@ static void pr_debug_type_name(Dwarf_Die *die, enum type_state_kind kind) break; } + dwarf_aggregate_size(die, &size); + strbuf_init(&sb, 32); die_get_typename_from_type(die, &sb); str = strbuf_detach(&sb, NULL); - pr_info(" type=%s (die:%lx)\n", str, (long)dwarf_dieoffset(die)); + pr_info(" type='%s' size=%#lx (die:%#lx)\n", + str, (long)size, (long)dwarf_dieoffset(die)); free(str); } +static void pr_debug_location(Dwarf_Die *die, u64 pc, int reg) +{ + ptrdiff_t off = 0; + Dwarf_Attribute attr; + Dwarf_Addr base, start, end; + Dwarf_Op *ops; + size_t nops; + + if (!debug_type_profile && verbose < 3) + return; + + if (dwarf_attr(die, DW_AT_location, &attr) == NULL) + return; + + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { + if (reg != DWARF_REG_PC && end < pc) + continue; + if (reg != DWARF_REG_PC && start > pc) + break; + + pr_info(" variable location: "); + switch (ops->atom) { + case DW_OP_reg0 ...DW_OP_reg31: + pr_info("reg%d\n", ops->atom - DW_OP_reg0); + break; + case DW_OP_breg0 ...DW_OP_breg31: + pr_info("base=reg%d, offset=%#lx\n", + ops->atom - DW_OP_breg0, (long)ops->number); + break; + case DW_OP_regx: + pr_info("reg%ld\n", (long)ops->number); + break; + case DW_OP_bregx: + pr_info("base=reg%ld, offset=%#lx\n", + (long)ops->number, (long)ops->number2); + break; + case DW_OP_fbreg: + pr_info("use frame base, offset=%#lx\n", (long)ops->number); + break; + case DW_OP_addr: + pr_info("address=%#lx\n", (long)ops->number); + break; + default: + pr_info("unknown: code=%#x, number=%#lx\n", + ops->atom, (long)ops->number); + break; + } + break; + } +} + /* * Type information in a register, valid when @ok is true. * The @caller_saved registers are invalidated after a function call. @@ -1404,7 +1459,7 @@ again: found = find_data_type_insn(dloc, reg, &basic_blocks, var_types, cu_die, type_die); if (found > 0) { - pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x", + pr_debug_dtp("found by insn track: %#x(reg%d) type-offset=%#x\n", dloc->op->offset, reg, dloc->type_offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); ret = 0; @@ -1440,16 +1495,16 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) char buf[64]; if (dloc->op->multi_regs) - snprintf(buf, sizeof(buf), " or reg%d", dloc->op->reg2); + snprintf(buf, sizeof(buf), "reg%d, reg%d", dloc->op->reg1, dloc->op->reg2); else if (dloc->op->reg1 == DWARF_REG_PC) - snprintf(buf, sizeof(buf), " (PC)"); + snprintf(buf, sizeof(buf), "PC"); else - buf[0] = '\0'; + snprintf(buf, sizeof(buf), "reg%d", dloc->op->reg1); pr_debug_dtp("-----------------------------------------------------------\n"); - pr_debug_dtp("%s [%"PRIx64"] for reg%d%s offset=%#x in %s\n", - __func__, dloc->ip - dloc->ms->sym->start, - dloc->op->reg1, buf, dloc->op->offset, dloc->ms->sym->name); + pr_debug_dtp("find data type for %#x(%s) at %s+%#"PRIx64"\n", + dloc->op->offset, buf, dloc->ms->sym->name, + dloc->ip - dloc->ms->sym->start); /* * IP is a relative instruction address from the start of the map, as @@ -1468,14 +1523,15 @@ static int find_data_type_die(struct data_loc_info *dloc, Dwarf_Die *type_die) reg = loc->reg1; offset = loc->offset; - pr_debug_dtp("CU die offset: %#lx\n", (long)dwarf_dieoffset(&cu_die)); + pr_debug_dtp("CU for %s (die:%#lx)\n", + dwarf_diename(&cu_die), (long)dwarf_dieoffset(&cu_die)); if (reg == DWARF_REG_PC) { if (get_global_var_type(&cu_die, dloc, dloc->ip, dloc->var_addr, &offset, type_die)) { dloc->type_offset = offset; - pr_debug_dtp("found PC-rel by addr=%#"PRIx64" offset=%#x", + pr_debug_dtp("found by addr=%#"PRIx64" type_offset=%#x\n", dloc->var_addr, offset); pr_debug_type_name(type_die, TSR_KIND_TYPE); ret = 0; @@ -1537,13 +1593,22 @@ retry: pr_debug_dtp("found \"%s\" in scope=%d/%d (die: %#lx) ", dwarf_diename(&var_die), i+1, nr_scopes, (long)dwarf_dieoffset(&scopes[i])); - if (reg == DWARF_REG_PC) - pr_debug_dtp("%#x(PC) offset=%#x", loc->offset, offset); - else if (reg == DWARF_REG_FB || is_fbreg) - pr_debug_dtp("%#x(reg%d) stack fb_offset=%#x offset=%#x", - loc->offset, reg, fb_offset, offset); - else - pr_debug_dtp("%#x(reg%d)", loc->offset, reg); + if (reg == DWARF_REG_PC) { + pr_debug_dtp("addr=%#"PRIx64" type_offset=%#x\n", + dloc->var_addr, offset); + } else if (reg == DWARF_REG_FB || is_fbreg) { + pr_debug_dtp("stack_offset=%#x type_offset=%#x\n", + fb_offset, offset); + } else { + pr_debug_dtp("type_offset=%#x\n", offset); + } + pr_debug_location(&var_die, pc, reg); + pr_debug_type_name(type_die, TSR_KIND_TYPE); + } else { + pr_debug_dtp("check variable \"%s\" failed (die: %#lx)\n", + dwarf_diename(&var_die), + (long)dwarf_dieoffset(&var_die)); + pr_debug_location(&var_die, pc, reg); pr_debug_type_name(type_die, TSR_KIND_TYPE); } dloc->type_offset = offset; |