aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/probe-finder.c
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-03-16 18:06:12 -0400
committerIngo Molnar <mingo@elte.hu>2010-03-17 06:32:31 -0400
commit4235b0454ebeefc2295ad8417e18a8761425b19e (patch)
treee6b0a3c66618dede18117a71fd16d2e65f93cba1 /tools/perf/util/probe-finder.c
parentf4d7da499e4fc1fdff8f26fdeb1a058d475a7a6c (diff)
perf probe: Introduce kprobe_trace_event and perf_probe_event
Introduce kprobe_trace_event and perf_probe_event and replace old probe_point structure with it. probe_point structure is not enough flexible nor extensible. New data structures will help implementing further features. 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: Paul Mackerras <paulus@samba.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r--tools/perf/util/probe-finder.c140
1 files changed, 63 insertions, 77 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 3942e14e95cf..251b4c49653e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -319,19 +319,20 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
319 */ 319 */
320 320
321/* Show a location */ 321/* Show a location */
322static void show_location(Dwarf_Op *op, struct probe_finder *pf) 322static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
323{ 323{
324 unsigned int regn; 324 unsigned int regn;
325 Dwarf_Word offs = 0; 325 Dwarf_Word offs = 0;
326 int deref = 0, ret; 326 bool ref = false;
327 const char *regs; 327 const char *regs;
328 struct kprobe_trace_arg *tvar = pf->tvar;
328 329
329 /* TODO: support CFA */ 330 /* TODO: support CFA */
330 /* If this is based on frame buffer, set the offset */ 331 /* If this is based on frame buffer, set the offset */
331 if (op->atom == DW_OP_fbreg) { 332 if (op->atom == DW_OP_fbreg) {
332 if (pf->fb_ops == NULL) 333 if (pf->fb_ops == NULL)
333 die("The attribute of frame base is not supported.\n"); 334 die("The attribute of frame base is not supported.\n");
334 deref = 1; 335 ref = true;
335 offs = op->number; 336 offs = op->number;
336 op = &pf->fb_ops[0]; 337 op = &pf->fb_ops[0];
337 } 338 }
@@ -339,13 +340,13 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
339 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { 340 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
340 regn = op->atom - DW_OP_breg0; 341 regn = op->atom - DW_OP_breg0;
341 offs += op->number; 342 offs += op->number;
342 deref = 1; 343 ref = true;
343 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { 344 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
344 regn = op->atom - DW_OP_reg0; 345 regn = op->atom - DW_OP_reg0;
345 } else if (op->atom == DW_OP_bregx) { 346 } else if (op->atom == DW_OP_bregx) {
346 regn = op->number; 347 regn = op->number;
347 offs += op->number2; 348 offs += op->number2;
348 deref = 1; 349 ref = true;
349 } else if (op->atom == DW_OP_regx) { 350 } else if (op->atom == DW_OP_regx) {
350 regn = op->number; 351 regn = op->number;
351 } else 352 } else
@@ -355,17 +356,15 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf)
355 if (!regs) 356 if (!regs)
356 die("%u exceeds max register number.", regn); 357 die("%u exceeds max register number.", regn);
357 358
358 if (deref) 359 tvar->value = xstrdup(regs);
359 ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", 360 if (ref) {
360 pf->var, (intmax_t)offs, regs); 361 tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref));
361 else 362 tvar->ref->offset = (long)offs;
362 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 363 }
363 DIE_IF(ret < 0);
364 DIE_IF(ret >= pf->len);
365} 364}
366 365
367/* Show a variables in kprobe event format */ 366/* Show a variables in kprobe event format */
368static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 367static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
369{ 368{
370 Dwarf_Attribute attr; 369 Dwarf_Attribute attr;
371 Dwarf_Op *expr; 370 Dwarf_Op *expr;
@@ -379,50 +378,51 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
379 if (ret <= 0 || nexpr == 0) 378 if (ret <= 0 || nexpr == 0)
380 goto error; 379 goto error;
381 380
382 show_location(expr, pf); 381 convert_location(expr, pf);
383 /* *expr will be cached in libdw. Don't free it. */ 382 /* *expr will be cached in libdw. Don't free it. */
384 return ; 383 return ;
385error: 384error:
386 /* TODO: Support const_value */ 385 /* TODO: Support const_value */
387 die("Failed to find the location of %s at this address.\n" 386 die("Failed to find the location of %s at this address.\n"
388 " Perhaps, it has been optimized out.", pf->var); 387 " Perhaps, it has been optimized out.", pf->pvar->name);
389} 388}
390 389
391/* Find a variable in a subprogram die */ 390/* Find a variable in a subprogram die */
392static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 391static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
393{ 392{
394 int ret;
395 Dwarf_Die vr_die; 393 Dwarf_Die vr_die;
396 394
397 /* TODO: Support struct members and arrays */ 395 /* TODO: Support struct members and arrays */
398 if (!is_c_varname(pf->var)) { 396 if (!is_c_varname(pf->pvar->name)) {
399 /* Output raw parameters */ 397 /* Copy raw parameters */
400 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 398 pf->tvar->value = xstrdup(pf->pvar->name);
401 DIE_IF(ret < 0); 399 } else {
402 DIE_IF(ret >= pf->len); 400 pf->tvar->name = xstrdup(pf->pvar->name);
403 return ; 401 pr_debug("Searching '%s' variable in context.\n",
402 pf->pvar->name);
403 /* Search child die for local variables and parameters. */
404 if (!die_find_variable(sp_die, pf->pvar->name, &vr_die))
405 die("Failed to find '%s' in this function.",
406 pf->pvar->name);
407 convert_variable(&vr_die, pf);
404 } 408 }
405
406 pr_debug("Searching '%s' variable in context.\n", pf->var);
407 /* Search child die for local variables and parameters. */
408 if (!die_find_variable(sp_die, pf->var, &vr_die))
409 die("Failed to find '%s' in this function.", pf->var);
410
411 show_variable(&vr_die, pf);
412} 409}
413 410
414/* Show a probe point to output buffer */ 411/* Show a probe point to output buffer */
415static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) 412static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
416{ 413{
417 struct probe_point *pp = pf->pp; 414 struct kprobe_trace_event *tev;
418 Dwarf_Addr eaddr; 415 Dwarf_Addr eaddr;
419 Dwarf_Die die_mem; 416 Dwarf_Die die_mem;
420 const char *name; 417 const char *name;
421 char tmp[MAX_PROBE_BUFFER]; 418 int ret, i;
422 int ret, i, len;
423 Dwarf_Attribute fb_attr; 419 Dwarf_Attribute fb_attr;
424 size_t nops; 420 size_t nops;
425 421
422 if (pf->ntevs == MAX_PROBES)
423 die("Too many( > %d) probe point found.\n", MAX_PROBES);
424 tev = &pf->tevs[pf->ntevs++];
425
426 /* If no real subprogram, find a real one */ 426 /* If no real subprogram, find a real one */
427 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { 427 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
428 sp_die = die_find_real_subprogram(&pf->cu_die, 428 sp_die = die_find_real_subprogram(&pf->cu_die,
@@ -431,31 +431,18 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
431 die("Probe point is not found in subprograms."); 431 die("Probe point is not found in subprograms.");
432 } 432 }
433 433
434 /* Output name of probe point */ 434 /* Copy the name of probe point */
435 name = dwarf_diename(sp_die); 435 name = dwarf_diename(sp_die);
436 if (name) { 436 if (name) {
437 dwarf_entrypc(sp_die, &eaddr); 437 dwarf_entrypc(sp_die, &eaddr);
438 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name, 438 tev->point.symbol = xstrdup(name);
439 (unsigned long)(pf->addr - eaddr)); 439 tev->point.offset = (unsigned long)(pf->addr - eaddr);
440 /* Copy the function name if possible */ 440 } else
441 if (!pp->function) {
442 pp->function = xstrdup(name);
443 pp->offset = (size_t)(pf->addr - eaddr);
444 }
445 } else {
446 /* This function has no name. */ 441 /* This function has no name. */
447 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", 442 tev->point.offset = (unsigned long)pf->addr;
448 (uintmax_t)pf->addr); 443
449 if (!pp->function) { 444 pr_debug("Probe point found: %s+%lu\n", tev->point.symbol,
450 /* TODO: Use _stext */ 445 tev->point.offset);
451 pp->function = xstrdup("");
452 pp->offset = (size_t)pf->addr;
453 }
454 }
455 DIE_IF(ret < 0);
456 DIE_IF(ret >= MAX_PROBE_BUFFER);
457 len = ret;
458 pr_debug("Probe point found: %s\n", tmp);
459 446
460 /* Get the frame base attribute/ops */ 447 /* Get the frame base attribute/ops */
461 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); 448 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
@@ -465,22 +452,16 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
465 452
466 /* Find each argument */ 453 /* Find each argument */
467 /* TODO: use dwarf_cfi_addrframe */ 454 /* TODO: use dwarf_cfi_addrframe */
468 for (i = 0; i < pp->nr_args; i++) { 455 tev->nargs = pf->pev->nargs;
469 pf->var = pp->args[i]; 456 tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs);
470 pf->buf = &tmp[len]; 457 for (i = 0; i < pf->pev->nargs; i++) {
471 pf->len = MAX_PROBE_BUFFER - len; 458 pf->pvar = &pf->pev->args[i];
459 pf->tvar = &tev->args[i];
472 find_variable(sp_die, pf); 460 find_variable(sp_die, pf);
473 len += strlen(pf->buf);
474 } 461 }
475 462
476 /* *pf->fb_ops will be cached in libdw. Don't free it. */ 463 /* *pf->fb_ops will be cached in libdw. Don't free it. */
477 pf->fb_ops = NULL; 464 pf->fb_ops = NULL;
478
479 if (pp->found == MAX_PROBES)
480 die("Too many( > %d) probe point found.\n", MAX_PROBES);
481
482 pp->probes[pp->found] = xstrdup(tmp);
483 pp->found++;
484} 465}
485 466
486/* Find probe point from its line number */ 467/* Find probe point from its line number */
@@ -512,7 +493,7 @@ static void find_probe_point_by_line(struct probe_finder *pf)
512 (int)i, lineno, (uintmax_t)addr); 493 (int)i, lineno, (uintmax_t)addr);
513 pf->addr = addr; 494 pf->addr = addr;
514 495
515 show_probe_point(NULL, pf); 496 convert_probe_point(NULL, pf);
516 /* Continuing, because target line might be inlined. */ 497 /* Continuing, because target line might be inlined. */
517 } 498 }
518} 499}
@@ -563,7 +544,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
563 if (list_empty(&pf->lcache)) { 544 if (list_empty(&pf->lcache)) {
564 /* Matching lazy line pattern */ 545 /* Matching lazy line pattern */
565 ret = find_lazy_match_lines(&pf->lcache, pf->fname, 546 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
566 pf->pp->lazy_line); 547 pf->pev->point.lazy_line);
567 if (ret <= 0) 548 if (ret <= 0)
568 die("No matched lines found in %s.", pf->fname); 549 die("No matched lines found in %s.", pf->fname);
569 } 550 }
@@ -596,7 +577,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
596 (int)i, lineno, (unsigned long long)addr); 577 (int)i, lineno, (unsigned long long)addr);
597 pf->addr = addr; 578 pf->addr = addr;
598 579
599 show_probe_point(sp_die, pf); 580 convert_probe_point(sp_die, pf);
600 /* Continuing, because target line might be inlined. */ 581 /* Continuing, because target line might be inlined. */
601 } 582 }
602 /* TODO: deallocate lines, but how? */ 583 /* TODO: deallocate lines, but how? */
@@ -605,7 +586,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
605static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 586static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
606{ 587{
607 struct probe_finder *pf = (struct probe_finder *)data; 588 struct probe_finder *pf = (struct probe_finder *)data;
608 struct probe_point *pp = pf->pp; 589 struct perf_probe_point *pp = &pf->pev->point;
609 590
610 if (pp->lazy_line) 591 if (pp->lazy_line)
611 find_probe_point_lazy(in_die, pf); 592 find_probe_point_lazy(in_die, pf);
@@ -616,7 +597,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
616 pr_debug("found inline addr: 0x%jx\n", 597 pr_debug("found inline addr: 0x%jx\n",
617 (uintmax_t)pf->addr); 598 (uintmax_t)pf->addr);
618 599
619 show_probe_point(in_die, pf); 600 convert_probe_point(in_die, pf);
620 } 601 }
621 602
622 return DWARF_CB_OK; 603 return DWARF_CB_OK;
@@ -626,7 +607,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
626static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 607static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
627{ 608{
628 struct probe_finder *pf = (struct probe_finder *)data; 609 struct probe_finder *pf = (struct probe_finder *)data;
629 struct probe_point *pp = pf->pp; 610 struct perf_probe_point *pp = &pf->pev->point;
630 611
631 /* Check tag and diename */ 612 /* Check tag and diename */
632 if (dwarf_tag(sp_die) != DW_TAG_subprogram || 613 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
@@ -646,7 +627,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
646 pf->addr = die_get_entrypc(sp_die); 627 pf->addr = die_get_entrypc(sp_die);
647 pf->addr += pp->offset; 628 pf->addr += pp->offset;
648 /* TODO: Check the address in this function */ 629 /* TODO: Check the address in this function */
649 show_probe_point(sp_die, pf); 630 convert_probe_point(sp_die, pf);
650 } 631 }
651 } else 632 } else
652 /* Inlined function: search instances */ 633 /* Inlined function: search instances */
@@ -660,20 +641,25 @@ static void find_probe_point_by_func(struct probe_finder *pf)
660 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); 641 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
661} 642}
662 643
663/* Find a probe point */ 644/* Find kprobe_trace_events specified by perf_probe_event from debuginfo */
664int find_probe_point(int fd, struct probe_point *pp) 645int find_kprobe_trace_events(int fd, struct perf_probe_event *pev,
646 struct kprobe_trace_event **tevs)
665{ 647{
666 struct probe_finder pf = {.pp = pp}; 648 struct probe_finder pf = {.pev = pev};
649 struct perf_probe_point *pp = &pev->point;
667 Dwarf_Off off, noff; 650 Dwarf_Off off, noff;
668 size_t cuhl; 651 size_t cuhl;
669 Dwarf_Die *diep; 652 Dwarf_Die *diep;
670 Dwarf *dbg; 653 Dwarf *dbg;
671 654
655 pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES);
656 *tevs = pf.tevs;
657 pf.ntevs = 0;
658
672 dbg = dwarf_begin(fd, DWARF_C_READ); 659 dbg = dwarf_begin(fd, DWARF_C_READ);
673 if (!dbg) 660 if (!dbg)
674 return -ENOENT; 661 return -ENOENT;
675 662
676 pp->found = 0;
677 off = 0; 663 off = 0;
678 line_list__init(&pf.lcache); 664 line_list__init(&pf.lcache);
679 /* Loop on CUs (Compilation Unit) */ 665 /* Loop on CUs (Compilation Unit) */
@@ -704,7 +690,7 @@ int find_probe_point(int fd, struct probe_point *pp)
704 line_list__free(&pf.lcache); 690 line_list__free(&pf.lcache);
705 dwarf_end(dbg); 691 dwarf_end(dbg);
706 692
707 return pp->found; 693 return pf.ntevs;
708} 694}
709 695
710/* Find line range from its line number */ 696/* Find line range from its line number */