aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-06-27 03:27:27 -0400
committerSteven Rostedt <rostedt@goodmis.org>2011-07-15 16:10:17 -0400
commite0d153c69040bb37cbdf09deb52fee3013c07742 (patch)
treee008ba8ac1f328b6938e80b9208d64c4548f8e8e /tools/perf/util/probe-finder.c
parentbcfc082150c6b1e9443c1277bca8be80094150b5 (diff)
perf-probe: Move dwarf library routines to dwarf-aux.{c, h}
Move dwarf library related routines to dwarf-aux.{c,h}. This includes several minor changes. - Add simple documents for each API. - Rename die_find_real_subprogram() to die_find_realfunc() - Rename line_walk_handler_t to line_walk_callback_t. - Minor cleanups. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Paul Mackerras <paulus@samba.org> Cc: Ingo Molnar <mingo@elte.hu> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Link: http://lkml.kernel.org/r/20110627072727.6528.57647.stgit@fedora15 Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c520
1 files changed, 2 insertions, 518 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index d443b643957f..53d219bddb48 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -222,521 +222,6 @@ static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp,
222} 222}
223#endif 223#endif
224 224
225/* Dwarf wrappers */
226
227/* Find the realpath of the target file. */
228static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
229{
230 Dwarf_Files *files;
231 size_t nfiles, i;
232 const char *src = NULL;
233 int ret;
234
235 if (!fname)
236 return NULL;
237
238 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
239 if (ret != 0)
240 return NULL;
241
242 for (i = 0; i < nfiles; i++) {
243 src = dwarf_filesrc(files, i, NULL, NULL);
244 if (strtailcmp(src, fname) == 0)
245 break;
246 }
247 if (i == nfiles)
248 return NULL;
249 return src;
250}
251
252/* Get DW_AT_comp_dir (should be NULL with older gcc) */
253static const char *cu_get_comp_dir(Dwarf_Die *cu_die)
254{
255 Dwarf_Attribute attr;
256 if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL)
257 return NULL;
258 return dwarf_formstring(&attr);
259}
260
261/* Get a line number and file name for given address */
262static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr,
263 const char **fname, int *lineno)
264{
265 Dwarf_Line *line;
266 Dwarf_Addr laddr;
267
268 line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr);
269 if (line && dwarf_lineaddr(line, &laddr) == 0 &&
270 addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) {
271 *fname = dwarf_linesrc(line, NULL, NULL);
272 if (!*fname)
273 /* line number is useless without filename */
274 *lineno = 0;
275 }
276
277 return *lineno ?: -ENOENT;
278}
279
280/* Compare diename and tname */
281static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
282{
283 const char *name;
284 name = dwarf_diename(dw_die);
285 return name ? (strcmp(tname, name) == 0) : false;
286}
287
288/* Get callsite line number of inline-function instance */
289static int die_get_call_lineno(Dwarf_Die *in_die)
290{
291 Dwarf_Attribute attr;
292 Dwarf_Word ret;
293
294 if (!dwarf_attr(in_die, DW_AT_call_line, &attr))
295 return -ENOENT;
296
297 dwarf_formudata(&attr, &ret);
298 return (int)ret;
299}
300
301/* Get type die */
302static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
303{
304 Dwarf_Attribute attr;
305
306 if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) &&
307 dwarf_formref_die(&attr, die_mem))
308 return die_mem;
309 else
310 return NULL;
311}
312
313/* Get a type die, but skip qualifiers */
314static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
315{
316 int tag;
317
318 do {
319 vr_die = die_get_type(vr_die, die_mem);
320 if (!vr_die)
321 break;
322 tag = dwarf_tag(vr_die);
323 } while (tag == DW_TAG_const_type ||
324 tag == DW_TAG_restrict_type ||
325 tag == DW_TAG_volatile_type ||
326 tag == DW_TAG_shared_type);
327
328 return vr_die;
329}
330
331/* Get a type die, but skip qualifiers and typedef */
332static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
333{
334 do {
335 vr_die = __die_get_real_type(vr_die, die_mem);
336 } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef);
337
338 return vr_die;
339}
340
341static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name,
342 Dwarf_Word *result)
343{
344 Dwarf_Attribute attr;
345
346 if (dwarf_attr(tp_die, attr_name, &attr) == NULL ||
347 dwarf_formudata(&attr, result) != 0)
348 return -ENOENT;
349
350 return 0;
351}
352
353static bool die_is_signed_type(Dwarf_Die *tp_die)
354{
355 Dwarf_Word ret;
356
357 if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret))
358 return false;
359
360 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
361 ret == DW_ATE_signed_fixed);
362}
363
364/* Get data_member_location offset */
365static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs)
366{
367 Dwarf_Attribute attr;
368 Dwarf_Op *expr;
369 size_t nexpr;
370 int ret;
371
372 if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL)
373 return -ENOENT;
374
375 if (dwarf_formudata(&attr, offs) != 0) {
376 /* DW_AT_data_member_location should be DW_OP_plus_uconst */
377 ret = dwarf_getlocation(&attr, &expr, &nexpr);
378 if (ret < 0 || nexpr == 0)
379 return -ENOENT;
380
381 if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) {
382 pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n",
383 expr[0].atom, nexpr);
384 return -ENOTSUP;
385 }
386 *offs = (Dwarf_Word)expr[0].number;
387 }
388 return 0;
389}
390
391/* Return values for die_find callbacks */
392enum {
393 DIE_FIND_CB_END = 0, /* End of Search */
394 DIE_FIND_CB_CHILD = 1, /* Search only children */
395 DIE_FIND_CB_SIBLING = 2, /* Search only siblings */
396 DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */
397};
398
399/* Search a child die */
400static Dwarf_Die *die_find_child(Dwarf_Die *rt_die,
401 int (*callback)(Dwarf_Die *, void *),
402 void *data, Dwarf_Die *die_mem)
403{
404 Dwarf_Die child_die;
405 int ret;
406
407 ret = dwarf_child(rt_die, die_mem);
408 if (ret != 0)
409 return NULL;
410
411 do {
412 ret = callback(die_mem, data);
413 if (ret == DIE_FIND_CB_END)
414 return die_mem;
415
416 if ((ret & DIE_FIND_CB_CHILD) &&
417 die_find_child(die_mem, callback, data, &child_die)) {
418 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
419 return die_mem;
420 }
421 } while ((ret & DIE_FIND_CB_SIBLING) &&
422 dwarf_siblingof(die_mem, die_mem) == 0);
423
424 return NULL;
425}
426
427struct __addr_die_search_param {
428 Dwarf_Addr addr;
429 Dwarf_Die *die_mem;
430};
431
432static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
433{
434 struct __addr_die_search_param *ad = data;
435
436 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
437 dwarf_haspc(fn_die, ad->addr)) {
438 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
439 return DWARF_CB_ABORT;
440 }
441 return DWARF_CB_OK;
442}
443
444/* Search a real subprogram including this line, */
445static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
446 Dwarf_Die *die_mem)
447{
448 struct __addr_die_search_param ad;
449 ad.addr = addr;
450 ad.die_mem = die_mem;
451 /* dwarf_getscopes can't find subprogram. */
452 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
453 return NULL;
454 else
455 return die_mem;
456}
457
458/* die_find callback for inline function search */
459static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data)
460{
461 Dwarf_Addr *addr = data;
462
463 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
464 dwarf_haspc(die_mem, *addr))
465 return DIE_FIND_CB_END;
466
467 return DIE_FIND_CB_CONTINUE;
468}
469
470/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
471static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
472 Dwarf_Die *die_mem)
473{
474 Dwarf_Die tmp_die;
475
476 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die);
477 if (!sp_die)
478 return NULL;
479
480 /* Inlined function could be recursive. Trace it until fail */
481 while (sp_die) {
482 memcpy(die_mem, sp_die, sizeof(Dwarf_Die));
483 sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr,
484 &tmp_die);
485 }
486
487 return die_mem;
488}
489
490/* Walker on lines (Note: line number will not be sorted) */
491typedef int (* line_walk_handler_t) (const char *fname, int lineno,
492 Dwarf_Addr addr, void *data);
493
494struct __line_walk_param {
495 const char *fname;
496 line_walk_handler_t handler;
497 void *data;
498 int retval;
499};
500
501static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data)
502{
503 struct __line_walk_param *lw = data;
504 Dwarf_Addr addr;
505 int lineno;
506
507 if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) {
508 lineno = die_get_call_lineno(in_die);
509 if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) {
510 lw->retval = lw->handler(lw->fname, lineno, addr,
511 lw->data);
512 if (lw->retval != 0)
513 return DIE_FIND_CB_END;
514 }
515 }
516 return DIE_FIND_CB_SIBLING;
517}
518
519/* Walk on lines of blocks included in given DIE */
520static int __die_walk_funclines(Dwarf_Die *sp_die,
521 line_walk_handler_t handler, void *data)
522{
523 struct __line_walk_param lw = {
524 .handler = handler,
525 .data = data,
526 .retval = 0,
527 };
528 Dwarf_Die die_mem;
529 Dwarf_Addr addr;
530 int lineno;
531
532 /* Handle function declaration line */
533 lw.fname = dwarf_decl_file(sp_die);
534 if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 &&
535 dwarf_entrypc(sp_die, &addr) == 0) {
536 lw.retval = handler(lw.fname, lineno, addr, data);
537 if (lw.retval != 0)
538 goto done;
539 }
540 die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem);
541done:
542 return lw.retval;
543}
544
545static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data)
546{
547 struct __line_walk_param *lw = data;
548
549 lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data);
550 if (lw->retval != 0)
551 return DWARF_CB_ABORT;
552
553 return DWARF_CB_OK;
554}
555
556/*
557 * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on
558 * the lines inside the subprogram, otherwise PDIE must be a CU DIE.
559 */
560static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler,
561 void *data)
562{
563 Dwarf_Lines *lines;
564 Dwarf_Line *line;
565 Dwarf_Addr addr;
566 const char *fname;
567 int lineno, ret = 0;
568 Dwarf_Die die_mem, *cu_die;
569 size_t nlines, i;
570
571 /* Get the CU die */
572 if (dwarf_tag(pdie) == DW_TAG_subprogram)
573 cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL);
574 else
575 cu_die = pdie;
576 if (!cu_die) {
577 pr_debug2("Failed to get CU from subprogram\n");
578 return -EINVAL;
579 }
580
581 /* Get lines list in the CU */
582 if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) {
583 pr_debug2("Failed to get source lines on this CU.\n");
584 return -ENOENT;
585 }
586 pr_debug2("Get %zd lines from this CU\n", nlines);
587
588 /* Walk on the lines on lines list */
589 for (i = 0; i < nlines; i++) {
590 line = dwarf_onesrcline(lines, i);
591 if (line == NULL ||
592 dwarf_lineno(line, &lineno) != 0 ||
593 dwarf_lineaddr(line, &addr) != 0) {
594 pr_debug2("Failed to get line info. "
595 "Possible error in debuginfo.\n");
596 continue;
597 }
598 /* Filter lines based on address */
599 if (pdie != cu_die)
600 /*
601 * Address filtering
602 * The line is included in given function, and
603 * no inline block includes it.
604 */
605 if (!dwarf_haspc(pdie, addr) ||
606 die_find_inlinefunc(pdie, addr, &die_mem))
607 continue;
608 /* Get source line */
609 fname = dwarf_linesrc(line, NULL, NULL);
610
611 ret = handler(fname, lineno, addr, data);
612 if (ret != 0)
613 return ret;
614 }
615
616 /*
617 * Dwarf lines doesn't include function declarations and inlined
618 * subroutines. We have to check functions list or given function.
619 */
620 if (pdie != cu_die)
621 ret = __die_walk_funclines(pdie, handler, data);
622 else {
623 struct __line_walk_param param = {
624 .handler = handler,
625 .data = data,
626 .retval = 0,
627 };
628 dwarf_getfuncs(cu_die, __die_walk_culines_cb, &param, 0);
629 ret = param.retval;
630 }
631
632 return ret;
633}
634
635struct __find_variable_param {
636 const char *name;
637 Dwarf_Addr addr;
638};
639
640static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data)
641{
642 struct __find_variable_param *fvp = data;
643 int tag;
644
645 tag = dwarf_tag(die_mem);
646 if ((tag == DW_TAG_formal_parameter ||
647 tag == DW_TAG_variable) &&
648 die_compare_name(die_mem, fvp->name))
649 return DIE_FIND_CB_END;
650
651 if (dwarf_haspc(die_mem, fvp->addr))
652 return DIE_FIND_CB_CONTINUE;
653 else
654 return DIE_FIND_CB_SIBLING;
655}
656
657/* Find a variable called 'name' at given address */
658static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name,
659 Dwarf_Addr addr, Dwarf_Die *die_mem)
660{
661 struct __find_variable_param fvp = { .name = name, .addr = addr};
662
663 return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp,
664 die_mem);
665}
666
667static int __die_find_member_cb(Dwarf_Die *die_mem, void *data)
668{
669 const char *name = data;
670
671 if ((dwarf_tag(die_mem) == DW_TAG_member) &&
672 die_compare_name(die_mem, name))
673 return DIE_FIND_CB_END;
674
675 return DIE_FIND_CB_SIBLING;
676}
677
678/* Find a member called 'name' */
679static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
680 Dwarf_Die *die_mem)
681{
682 return die_find_child(st_die, __die_find_member_cb, (void *)name,
683 die_mem);
684}
685
686/* Get the name of given variable DIE */
687static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len)
688{
689 Dwarf_Die type;
690 int tag, ret, ret2;
691 const char *tmp = "";
692
693 if (__die_get_real_type(vr_die, &type) == NULL)
694 return -ENOENT;
695
696 tag = dwarf_tag(&type);
697 if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)
698 tmp = "*";
699 else if (tag == DW_TAG_subroutine_type) {
700 /* Function pointer */
701 ret = snprintf(buf, len, "(function_type)");
702 return (ret >= len) ? -E2BIG : ret;
703 } else {
704 if (!dwarf_diename(&type))
705 return -ENOENT;
706 if (tag == DW_TAG_union_type)
707 tmp = "union ";
708 else if (tag == DW_TAG_structure_type)
709 tmp = "struct ";
710 /* Write a base name */
711 ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type));
712 return (ret >= len) ? -E2BIG : ret;
713 }
714 ret = die_get_typename(&type, buf, len);
715 if (ret > 0) {
716 ret2 = snprintf(buf + ret, len - ret, "%s", tmp);
717 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
718 }
719 return ret;
720}
721
722/* Get the name and type of given variable DIE, stored as "type\tname" */
723static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len)
724{
725 int ret, ret2;
726
727 ret = die_get_typename(vr_die, buf, len);
728 if (ret < 0) {
729 pr_debug("Failed to get type, make it unknown.\n");
730 ret = snprintf(buf, len, "(unknown_type)");
731 }
732 if (ret > 0) {
733 ret2 = snprintf(buf + ret, len - ret, "\t%s",
734 dwarf_diename(vr_die));
735 ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret;
736 }
737 return ret;
738}
739
740/* 225/*
741 * Probe finder related functions 226 * Probe finder related functions
742 */ 227 */
@@ -1206,8 +691,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf)
1206 691
1207 /* If no real subprogram, find a real one */ 692 /* If no real subprogram, find a real one */
1208 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 693 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
1209 sp_die = die_find_real_subprogram(&pf->cu_die, 694 sp_die = die_find_realfunc(&pf->cu_die, pf->addr, &die_mem);
1210 pf->addr, &die_mem);
1211 if (!sp_die) { 695 if (!sp_die) {
1212 pr_warning("Failed to find probe point in any " 696 pr_warning("Failed to find probe point in any "
1213 "functions.\n"); 697 "functions.\n");
@@ -1768,7 +1252,7 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt)
1768 /* Don't care whether it failed or not */ 1252 /* Don't care whether it failed or not */
1769 1253
1770 /* Find a corresponding function (name, baseline and baseaddr) */ 1254 /* Find a corresponding function (name, baseline and baseaddr) */
1771 if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { 1255 if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) {
1772 /* Get function entry information */ 1256 /* Get function entry information */
1773 tmp = dwarf_diename(&spdie); 1257 tmp = dwarf_diename(&spdie);
1774 if (!tmp || 1258 if (!tmp ||