diff options
| author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-02-25 08:35:50 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-02-25 11:49:29 -0500 |
| commit | e92b85e1ffaa0bd8e5d92e7c378a3909e7f23122 (patch) | |
| tree | 6bd934ca363a3529ad4ecb1112c1d2c70c13089b | |
| parent | 804b36068eccd8163ccea420c662fb5d1a21b141 (diff) | |
perf probe: Use libdw callback routines
Use libdw callback functions aggressively, and remove
local tree-search API. This change simplifies the code.
Changes in v3:
- Cast Dwarf_Addr to uintmax_t for printf-formats.
Changes in v2:
- Cast Dwarf_Addr to unsigned long long for printf-formats.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: K.Prasad <prasad@linux.vnet.ibm.com>
Cc: Ulrich Drepper <drepper@redhat.com>
Cc: Roland McGrath <roland@redhat.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
LKML-Reference: <20100225133549.6725.81499.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
| -rw-r--r-- | tools/perf/util/probe-finder.c | 262 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.h | 1 |
2 files changed, 86 insertions, 177 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index c422472fe4d1..6305f344f382 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -38,13 +38,6 @@ | |||
| 38 | #include "probe-finder.h" | 38 | #include "probe-finder.h" |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | /* Dwarf_Die Linkage to parent Die */ | ||
| 42 | struct die_link { | ||
| 43 | struct die_link *parent; /* Parent die */ | ||
| 44 | Dwarf_Die die; /* Current die */ | ||
| 45 | }; | ||
| 46 | |||
| 47 | |||
| 48 | /* | 41 | /* |
| 49 | * Generic dwarf analysis helpers | 42 | * Generic dwarf analysis helpers |
| 50 | */ | 43 | */ |
| @@ -177,26 +170,6 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | |||
| 177 | return strcmp(tname, name); | 170 | return strcmp(tname, name); |
| 178 | } | 171 | } |
| 179 | 172 | ||
| 180 | /* Check the address is in the subprogram(function). */ | ||
| 181 | static bool die_within_subprogram(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
| 182 | size_t *offs) | ||
| 183 | { | ||
| 184 | Dwarf_Addr epc; | ||
| 185 | int ret; | ||
| 186 | |||
| 187 | ret = dwarf_haspc(sp_die, addr); | ||
| 188 | if (ret <= 0) | ||
| 189 | return false; | ||
| 190 | |||
| 191 | if (offs) { | ||
| 192 | ret = dwarf_entrypc(sp_die, &epc); | ||
| 193 | DIE_IF(ret == -1); | ||
| 194 | *offs = addr - epc; | ||
| 195 | } | ||
| 196 | |||
| 197 | return true; | ||
| 198 | } | ||
| 199 | |||
| 200 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | 173 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ |
| 201 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | 174 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) |
| 202 | { | 175 | { |
| @@ -208,70 +181,34 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | |||
| 208 | return epc; | 181 | return epc; |
| 209 | } | 182 | } |
| 210 | 183 | ||
| 211 | /* Check if the abstract origin's address or not */ | 184 | /* Get a variable die */ |
| 212 | static bool die_compare_abstract_origin(Dwarf_Die *in_die, void *origin_addr) | 185 | static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, |
| 213 | { | 186 | Dwarf_Die *die_mem) |
| 214 | Dwarf_Attribute attr; | ||
| 215 | Dwarf_Die origin; | ||
| 216 | |||
| 217 | if (!dwarf_attr(in_die, DW_AT_abstract_origin, &attr)) | ||
| 218 | return false; | ||
| 219 | if (!dwarf_formref_die(&attr, &origin)) | ||
| 220 | return false; | ||
| 221 | |||
| 222 | return origin.addr == origin_addr; | ||
| 223 | } | ||
| 224 | |||
| 225 | /* | ||
| 226 | * Search a Die from Die tree. | ||
| 227 | * Note: cur_link->die should be deallocated in this function. | ||
| 228 | */ | ||
| 229 | static int __search_die_tree(struct die_link *cur_link, | ||
| 230 | int (*die_cb)(struct die_link *, void *), | ||
| 231 | void *data) | ||
| 232 | { | 187 | { |
| 233 | struct die_link new_link; | 188 | Dwarf_Die child_die; |
| 189 | int tag; | ||
| 234 | int ret; | 190 | int ret; |
| 235 | 191 | ||
| 236 | if (!die_cb) | 192 | ret = dwarf_child(sp_die, die_mem); |
| 237 | return 0; | 193 | if (ret != 0) |
| 238 | 194 | return NULL; | |
| 239 | /* Check current die */ | ||
| 240 | while (!(ret = die_cb(cur_link, data))) { | ||
| 241 | /* Check child die */ | ||
| 242 | ret = dwarf_child(&cur_link->die, &new_link.die); | ||
| 243 | if (ret == 0) { | ||
| 244 | new_link.parent = cur_link; | ||
| 245 | ret = __search_die_tree(&new_link, die_cb, data); | ||
| 246 | if (ret) | ||
| 247 | break; | ||
| 248 | } | ||
| 249 | 195 | ||
| 250 | /* Move to next sibling */ | 196 | do { |
| 251 | ret = dwarf_siblingof(&cur_link->die, &cur_link->die); | 197 | tag = dwarf_tag(die_mem); |
| 252 | if (ret != 0) | 198 | if ((tag == DW_TAG_formal_parameter || |
| 253 | return 0; | 199 | tag == DW_TAG_variable) && |
| 254 | } | 200 | (die_compare_name(die_mem, name) == 0)) |
| 255 | return ret; | 201 | return die_mem; |
| 256 | } | ||
| 257 | 202 | ||
| 258 | /* Search a die in its children's die tree */ | 203 | if (die_find_variable(die_mem, name, &child_die)) { |
| 259 | static int search_die_from_children(Dwarf_Die *parent_die, | 204 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); |
| 260 | int (*die_cb)(struct die_link *, void *), | 205 | return die_mem; |
| 261 | void *data) | 206 | } |
| 262 | { | 207 | } while (dwarf_siblingof(die_mem, die_mem) == 0); |
| 263 | struct die_link new_link; | ||
| 264 | int ret; | ||
| 265 | 208 | ||
| 266 | new_link.parent = NULL; | 209 | return NULL; |
| 267 | ret = dwarf_child(parent_die, &new_link.die); | ||
| 268 | if (ret == 0) | ||
| 269 | return __search_die_tree(&new_link, die_cb, data); | ||
| 270 | else | ||
| 271 | return 0; | ||
| 272 | } | 210 | } |
| 273 | 211 | ||
| 274 | |||
| 275 | /* | 212 | /* |
| 276 | * Probe finder related functions | 213 | * Probe finder related functions |
| 277 | */ | 214 | */ |
| @@ -347,28 +284,13 @@ error: | |||
| 347 | " Perhaps, it has been optimized out.", pf->var); | 284 | " Perhaps, it has been optimized out.", pf->var); |
| 348 | } | 285 | } |
| 349 | 286 | ||
| 350 | static int variable_search_cb(struct die_link *dlink, void *data) | ||
| 351 | { | ||
| 352 | struct probe_finder *pf = (struct probe_finder *)data; | ||
| 353 | int tag; | ||
| 354 | |||
| 355 | tag = dwarf_tag(&dlink->die); | ||
| 356 | DIE_IF(tag < 0); | ||
| 357 | if ((tag == DW_TAG_formal_parameter || | ||
| 358 | tag == DW_TAG_variable) && | ||
| 359 | (die_compare_name(&dlink->die, pf->var) == 0)) { | ||
| 360 | show_variable(&dlink->die, pf); | ||
| 361 | return 1; | ||
| 362 | } | ||
| 363 | /* TODO: Support struct members and arrays */ | ||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 367 | /* Find a variable in a subprogram die */ | 287 | /* Find a variable in a subprogram die */ |
| 368 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 288 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
| 369 | { | 289 | { |
| 370 | int ret; | 290 | int ret; |
| 291 | Dwarf_Die vr_die; | ||
| 371 | 292 | ||
| 293 | /* TODO: Support struct members and arrays */ | ||
| 372 | if (!is_c_varname(pf->var)) { | 294 | if (!is_c_varname(pf->var)) { |
| 373 | /* Output raw parameters */ | 295 | /* Output raw parameters */ |
| 374 | ret = snprintf(pf->buf, pf->len, " %s", pf->var); | 296 | ret = snprintf(pf->buf, pf->len, " %s", pf->var); |
| @@ -379,31 +301,42 @@ static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 379 | 301 | ||
| 380 | pr_debug("Searching '%s' variable in context.\n", pf->var); | 302 | pr_debug("Searching '%s' variable in context.\n", pf->var); |
| 381 | /* Search child die for local variables and parameters. */ | 303 | /* Search child die for local variables and parameters. */ |
| 382 | ret = search_die_from_children(sp_die, variable_search_cb, pf); | 304 | if (!die_find_variable(sp_die, pf->var, &vr_die)) |
| 383 | if (!ret) | ||
| 384 | die("Failed to find '%s' in this function.", pf->var); | 305 | die("Failed to find '%s' in this function.", pf->var); |
| 306 | |||
| 307 | show_variable(&vr_die, pf); | ||
| 385 | } | 308 | } |
| 386 | 309 | ||
| 387 | /* Show a probe point to output buffer */ | 310 | /* Show a probe point to output buffer */ |
| 388 | static void show_probe_point(Dwarf_Die *sp_die, size_t offs, | 311 | static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) |
