Skip to content

Commit b0ef073

Browse files
Masami HiramatsuIngo Molnar
authored andcommitted
perf/probes: Support function entry relative line number
Add function-entry relative line number specifying support to perf-probe. This allows users to define probes by line number from entry of the function. e.g. perf probe schedule:16 Signed-off-by: Masami Hiramatsu <[email protected]> Cc: Steven Rostedt <[email protected]> Cc: Jim Keniston <[email protected]> Cc: Ananth N Mavinakayanahalli <[email protected]> Cc: Christoph Hellwig <[email protected]> Cc: Frank Ch. Eigler <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: Jason Baron <[email protected]> Cc: K.Prasad <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Srikar Dronamraju <[email protected]> LKML-Reference: <20091027204319.30545.30678.stgit@harusame> Signed-off-by: Ingo Molnar <[email protected]>
1 parent 253977b commit b0ef073

File tree

3 files changed

+70
-25
lines changed

3 files changed

+70
-25
lines changed

tools/perf/builtin-probe.c

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,17 +133,16 @@ static void parse_probe_point(char *arg, struct probe_point *pp)
133133
}
134134

135135
/* Exclusion check */
136-
if (pp->line && pp->function)
137-
semantic_error("Function-relative line number is not"
138-
" supported yet.");
136+
if (pp->line && pp->offset)
137+
semantic_error("Offset can't be used with line number.");
139138
if (!pp->line && pp->file && !pp->function)
140139
semantic_error("File always requires line number.");
141140
if (pp->offset && !pp->function)
142141
semantic_error("Offset requires an entry function.");
143142
if (pp->retprobe && !pp->function)
144143
semantic_error("Return probe requires an entry function.");
145-
if (pp->offset && pp->retprobe)
146-
semantic_error("Offset can't be used with return probe.");
144+
if ((pp->offset || pp->line) && pp->retprobe)
145+
semantic_error("Offset/Line can't be used with return probe.");
147146

148147
pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n",
149148
pp->function, pp->file, pp->line, pp->offset, pp->retprobe);
@@ -270,7 +269,7 @@ static const struct option options[] = {
270269
#ifdef NO_LIBDWARF
271270
"FUNC[+OFFS|%return] [ARG ...]",
272271
#else
273-
"FUNC[+OFFS|%return][@SRC]|SRC:LINE [ARG ...]",
272+
"FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]",
274273
#endif
275274
"probe point definition, where\n"
276275
"\t\tGRP:\tGroup name (optional)\n"
@@ -282,7 +281,8 @@ static const struct option options[] = {
282281
"\t\tARG:\tProbe argument (only \n"
283282
#else
284283
"\t\tSRC:\tSource code path\n"
285-
"\t\tLINE:\tLine number\n"
284+
"\t\tRLN:\tRelative line number from function entry.\n"
285+
"\t\tALN:\tAbsolute line number in file.\n"
286286
"\t\tARG:\tProbe argument (local variable name or\n"
287287
#endif
288288
"\t\t\tkprobe-tracer argument format is supported.)\n",

tools/perf/util/probe-finder.c

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ static int strtailcmp(const char *s1, const char *s2)
114114
}
115115

116116
/* Find the fileno of the target file. */
117-
static Dwarf_Unsigned die_get_fileno(Dwarf_Die cu_die, const char *fname)
117+
static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118118
{
119119
Dwarf_Signed cnt, i;
120120
Dwarf_Unsigned found = 0;
@@ -335,6 +335,36 @@ static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc,
335335
return ret;
336336
}
337337

338+
/* Get decl_file attribute value (file number) */
339+
static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die)
340+
{
341+
Dwarf_Attribute attr;
342+
Dwarf_Unsigned fno;
343+
int ret;
344+
345+
ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error);
346+
DIE_IF(ret != DW_DLV_OK);
347+
dwarf_formudata(attr, &fno, &__dw_error);
348+
DIE_IF(ret != DW_DLV_OK);
349+
dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
350+
return fno;
351+
}
352+
353+
/* Get decl_line attribute value (line number) */
354+
static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
355+
{
356+
Dwarf_Attribute attr;
357+
Dwarf_Unsigned lno;
358+
int ret;
359+
360+
ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error);
361+
DIE_IF(ret != DW_DLV_OK);
362+
dwarf_formudata(attr, &lno, &__dw_error);
363+
DIE_IF(ret != DW_DLV_OK);
364+
dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
365+
return lno;
366+
}
367+
338368
/*
339369
* Probe finder related functions
340370
*/
@@ -501,6 +531,7 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
501531
DIE_IF(ret < 0);
502532
DIE_IF(ret >= MAX_PROBE_BUFFER);
503533
len = ret;
534+
pr_debug("Probe point found: %s\n", tmp);
504535

505536
/* Find each argument */
506537
get_current_frame_base(sp_die, pf);
@@ -536,17 +567,16 @@ static int probeaddr_callback(struct die_link *dlink, void *data)
536567
}
537568

