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 dwarf-aux: Add die_find_variable_by_reg() helper

The die_find_variable_by_reg() will search for a variable or a parameter
sub-DIE in the given scope DIE where the location matches to the given
register.

For the simplest and most common case, memory access usually happens
with a base register and an offset to the field so the register holds a
pointer in a variable or function parameter. Then we can find one if it
has a location expression at the (instruction) address. This function
only handles such a simple case for now.

In this case, the expression has a DW_OP_regN operation where N < 32.
If the register index (N) is greater than or equal to 32, DW_OP_regx
operation with an operand which saves the value for the N would be used.
It rejects expressions with more operations.

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Cc: linux-toolchains@vger.kernel.org
Cc: linux-trace-devel@vger.kernel.org
Link: https://lore.kernel.org/r/20231110000012.3538610-8-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by

Namhyung Kim and committed by
Arnaldo Carvalho de Melo
3f5928e4 981620fd

+79
+67
tools/perf/util/dwarf-aux.c
··· 1245 1245 out: 1246 1246 return ret; 1247 1247 } 1248 + 1249 + /* Interval parameters for __die_find_var_reg_cb() */ 1250 + struct find_var_data { 1251 + /* Target instruction address */ 1252 + Dwarf_Addr pc; 1253 + /* Target register */ 1254 + unsigned reg; 1255 + }; 1256 + 1257 + /* Max number of registers DW_OP_regN supports */ 1258 + #define DWARF_OP_DIRECT_REGS 32 1259 + 1260 + /* Only checks direct child DIEs in the given scope. */ 1261 + static int __die_find_var_reg_cb(Dwarf_Die *die_mem, void *arg) 1262 + { 1263 + struct find_var_data *data = arg; 1264 + int tag = dwarf_tag(die_mem); 1265 + ptrdiff_t off = 0; 1266 + Dwarf_Attribute attr; 1267 + Dwarf_Addr base, start, end; 1268 + Dwarf_Op *ops; 1269 + size_t nops; 1270 + 1271 + if (tag != DW_TAG_variable && tag != DW_TAG_formal_parameter) 1272 + return DIE_FIND_CB_SIBLING; 1273 + 1274 + if (dwarf_attr(die_mem, DW_AT_location, &attr) == NULL) 1275 + return DIE_FIND_CB_SIBLING; 1276 + 1277 + while ((off = dwarf_getlocations(&attr, off, &base, &start, &end, &ops, &nops)) > 0) { 1278 + /* Assuming the location list is sorted by address */ 1279 + if (end < data->pc) 1280 + continue; 1281 + if (start > data->pc) 1282 + break; 1283 + 1284 + /* Only match with a simple case */ 1285 + if (data->reg < DWARF_OP_DIRECT_REGS) { 1286 + if (ops->atom == (DW_OP_reg0 + data->reg) && nops == 1) 1287 + return DIE_FIND_CB_END; 1288 + } else { 1289 + if (ops->atom == DW_OP_regx && ops->number == data->reg && 1290 + nops == 1) 1291 + return DIE_FIND_CB_END; 1292 + } 1293 + } 1294 + return DIE_FIND_CB_SIBLING; 1295 + } 1296 + 1297 + /** 1298 + * die_find_variable_by_reg - Find a variable saved in a register 1299 + * @sc_die: a scope DIE 1300 + * @pc: the program address to find 1301 + * @reg: the register number to find 1302 + * @die_mem: a buffer to save the resulting DIE 1303 + * 1304 + * Find the variable DIE accessed by the given register. 1305 + */ 1306 + Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, 1307 + Dwarf_Die *die_mem) 1308 + { 1309 + struct find_var_data data = { 1310 + .pc = pc, 1311 + .reg = reg, 1312 + }; 1313 + return die_find_child(sc_die, __die_find_var_reg_cb, &data, die_mem); 1314 + } 1248 1315 #endif 1249 1316 1250 1317 /*
+12
tools/perf/util/dwarf-aux.h
··· 137 137 /* Get byte offset range of given variable DIE */ 138 138 int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf); 139 139 140 + /* Find a variable saved in the 'reg' at given address */ 141 + Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die, Dwarf_Addr pc, int reg, 142 + Dwarf_Die *die_mem); 143 + 140 144 #else /* HAVE_DWARF_GETLOCATIONS_SUPPORT */ 141 145 142 146 static inline int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, ··· 148 144 struct strbuf *buf __maybe_unused) 149 145 { 150 146 return -ENOTSUP; 147 + } 148 + 149 + static inline Dwarf_Die *die_find_variable_by_reg(Dwarf_Die *sc_die __maybe_unused, 150 + Dwarf_Addr pc __maybe_unused, 151 + int reg __maybe_unused, 152 + Dwarf_Die *die_mem __maybe_unused) 153 + { 154 + return NULL; 151 155 } 152 156 153 157 #endif /* HAVE_DWARF_GETLOCATIONS_SUPPORT */