538569
/* Find probe point from its line number */
539-
static void find_by_line(Dwarf_Die cu_die, struct probe_finder *pf)
570+
static void find_by_line(struct probe_finder *pf)
540571
{
541-
struct probe_point *pp = pf->pp;
542-
Dwarf_Signed cnt, i;
572+
Dwarf_Signed cnt, i, clm;
543573
Dwarf_Line *lines;
544574
Dwarf_Unsigned lineno = 0;
545575
Dwarf_Addr addr;
546576
Dwarf_Unsigned fno;
547577
int ret;
548578

549-
ret = dwarf_srclines(cu_die, &lines, &cnt, &__dw_error);
579+
ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error);
550580
DIE_IF(ret != DW_DLV_OK);
551581

552582
for (i = 0; i < cnt; i++) {
@@ -557,15 +587,20 @@ static void find_by_line(Dwarf_Die cu_die, struct probe_finder *pf)
557587

558588
ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
559589
DIE_IF(ret != DW_DLV_OK);
560-
if (lineno != (Dwarf_Unsigned)pp->line)
590+
if (lineno != pf->lno)
561591
continue;
562592

593+
ret = dwarf_lineoff(lines[i], &clm, &__dw_error);
594+
DIE_IF(ret != DW_DLV_OK);
595+
563596
ret = dwarf_lineaddr(lines[i], &addr, &__dw_error);
564597
DIE_IF(ret != DW_DLV_OK);
565-
pr_debug("Probe point found: 0x%llx\n", addr);
598+
pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
599+
(int)i, (unsigned)lineno, (int)clm, addr);
566600
pf->addr = addr;
567601
/* Search a real subprogram including this line, */
568-
ret = search_die_from_children(cu_die, probeaddr_callback, pf);
602+
ret = search_die_from_children(pf->cu_die,
603+
probeaddr_callback, pf);
569604
if (ret == 0)
570605
die("Probe point is not found in subprograms.\n");
571606
/* Continuing, because target line might be inlined. */
@@ -587,6 +622,13 @@ static int probefunc_callback(struct die_link *dlink, void *data)
587622
DIE_IF(ret == DW_DLV_ERROR);
588623
if (tag == DW_TAG_subprogram) {
589624
if (die_compare_name(dlink->die, pp->function) == 0) {
625+
if (pp->line) { /* Function relative line */
626+
pf->fno = die_get_decl_file(dlink->die);
627+
pf->lno = die_get_decl_line(dlink->die)
628+
+ pp->line;
629+
find_by_line(pf);
630+
return 1;
631+
}
590632
if (die_inlined_subprogram(dlink->die)) {
591633
/* Inlined function, save it. */
592634
ret = dwarf_die_CU_offset(dlink->die,
@@ -631,17 +673,16 @@ static int probefunc_callback(struct die_link *dlink, void *data)
631673
return 0;
632674
}
633675

634-
static void find_by_func(Dwarf_Die cu_die, struct probe_finder *pf)
676+
static void find_by_func(struct probe_finder *pf)
635677
{
636-
search_die_from_children(cu_die, probefunc_callback, pf);
678+
search_die_from_children(pf->cu_die, probefunc_callback, pf);
637679
}
638680

639681
/* Find a probe point */
640682
int find_probepoint(int fd, struct probe_point *pp)
641683
{
642684
Dwarf_Half addr_size = 0;
643685
Dwarf_Unsigned next_cuh = 0;
644-
Dwarf_Die cu_die = 0;
645686
int cu_number = 0, ret;
646687
struct probe_finder pf = {.pp = pp};
647688

@@ -659,25 +700,27 @@ int find_probepoint(int fd, struct probe_point *pp)
659700
break;
660701

661702
/* Get the DIE(Debugging Information Entry) of this CU */
662-
ret = dwarf_siblingof(__dw_debug, 0, &cu_die, &__dw_error);
703+
ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error);
663704
DIE_IF(ret != DW_DLV_OK);
664705

665706
/* Check if target file is included. */
666707
if (pp->file)
667-
pf.fno = die_get_fileno(cu_die, pp->file);
708+
pf.fno = cu_find_fileno(pf.cu_die, pp->file);
668709

669710
if (!pp->file || pf.fno) {
670711
/* Save CU base address (for frame_base) */
671-
ret = dwarf_lowpc(cu_die, &pf.cu_base, &__dw_error);
712+
ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error);
672713
DIE_IF(ret == DW_DLV_ERROR);
673714
if (ret == DW_DLV_NO_ENTRY)
674715
pf.cu_base = 0;
675-
if (pp->line)
676-
find_by_line(cu_die, &pf);
677716
if (pp->function)
678-
find_by_func(cu_die, &pf);
717+
find_by_func(&pf);
718+
else {
719+
pf.lno = pp->line;
720+
find_by_line(&pf);
721+
}
679722
}
680-
dwarf_dealloc(__dw_debug, cu_die, DW_DLA_DIE);
723+
dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE);
681724
}
682725
ret = dwarf_finish(__dw_debug, &__dw_error);
683726
DIE_IF(ret != DW_DLV_OK);

tools/perf/util/probe-finder.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@ struct probe_finder {
4141
/* For function searching */
4242
Dwarf_Addr addr; /* Address */
4343
Dwarf_Unsigned fno; /* File number */
44+
Dwarf_Unsigned lno; /* Line number */
4445
Dwarf_Off inl_offs; /* Inline offset */
46+
Dwarf_Die cu_die; /* Current CU */
4547

4648
/* For variable searching */
4749
Dwarf_Addr cu_base; /* Current CU base address */

0 commit comments

Comments
 (0)