aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2010-03-09 11:11:53 -0500
committerIngo Molnar <mingo@elte.hu>2010-03-09 11:11:53 -0500
commit548b84166917d6f5e2296123b85ad24aecd3801d (patch)
tree0ab0300e23a02df0fe3c0579627e4998bb122c00 /tools/perf
parentcfb581bcd4f8c158c6f2b48bf5e232bb9e6855c0 (diff)
parent57d54889cd00db2752994b389ba714138652e60c (diff)
Merge commit 'v2.6.34-rc1' into perf/urgent
Conflicts: tools/perf/util/probe-event.c Merge reason: Pick up -rc1 and resolve the conflict as well. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-probe.txt58
-rw-r--r--tools/perf/Makefile10
-rw-r--r--tools/perf/builtin-probe.c36
-rw-r--r--tools/perf/util/probe-event.c55
-rw-r--r--tools/perf/util/probe-finder.c1002
-rw-r--r--tools/perf/util/probe-finder.h53
-rw-r--r--tools/perf/util/string.c55
-rw-r--r--tools/perf/util/string.h1
8 files changed, 644 insertions, 626 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index 2de34075f6a4..34202b1be0bb 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -41,7 +41,8 @@ OPTIONS
41 41
42-d:: 42-d::
43--del=:: 43--del=::
44 Delete a probe event. 44 Delete probe events. This accepts glob wildcards('*', '?') and character
45 classes(e.g. [a-z], [!A-Z]).
45 46
46-l:: 47-l::
47--list:: 48--list::
@@ -50,17 +51,29 @@ OPTIONS
50-L:: 51-L::
51--line=:: 52--line=::
52 Show source code lines which can be probed. This needs an argument 53 Show source code lines which can be probed. This needs an argument
53 which specifies a range of the source code. 54 which specifies a range of the source code. (see LINE SYNTAX for detail)
55
56-f::
57--force::
58 Forcibly add events with existing name.
54 59
55PROBE SYNTAX 60PROBE SYNTAX
56------------ 61------------
57Probe points are defined by following syntax. 62Probe points are defined by following syntax.
58 63
59 "[EVENT=]FUNC[+OFFS|:RLN|%return][@SRC]|SRC:ALN [ARG ...]" 64 1) Define event based on function name
65 [EVENT=]FUNC[@SRC][:RLN|+OFFS|%return|;PTN] [ARG ...]
66
67 2) Define event based on source file with line number
68 [EVENT=]SRC:ALN [ARG ...]
69
70 3) Define event based on source file with lazy pattern
71 [EVENT=]SRC;PTN [ARG ...]
72
60 73
61'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'. 74'EVENT' specifies the name of new event, if omitted, it will be set the name of the probed function. Currently, event group name is set as 'probe'.
62'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, 'RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. In addition, 'SRC' specifies a source file which has that function. 75'FUNC' specifies a probed function name, and it may have one of the following options; '+OFFS' is the offset from function entry address in bytes, ':RLN' is the relative-line number from function entry line, and '%return' means that it probes function return. And ';PTN' means lazy matching pattern (see LAZY MATCHING). Note that ';PTN' must be the end of the probe point definition. In addition, '@SRC' specifies a source file which has that function.
63It is also possible to specify a probe point by the source line number by using 'SRC:ALN' syntax, where 'SRC' is the source file path and 'ALN' is the line number. 76It is also possible to specify a probe point by the source line number or lazy matching by using 'SRC:ALN' or 'SRC;PTN' syntax, where 'SRC' is the source file path, ':ALN' is the line number and ';PTN' is the lazy matching pattern.
64'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc). 77'ARG' specifies the arguments of this probe point. You can use the name of local variable, or kprobe-tracer argument format (e.g. $retval, %ax, etc).
65 78
66LINE SYNTAX 79LINE SYNTAX
@@ -76,6 +89,41 @@ and 'ALN2' is end line number in the file. It is also possible to specify how
76many lines to show by using 'NUM'. 89many lines to show by using 'NUM'.
77So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function. 90So, "source.c:100-120" shows lines between 100th to l20th in source.c file. And "func:10+20" shows 20 lines from 10th line of func function.
78 91
92LAZY MATCHING
93-------------
94 The lazy line matching is similar to glob matching but ignoring spaces in both of pattern and target. So this accepts wildcards('*', '?') and character classes(e.g. [a-z], [!A-Z]).
95
96e.g.
97 'a=*' can matches 'a=b', 'a = b', 'a == b' and so on.
98
99This provides some sort of flexibility and robustness to probe point definitions against minor code changes. For example, actual 10th line of schedule() can be moved easily by modifying schedule(), but the same line matching 'rq=cpu_rq*' may still exist in the function.)
100
101
102EXAMPLES
103--------
104Display which lines in schedule() can be probed:
105
106 ./perf probe --line schedule
107
108Add a probe on schedule() function 12th line with recording cpu local variable:
109
110 ./perf probe schedule:12 cpu
111 or
112 ./perf probe --add='schedule:12 cpu'
113
114 this will add one or more probes which has the name start with "schedule".
115
116 Add probes on lines in schedule() function which calls update_rq_clock().
117
118 ./perf probe 'schedule;update_rq_clock*'
119 or
120 ./perf probe --add='schedule;update_rq_clock*'
121
122Delete all probes on schedule().
123
124 ./perf probe --del='schedule*'
125
126
79SEE ALSO 127SEE ALSO
80-------- 128--------
81linkperf:perf-trace[1], linkperf:perf-record[1] 129linkperf:perf-trace[1], linkperf:perf-record[1]
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 54a5b50ff312..2d537382c686 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -500,12 +500,12 @@ else
500 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]); 500 msg := $(error No libelf.h/libelf found, please install libelf-dev/elfutils-libelf-devel and glibc-dev[el]);
501endif 501endif
502 502
503ifneq ($(shell sh -c "(echo '\#ifndef _MIPS_SZLONG'; echo '\#define _MIPS_SZLONG 0'; echo '\#endif'; echo '\#include <dwarf.h>'; echo '\#include <libdwarf.h>'; echo 'int main(void) { Dwarf_Debug dbg; Dwarf_Error err; Dwarf_Ranges *rng; dwarf_init(0, DW_DLC_READ, 0, 0, &dbg, &err); dwarf_get_ranges(dbg, 0, &rng, 0, 0, &err); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/libdwarf -ldwarf -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) 503ifneq ($(shell sh -c "(echo '\#include <dwarf.h>'; echo '\#include <libdw.h>'; echo 'int main(void) { Dwarf *dbg; dbg = dwarf_begin(0, DWARF_C_READ); return (long)dbg; }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -I/usr/include/elfutils -ldw -lelf -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y)
504 msg := $(warning No libdwarf.h found or old libdwarf.h found, disables dwarf support. Please install libdwarf-dev/libdwarf-devel >= 20081231); 504 msg := $(warning No libdw.h found or old libdw.h found, disables dwarf support. Please install elfutils-devel/elfutils-dev);
505 BASIC_CFLAGS += -DNO_LIBDWARF 505 BASIC_CFLAGS += -DNO_DWARF_SUPPORT
506else 506else
507 BASIC_CFLAGS += -I/usr/include/libdwarf 507 BASIC_CFLAGS += -I/usr/include/elfutils
508 EXTLIBS += -lelf -ldwarf 508 EXTLIBS += -lelf -ldw
509 LIB_OBJS += util/probe-finder.o 509 LIB_OBJS += util/probe-finder.o
510endif 510endif
511 511
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index ad47bd4c50ef..c30a33592340 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -128,7 +128,7 @@ static void evaluate_probe_point(struct probe_point *pp)
128 pp->function); 128 pp->function);
129} 129}
130 130
131#ifndef NO_LIBDWARF 131#ifndef NO_DWARF_SUPPORT
132static int open_vmlinux(void) 132static int open_vmlinux(void)
133{ 133{
134 if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) { 134 if (map__load(session.kmaps[MAP__FUNCTION], NULL) < 0) {
@@ -156,14 +156,16 @@ static const char * const probe_usage[] = {
156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]", 156 "perf probe [<options>] --add 'PROBEDEF' [--add 'PROBEDEF' ...]",
157 "perf probe [<options>] --del '[GROUP:]EVENT' ...", 157 "perf probe [<options>] --del '[GROUP:]EVENT' ...",
158 "perf probe --list", 158 "perf probe --list",
159#ifndef NO_DWARF_SUPPORT
159 "perf probe --line 'LINEDESC'", 160 "perf probe --line 'LINEDESC'",
161#endif
160 NULL 162 NULL
161}; 163};
162 164
163static const struct option options[] = { 165static const struct option options[] = {
164 OPT_BOOLEAN('v', "verbose", &verbose, 166 OPT_BOOLEAN('v', "verbose", &verbose,
165 "be more verbose (show parsed arguments, etc)"), 167 "be more verbose (show parsed arguments, etc)"),
166#ifndef NO_LIBDWARF 168#ifndef NO_DWARF_SUPPORT
167 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name, 169 OPT_STRING('k', "vmlinux", &symbol_conf.vmlinux_name,
168 "file", "vmlinux pathname"), 170 "file", "vmlinux pathname"),
169#endif 171#endif
@@ -172,30 +174,32 @@ static const struct option options[] = {
172 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.", 174 OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
173 opt_del_probe_event), 175 opt_del_probe_event),
174 OPT_CALLBACK('a', "add", NULL, 176 OPT_CALLBACK('a', "add", NULL,
175#ifdef NO_LIBDWARF 177#ifdef NO_DWARF_SUPPORT
176 "[EVENT=]FUNC[+OFFS|%return] [ARG ...]", 178 "[EVENT=]FUNC[+OFF|%return] [ARG ...]",
177#else 179#else
178 "[EVENT=]FUNC[+OFFS|%return|:RLN][@SRC]|SRC:ALN [ARG ...]", 180 "[EVENT=]FUNC[@SRC][+OFF|%return|:RL|;PT]|SRC:AL|SRC;PT"
181 " [ARG ...]",
179#endif 182#endif
180 "probe point definition, where\n" 183 "probe point definition, where\n"
181 "\t\tGROUP:\tGroup name (optional)\n" 184 "\t\tGROUP:\tGroup name (optional)\n"
182 "\t\tEVENT:\tEvent name\n" 185 "\t\tEVENT:\tEvent name\n"
183 "\t\tFUNC:\tFunction name\n" 186 "\t\tFUNC:\tFunction name\n"
184 "\t\tOFFS:\tOffset from function entry (in byte)\n" 187 "\t\tOFF:\tOffset from function entry (in byte)\n"
185 "\t\t%return:\tPut the probe at function return\n" 188 "\t\t%return:\tPut the probe at function return\n"
186#ifdef NO_LIBDWARF 189#ifdef NO_DWARF_SUPPORT
187 "\t\tARG:\tProbe argument (only \n" 190 "\t\tARG:\tProbe argument (only \n"
188#else 191#else
189 "\t\tSRC:\tSource code path\n" 192 "\t\tSRC:\tSource code path\n"
190 "\t\tRLN:\tRelative line number from function entry.\n" 193 "\t\tRL:\tRelative line number from function entry.\n"
191 "\t\tALN:\tAbsolute line number in file.\n" 194 "\t\tAL:\tAbsolute line number in file.\n"
195 "\t\tPT:\tLazy expression of line code.\n"
192 "\t\tARG:\tProbe argument (local variable name or\n" 196 "\t\tARG:\tProbe argument (local variable name or\n"
193#endif 197#endif
194 "\t\t\tkprobe-tracer argument format.)\n", 198 "\t\t\tkprobe-tracer argument format.)\n",
195 opt_add_probe_event), 199 opt_add_probe_event),
196 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events" 200 OPT_BOOLEAN('f', "force", &session.force_add, "forcibly add events"
197 " with existing name"), 201 " with existing name"),
198#ifndef NO_LIBDWARF 202#ifndef NO_DWARF_SUPPORT
199 OPT_CALLBACK('L', "line", NULL, 203 OPT_CALLBACK('L', "line", NULL,
200 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]", 204 "FUNC[:RLN[+NUM|:RLN2]]|SRC:ALN[+NUM|:ALN2]",
201 "Show source code lines.", opt_show_lines), 205 "Show source code lines.", opt_show_lines),
@@ -223,7 +227,7 @@ static void init_vmlinux(void)
223int cmd_probe(int argc, const char **argv, const char *prefix __used) 227int cmd_probe(int argc, const char **argv, const char *prefix __used)
224{ 228{
225 int i, ret; 229 int i, ret;
226#ifndef NO_LIBDWARF 230#ifndef NO_DWARF_SUPPORT
227 int fd; 231 int fd;
228#endif 232#endif
229 struct probe_point *pp; 233 struct probe_point *pp;
@@ -259,7 +263,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
259 return 0; 263 return 0;
260 } 264 }
261 265
262#ifndef NO_LIBDWARF 266#ifndef NO_DWARF_SUPPORT
263 if (session.show_lines) { 267 if (session.show_lines) {
264 if (session.nr_probe != 0 || session.dellist) { 268 if (session.nr_probe != 0 || session.dellist) {
265 pr_warning(" Error: Don't use --line with" 269 pr_warning(" Error: Don't use --line with"
@@ -290,9 +294,9 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
290 init_vmlinux(); 294 init_vmlinux();
291 295
292 if (session.need_dwarf) 296 if (session.need_dwarf)
293#ifdef NO_LIBDWARF 297#ifdef NO_DWARF_SUPPORT
294 die("Debuginfo-analysis is not supported"); 298 die("Debuginfo-analysis is not supported");
295#else /* !NO_LIBDWARF */ 299#else /* !NO_DWARF_SUPPORT */
296 pr_debug("Some probes require debuginfo.\n"); 300 pr_debug("Some probes require debuginfo.\n");
297 301
298 fd = open_vmlinux(); 302 fd = open_vmlinux();
@@ -312,7 +316,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
312 continue; 316 continue;
313 317
314 lseek(fd, SEEK_SET, 0); 318 lseek(fd, SEEK_SET, 0);
315 ret = find_probepoint(fd, pp); 319 ret = find_probe_point(fd, pp);
316 if (ret > 0) 320 if (ret > 0)
317 continue; 321 continue;
318 if (ret == 0) { /* No error but failed to find probe point. */ 322 if (ret == 0) { /* No error but failed to find probe point. */
@@ -333,7 +337,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used)
333 close(fd); 337 close(fd);
334 338
335end_dwarf: 339end_dwarf:
336#endif /* !NO_LIBDWARF */ 340#endif /* !NO_DWARF_SUPPORT */
337 341
338 /* Synthesize probes without dwarf */ 342 /* Synthesize probes without dwarf */
339 for (i = 0; i < session.nr_probe; i++) { 343 for (i = 0; i < session.nr_probe; i++) {
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index a21b6bf055ac..53181dbfe4a8 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -119,14 +119,14 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
119 char c, nc = 0; 119 char c, nc = 0;
120 /* 120 /*
121 * <Syntax> 121 * <Syntax>
122 * perf probe [EVENT=]SRC:LN 122 * perf probe [EVENT=]SRC[:LN|;PTN]
123 * perf probe [EVENT=]FUNC[+OFFS|%return][@SRC] 123 * perf probe [EVENT=]FUNC[@SRC][+OFFS|%return|:LN|;PAT]
124 * 124 *
125 * TODO:Group name support 125 * TODO:Group name support
126 */ 126 */
127 127
128 ptr = strchr(arg, '='); 128 ptr = strpbrk(arg, ";=@+%");
129 if (ptr) { /* Event name */ 129 if (ptr && *ptr == '=') { /* Event name */
130 *ptr = '\0'; 130 *ptr = '\0';
131 tmp = ptr + 1; 131 tmp = ptr + 1;
132 ptr = strchr(arg, ':'); 132 ptr = strchr(arg, ':');
@@ -139,7 +139,7 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
139 arg = tmp; 139 arg = tmp;
140 } 140 }
141 141
142 ptr = strpbrk(arg, ":+@%"); 142 ptr = strpbrk(arg, ";:+@%");
143 if (ptr) { 143 if (ptr) {
144 nc = *ptr; 144 nc = *ptr;
145 *ptr++ = '\0'; 145 *ptr++ = '\0';
@@ -156,7 +156,11 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
156 while (ptr) { 156 while (ptr) {
157 arg = ptr; 157 arg = ptr;
158 c = nc; 158 c = nc;
159 ptr = strpbrk(arg, ":+@%"); 159 if (c == ';') { /* Lazy pattern must be the last part */
160 pp->lazy_line = strdup(arg);
161 break;
162 }
163 ptr = strpbrk(arg, ";:+@%");
160 if (ptr) { 164 if (ptr) {
161 nc = *ptr; 165 nc = *ptr;
162 *ptr++ = '\0'; 166 *ptr++ = '\0';
@@ -165,13 +169,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
165 case ':': /* Line number */ 169 case ':': /* Line number */
166 pp->line = strtoul(arg, &tmp, 0); 170 pp->line = strtoul(arg, &tmp, 0);
167 if (*tmp != '\0') 171 if (*tmp != '\0')
168 semantic_error("There is non-digit charactor" 172 semantic_error("There is non-digit char"
169 " in line number."); 173 " in line number.");
170 break; 174 break;
171 case '+': /* Byte offset from a symbol */ 175 case '+': /* Byte offset from a symbol */
172 pp->offset = strtoul(arg, &tmp, 0); 176 pp->offset = strtoul(arg, &tmp, 0);
173 if (*tmp != '\0') 177 if (*tmp != '\0')
174 semantic_error("There is non-digit charactor" 178 semantic_error("There is non-digit character"
175 " in offset."); 179 " in offset.");
176 break; 180 break;
177 case '@': /* File name */ 181 case '@': /* File name */
@@ -179,9 +183,6 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
179 semantic_error("SRC@SRC is not allowed."); 183 semantic_error("SRC@SRC is not allowed.");
180 pp->file = strdup(arg); 184 pp->file = strdup(arg);
181 DIE_IF(pp->file == NULL); 185 DIE_IF(pp->file == NULL);
182 if (ptr)
183 semantic_error("@SRC must be the last "
184 "option.");
185 break; 186 break;
186 case '%': /* Probe places */ 187 case '%': /* Probe places */
187 if (strcmp(arg, "return") == 0) { 188 if (strcmp(arg, "return") == 0) {
@@ -196,11 +197,18 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
196 } 197 }
197 198
198 /* Exclusion check */ 199 /* Exclusion check */
200 if (pp->lazy_line && pp->line)
201 semantic_error("Lazy pattern can't be used with line number.");
202
203 if (pp->lazy_line && pp->offset)
204 semantic_error("Lazy pattern can't be used with offset.");
205
199 if (pp->line && pp->offset) 206 if (pp->line && pp->offset)
200 semantic_error("Offset can't be used with line number."); 207 semantic_error("Offset can't be used with line number.");
201 208
202 if (!pp->line && pp->file && !pp->function) 209 if (!pp->line && !pp->lazy_line && pp->file && !pp->function)
203 semantic_error("File always requires line number."); 210 semantic_error("File always requires line number or "
211 "lazy pattern.");
204 212
205 if (pp->offset && !pp->function) 213 if (pp->offset && !pp->function)
206 semantic_error("Offset requires an entry function."); 214 semantic_error("Offset requires an entry function.");
@@ -208,11 +216,13 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp)
208 if (pp->retprobe && !pp->function) 216 if (pp->retprobe && !pp->function)
209 semantic_error("Return probe requires an entry function."); 217 semantic_error("Return probe requires an entry function.");
210 218
211 if ((pp->offset || pp->line) && pp->retprobe) 219 if ((pp->offset || pp->line || pp->lazy_line) && pp->retprobe)
212 semantic_error("Offset/Line can't be used with return probe."); 220 semantic_error("Offset/Line/Lazy pattern can't be used with "
221 "return probe.");
213 222
214 pr_debug("symbol:%s file:%s line:%d offset:%d, return:%d\n", 223 pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n",
215 pp->function, pp->file, pp->line, pp->offset, pp->retprobe); 224 pp->function, pp->file, pp->line, pp->offset, pp->retprobe,
225 pp->lazy_line);
216} 226}
217 227
218/* Parse perf-probe event definition */ 228/* Parse perf-probe event definition */
@@ -458,6 +468,8 @@ static void clear_probe_point(struct probe_point *pp)
458 free(pp->function); 468 free(pp->function);
459 if (pp->file) 469 if (pp->file)
460 free(pp->file); 470 free(pp->file);
471 if (pp->lazy_line)
472 free(pp->lazy_line);
461 for (i = 0; i < pp->nr_args; i++) 473 for (i = 0; i < pp->nr_args; i++)
462 free(pp->args[i]); 474 free(pp->args[i]);
463 if (pp->args) 475 if (pp->args)
@@ -719,6 +731,7 @@ void del_trace_kprobe_events(struct strlist *dellist)
719} 731}
720 732
721#define LINEBUF_SIZE 256 733#define LINEBUF_SIZE 256
734#define NR_ADDITIONAL_LINES 2
722 735
723static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) 736static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num)
724{ 737{
@@ -779,5 +792,11 @@ void show_line_range(struct line_range *lr)
779 show_one_line(fp, (l++) - lr->offset, false, false); 792 show_one_line(fp, (l++) - lr->offset, false, false);
780 show_one_line(fp, (l++) - lr->offset, false, true); 793 show_one_line(fp, (l++) - lr->offset, false, true);
781 } 794 }
795
796 if (lr->end == INT_MAX)
797 lr->end = l + NR_ADDITIONAL_LINES;
798 while (l < lr->end && !feof(fp))
799 show_one_line(fp, (l++) - lr->offset, false, false);
800
782 fclose(fp); 801 fclose(fp);
783} 802}
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 1b2124d12f68..e77dc886760e 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -32,21 +32,13 @@
32#include <stdarg.h> 32#include <stdarg.h>
33#include <ctype.h> 33#include <ctype.h>
34 34
35#include "string.h"
35#include "event.h" 36#include "event.h"
36#include "debug.h" 37#include "debug.h"
37#include "util.h" 38#include "util.h"
38#include "probe-finder.h" 39#include "probe-finder.h"
39 40
40 41
41/* Dwarf_Die Linkage to parent Die */
42struct die_link {
43 struct die_link *parent; /* Parent die */
44 Dwarf_Die die; /* Current die */
45};
46
47static Dwarf_Debug __dw_debug;
48static Dwarf_Error __dw_error;
49
50/* 42/*
51 * Generic dwarf analysis helpers 43 * Generic dwarf analysis helpers
52 */ 44 */
@@ -113,281 +105,190 @@ static int strtailcmp(const char *s1, const char *s2)
113 return 0; 105 return 0;
114} 106}
115 107
116/* Find the fileno of the target file. */ 108/* Line number list operations */
117static Dwarf_Unsigned cu_find_fileno(Dwarf_Die cu_die, const char *fname)
118{
119 Dwarf_Signed cnt, i;
120 Dwarf_Unsigned found = 0;
121 char **srcs;
122 int ret;
123 109
124 if (!fname) 110/* Add a line to line number list */
125 return 0; 111static void line_list__add_line(struct list_head *head, unsigned int line)
112{
113 struct line_node *ln;
114 struct list_head *p;
126 115
127 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 116 /* Reverse search, because new line will be the last one */
128 if (ret == DW_DLV_OK) { 117 list_for_each_entry_reverse(ln, head, list) {
129 for (i = 0; i < cnt && !found; i++) { 118 if (ln->line < line) {
130 if (strtailcmp(srcs[i], fname) == 0) 119 p = &ln->list;
131 found = i + 1; 120 goto found;
132 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING); 121 } else if (ln->line == line) /* Already exist */
133 } 122 return ;
134 for (; i < cnt; i++)
135 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
136 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
137 } 123 }
138 if (found) 124 /* List is empty, or the smallest entry */
139 pr_debug("found fno: %d\n", (int)found); 125 p = head;
140 return found; 126found:
127 pr_debug("line list: add a line %u\n", line);
128 ln = zalloc(sizeof(struct line_node));
129 DIE_IF(ln == NULL);
130 ln->line = line;
131 INIT_LIST_HEAD(&ln->list);
132 list_add(&ln->list, p);
141} 133}
142 134
143static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf) 135/* Check if the line in line number list */
136static int line_list__has_line(struct list_head *head, unsigned int line)
144{ 137{
145 Dwarf_Signed cnt, i; 138 struct line_node *ln;
146 char **srcs; 139
147 int ret = 0; 140 /* Reverse search, because new line will be the last one */
148 141 list_for_each_entry(ln, head, list)
149 if (!buf || !fno) 142 if (ln->line == line)
150 return -EINVAL; 143 return 1;
151 144
152 ret = dwarf_srcfiles(cu_die, &srcs, &cnt, &__dw_error); 145 return 0;
153 if (ret == DW_DLV_OK) {
154 if ((Dwarf_Unsigned)cnt > fno - 1) {
155 *buf = strdup(srcs[fno - 1]);
156 ret = 0;
157 pr_debug("found filename: %s\n", *buf);
158 } else
159 ret = -ENOENT;
160 for (i = 0; i < cnt; i++)
161 dwarf_dealloc(__dw_debug, srcs[i], DW_DLA_STRING);
162 dwarf_dealloc(__dw_debug, srcs, DW_DLA_LIST);
163 } else
164 ret = -EINVAL;
165 return ret;
166} 146}
167 147
168/* Compare diename and tname */ 148/* Init line number list */
169static int die_compare_name(Dwarf_Die dw_die, const char *tname) 149static void line_list__init(struct list_head *head)
170{ 150{
171 char *name; 151 INIT_LIST_HEAD(head);
172 int ret;
173 ret = dwarf_diename(dw_die, &name, &__dw_error);
174 DIE_IF(ret == DW_DLV_ERROR);
175 if (ret == DW_DLV_OK) {
176 ret = strcmp(tname, name);
177 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
178 } else
179 ret = -1;
180 return ret;
181} 152}
182 153
183/* Check the address is in the subprogram(function). */ 154/* Free line number list */
184static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, 155static void line_list__free(struct list_head *head)
185 Dwarf_Signed *offs)
186{ 156{
187 Dwarf_Addr lopc, hipc; 157 struct line_node *ln;
188 int ret; 158 while (!list_empty(head)) {
189 159 ln = list_first_entry(head, struct line_node, list);
190 /* TODO: check ranges */ 160 list_del(&ln->list);
191 ret = dwarf_lowpc(sp_die, &lopc, &__dw_error); 161 free(ln);
192 DIE_IF(ret == DW_DLV_ERROR); 162 }
193 if (ret == DW_DLV_NO_ENTRY)
194 return 0;
195 ret = dwarf_highpc(sp_die, &hipc, &__dw_error);
196 DIE_IF(ret != DW_DLV_OK);
197 if (lopc <= addr && addr < hipc) {
198 *offs = addr - lopc;
199 return 1;
200 } else
201 return 0;
202} 163}
203 164
204/* Check the die is inlined function */ 165/* Dwarf wrappers */
205static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) 166
167/* Find the realpath of the target file. */
168static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname)
206{ 169{
207 /* TODO: check strictly */ 170 Dwarf_Files *files;
208 Dwarf_Bool inl; 171 size_t nfiles, i;
172 const char *src;
209 int ret; 173 int ret;
210 174
211 ret = dwarf_hasattr(dw_die, DW_AT_inline, &inl, &__dw_error); 175 if (!fname)
212 DIE_IF(ret == DW_DLV_ERROR); 176 return NULL;
213 return inl;
214}
215 177
216/* Get the offset of abstruct_origin */ 178 ret = dwarf_getsrcfiles(cu_die, &files, &nfiles);
217static Dwarf_Off die_get_abstract_origin(Dwarf_Die dw_die) 179 if (ret != 0)
218{ 180 return NULL;
219 Dwarf_Attribute attr;
220 Dwarf_Off cu_offs;
221 int ret;
222 181
223 ret = dwarf_attr(dw_die, DW_AT_abstract_origin, &attr, &__dw_error); 182 for (i = 0; i < nfiles; i++) {
224 DIE_IF(ret != DW_DLV_OK); 183 src = dwarf_filesrc(files, i, NULL, NULL);
225 ret = dwarf_formref(attr, &cu_offs, &__dw_error); 184 if (strtailcmp(src, fname) == 0)
226 DIE_IF(ret != DW_DLV_OK); 185 break;
227 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 186 }
228 return cu_offs; 187 return src;
229} 188}
230 189
231/* Get entry pc(or low pc, 1st entry of ranges) of the die */ 190struct __addr_die_search_param {
232static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) 191 Dwarf_Addr addr;
192 Dwarf_Die *die_mem;
193};
194
195static int __die_search_func_cb(Dwarf_Die *fn_die, void *data)
233{ 196{
234 Dwarf_Attribute attr; 197 struct __addr_die_search_param *ad = data;
235 Dwarf_Addr addr;
236 Dwarf_Off offs;
237 Dwarf_Ranges *ranges;
238 Dwarf_Signed cnt;
239 int ret;
240 198
241 /* Try to get entry pc */ 199 if (dwarf_tag(fn_die) == DW_TAG_subprogram &&
242 ret = dwarf_attr(dw_die, DW_AT_entry_pc, &attr, &__dw_error); 200 dwarf_haspc(fn_die, ad->addr)) {
243 DIE_IF(ret == DW_DLV_ERROR); 201 memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die));
244 if (ret == DW_DLV_OK) { 202 return DWARF_CB_ABORT;
245 ret = dwarf_formaddr(attr, &addr, &__dw_error);
246 DIE_IF(ret != DW_DLV_OK);
247 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
248 return addr;
249 } 203 }
204 return DWARF_CB_OK;
205}
250 206
251 /* Try to get low pc */ 207/* Search a real subprogram including this line, */
252 ret = dwarf_lowpc(dw_die, &addr, &__dw_error); 208static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr,
253 DIE_IF(ret == DW_DLV_ERROR); 209 Dwarf_Die *die_mem)
254 if (ret == DW_DLV_OK) 210{
255 return addr; 211 struct __addr_die_search_param ad;
256 212 ad.addr = addr;
257 /* Try to get ranges */ 213 ad.die_mem = die_mem;
258 ret = dwarf_attr(dw_die, DW_AT_ranges, &attr, &__dw_error); 214 /* dwarf_getscopes can't find subprogram. */
259 DIE_IF(ret != DW_DLV_OK); 215 if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0))
260 ret = dwarf_formref(attr, &offs, &__dw_error); 216 return NULL;
261 DIE_IF(ret != DW_DLV_OK); 217 else
262 ret = dwarf_get_ranges(__dw_debug, offs, &ranges, &cnt, NULL, 218 return die_mem;
263 &__dw_error);
264 DIE_IF(ret != DW_DLV_OK);
265 addr = ranges[0].dwr_addr1;
266 dwarf_ranges_dealloc(__dw_debug, ranges, cnt);
267 return addr;
268} 219}
269 220
270/* 221/* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */
271 * Search a Die from Die tree. 222static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr,
272 * Note: cur_link->die should be deallocated in this function. 223 Dwarf_Die *die_mem)
273 */
274static int __search_die_tree(struct die_link *cur_link,
275 int (*die_cb)(struct die_link *, void *),
276 void *data)
277{ 224{
278 Dwarf_Die new_die; 225 Dwarf_Die child_die;
279 struct die_link new_link;
280 int ret; 226 int ret;
281 227
282 if (!die_cb) 228 ret = dwarf_child(sp_die, die_mem);
283 return 0; 229 if (ret != 0)
284 230 return NULL;
285 /* Check current die */
286 while (!(ret = die_cb(cur_link, data))) {
287 /* Check child die */
288 ret = dwarf_child(cur_link->die, &new_die, &__dw_error);
289 DIE_IF(ret == DW_DLV_ERROR);
290 if (ret == DW_DLV_OK) {
291 new_link.parent = cur_link;
292 new_link.die = new_die;
293 ret = __search_die_tree(&new_link, die_cb, data);
294 if (ret)
295 break;
296 }
297 231
298 /* Move to next sibling */ 232 do {
299 ret = dwarf_siblingof(__dw_debug, cur_link->die, &new_die, 233 if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine &&
300 &__dw_error); 234 dwarf_haspc(die_mem, addr))
301 DIE_IF(ret == DW_DLV_ERROR); 235 return die_mem;
302 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
303 cur_link->die = new_die;
304 if (ret == DW_DLV_NO_ENTRY)
305 return 0;
306 }
307 dwarf_dealloc(__dw_debug, cur_link->die, DW_DLA_DIE);
308 return ret;
309}
310 236
311/* Search a die in its children's die tree */ 237 if (die_get_inlinefunc(die_mem, addr, &child_die)) {
312static int search_die_from_children(Dwarf_Die parent_die, 238 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
313 int (*die_cb)(struct die_link *, void *), 239 return die_mem;
314 void *data) 240 }
315{ 241 } while (dwarf_siblingof(die_mem, die_mem) == 0);
316 struct die_link new_link;
317 int ret;
318 242
319 new_link.parent = NULL; 243 return NULL;
320 ret = dwarf_child(parent_die, &new_link.die, &__dw_error);
321 DIE_IF(ret == DW_DLV_ERROR);
322 if (ret == DW_DLV_OK)
323 return __search_die_tree(&new_link, die_cb, data);
324 else
325 return 0;
326} 244}
327 245
328/* Find a locdesc corresponding to the address */ 246/* Compare diename and tname */
329static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, 247static bool die_compare_name(Dwarf_Die *dw_die, const char *tname)
330 Dwarf_Addr addr)
331{ 248{
332 Dwarf_Signed lcnt; 249 const char *name;
333 Dwarf_Locdesc **llbuf; 250 name = dwarf_diename(dw_die);
334 int ret, i; 251 DIE_IF(name == NULL);
335 252 return strcmp(tname, name);
336 ret = dwarf_loclist_n(attr, &llbuf, &lcnt, &__dw_error);
337 DIE_IF(ret != DW_DLV_OK);
338 ret = DW_DLV_NO_ENTRY;
339 for (i = 0; i < lcnt; ++i) {
340 if (llbuf[i]->ld_lopc <= addr &&
341 llbuf[i]->ld_hipc > addr) {
342 memcpy(desc, llbuf[i], sizeof(Dwarf_Locdesc));
343 desc->ld_s =
344 malloc(sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
345 DIE_IF(desc->ld_s == NULL);
346 memcpy(desc->ld_s, llbuf[i]->ld_s,
347 sizeof(Dwarf_Loc) * llbuf[i]->ld_cents);
348 ret = DW_DLV_OK;
349 break;
350 }
351 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
352 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
353 }
354 /* Releasing loop */
355 for (; i < lcnt; ++i) {
356 dwarf_dealloc(__dw_debug, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
357 dwarf_dealloc(__dw_debug, llbuf[i], DW_DLA_LOCDESC);
358 }
359 dwarf_dealloc(__dw_debug, llbuf, DW_DLA_LIST);
360 return ret;
361} 253}
362 254
363/* Get decl_file attribute value (file number) */ 255/* Get entry pc(or low pc, 1st entry of ranges) of the die */
364static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) 256static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die)
365{ 257{
366 Dwarf_Attribute attr; 258 Dwarf_Addr epc;
367 Dwarf_Unsigned fno;
368 int ret; 259 int ret;
369 260
370 ret = dwarf_attr(sp_die, DW_AT_decl_file, &attr, &__dw_error); 261 ret = dwarf_entrypc(dw_die, &epc);
371 DIE_IF(ret != DW_DLV_OK); 262 DIE_IF(ret == -1);
372 dwarf_formudata(attr, &fno, &__dw_error); 263 return epc;
373 DIE_IF(ret != DW_DLV_OK);
374 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
375 return fno;
376} 264}
377 265
378/* Get decl_line attribute value (line number) */ 266/* Get a variable die */
379static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) 267static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name,
268 Dwarf_Die *die_mem)
380{ 269{
381 Dwarf_Attribute attr; 270 Dwarf_Die child_die;
382 Dwarf_Unsigned lno; 271 int tag;
383 int ret; 272 int ret;
384 273
385 ret = dwarf_attr(sp_die, DW_AT_decl_line, &attr, &__dw_error); 274 ret = dwarf_child(sp_die, die_mem);
386 DIE_IF(ret != DW_DLV_OK); 275 if (ret != 0)
387 dwarf_formudata(attr, &lno, &__dw_error); 276 return NULL;
388 DIE_IF(ret != DW_DLV_OK); 277
389 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR); 278 do {
390 return lno; 279 tag = dwarf_tag(die_mem);
280 if ((tag == DW_TAG_formal_parameter ||
281 tag == DW_TAG_variable) &&
282 (die_compare_name(die_mem, name) == 0))
283 return die_mem;
284
285 if (die_find_variable(die_mem, name, &child_die)) {
286 memcpy(die_mem, &child_die, sizeof(Dwarf_Die));
287 return die_mem;
288 }
289 } while (dwarf_siblingof(die_mem, die_mem) == 0);
290
291 return NULL;
391} 292}
392 293
393/* 294/*
@@ -395,47 +296,45 @@ static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die)
395 */ 296 */
396 297
397/* Show a location */ 298/* Show a location */
398static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) 299static void show_location(Dwarf_Op *op, struct probe_finder *pf)
399{ 300{
400 Dwarf_Small op; 301 unsigned int regn;
401 Dwarf_Unsigned regn; 302 Dwarf_Word offs = 0;
402 Dwarf_Signed offs;
403 int deref = 0, ret; 303 int deref = 0, ret;
404 const char *regs; 304 const char *regs;
405 305
406 op = loc->lr_atom; 306 /* TODO: support CFA */
407
408 /* If this is based on frame buffer, set the offset */ 307 /* If this is based on frame buffer, set the offset */
409 if (op == DW_OP_fbreg) { 308 if (op->atom == DW_OP_fbreg) {
309 if (pf->fb_ops == NULL)
310 die("The attribute of frame base is not supported.\n");
410 deref = 1; 311 deref = 1;
411 offs = (Dwarf_Signed)loc->lr_number; 312 offs = op->number;
412 op = pf->fbloc.ld_s[0].lr_atom; 313 op = &pf->fb_ops[0];
413 loc = &pf->fbloc.ld_s[0]; 314 }
414 } else
415 offs = 0;
416 315
417 if (op >= DW_OP_breg0 && op <= DW_OP_breg31) { 316 if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) {
418 regn = op - DW_OP_breg0; 317 regn = op->atom - DW_OP_breg0;
419 offs += (Dwarf_Signed)loc->lr_number; 318 offs += op->number;
420 deref = 1; 319 deref = 1;
421 } else if (op >= DW_OP_reg0 && op <= DW_OP_reg31) { 320 } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) {
422 regn = op - DW_OP_reg0; 321 regn = op->atom - DW_OP_reg0;
423 } else if (op == DW_OP_bregx) { 322 } else if (op->atom == DW_OP_bregx) {
424 regn = loc->lr_number; 323 regn = op->number;
425 offs += (Dwarf_Signed)loc->lr_number2; 324 offs += op->number2;
426 deref = 1; 325 deref = 1;
427 } else if (op == DW_OP_regx) { 326 } else if (op->atom == DW_OP_regx) {
428 regn = loc->lr_number; 327 regn = op->number;
429 } else 328 } else
430 die("Dwarf_OP %d is not supported.", op); 329 die("DW_OP %d is not supported.", op->atom);
431 330
432 regs = get_arch_regstr(regn); 331 regs = get_arch_regstr(regn);
433 if (!regs) 332 if (!regs)
434 die("%lld exceeds max register number.", regn); 333 die("%u exceeds max register number.", regn);
435 334
436 if (deref) 335 if (deref)
437 ret = snprintf(pf->buf, pf->len, 336 ret = snprintf(pf->buf, pf->len, " %s=+%ju(%s)",
438 " %s=%+lld(%s)", pf->var, offs, regs); 337 pf->var, (uintmax_t)offs, regs);
439 else 338 else
440 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); 339 ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs);
441 DIE_IF(ret < 0); 340 DIE_IF(ret < 0);
@@ -443,52 +342,37 @@ static void show_location(Dwarf_Loc *loc, struct probe_finder *pf)
443} 342}
444 343
445/* Show a variables in kprobe event format */ 344/* Show a variables in kprobe event format */
446static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) 345static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
447{ 346{
448 Dwarf_Attribute attr; 347 Dwarf_Attribute attr;
449 Dwarf_Locdesc ld; 348 Dwarf_Op *expr;
349 size_t nexpr;
450 int ret; 350 int ret;
451 351
452 ret = dwarf_attr(vr_die, DW_AT_location, &attr, &__dw_error); 352 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL)
453 if (ret != DW_DLV_OK)
454 goto error; 353 goto error;
455 ret = attr_get_locdesc(attr, &ld, (pf->addr - pf->cu_base)); 354 /* TODO: handle more than 1 exprs */
456 if (ret != DW_DLV_OK) 355 ret = dwarf_getlocation_addr(&attr, (pf->addr - pf->cu_base),
356 &expr, &nexpr, 1);
357 if (ret <= 0 || nexpr == 0)
457 goto error; 358 goto error;
458 /* TODO? */ 359
459 DIE_IF(ld.ld_cents != 1); 360 show_location(expr, pf);
460 show_location(&ld.ld_s[0], pf); 361 /* *expr will be cached in libdw. Don't free it. */
461 free(ld.ld_s);
462 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
463 return ; 362 return ;
464error: 363error:
364 /* TODO: Support const_value */
465 die("Failed to find the location of %s at this address.\n" 365 die("Failed to find the location of %s at this address.\n"
466 " Perhaps, it has been optimized out.", pf->var); 366 " Perhaps, it has been optimized out.", pf->var);
467} 367}
468 368
469static int variable_callback(struct die_link *dlink, void *data)
470{
471 struct probe_finder *pf = (struct probe_finder *)data;
472 Dwarf_Half tag;
473 int ret;
474
475 ret = dwarf_tag(dlink->die, &tag, &__dw_error);
476 DIE_IF(ret == DW_DLV_ERROR);
477 if ((tag == DW_TAG_formal_parameter ||
478 tag == DW_TAG_variable) &&
479 (die_compare_name(dlink->die, pf->var) == 0)) {
480 show_variable(dlink->die, pf);
481 return 1;
482 }
483 /* TODO: Support struct members and arrays */
484 return 0;
485}
486
487/* Find a variable in a subprogram die */ 369/* Find a variable in a subprogram die */
488static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) 370static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
489{ 371{
490 int ret; 372 int ret;
373 Dwarf_Die vr_die;
491 374
375 /* TODO: Support struct members and arrays */
492 if (!is_c_varname(pf->var)) { 376 if (!is_c_varname(pf->var)) {
493 /* Output raw parameters */ 377 /* Output raw parameters */
494 ret = snprintf(pf->buf, pf->len, " %s", pf->var); 378 ret = snprintf(pf->buf, pf->len, " %s", pf->var);
@@ -499,58 +383,51 @@ static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf)
499 383
500 pr_debug("Searching '%s' variable in context.\n", pf->var); 384 pr_debug("Searching '%s' variable in context.\n", pf->var);
501 /* Search child die for local variables and parameters. */ 385 /* Search child die for local variables and parameters. */
502 ret = search_die_from_children(sp_die, variable_callback, pf); 386 if (!die_find_variable(sp_die, pf->var, &vr_die))
503 if (!ret)
504 die("Failed to find '%s' in this function.", pf->var); 387 die("Failed to find '%s' in this function.", pf->var);
505}
506
507/* Get a frame base on the address */
508static void get_current_frame_base(Dwarf_Die sp_die, struct probe_finder *pf)
509{
510 Dwarf_Attribute attr;
511 int ret;
512 388
513 ret = dwarf_attr(sp_die, DW_AT_frame_base, &attr, &__dw_error); 389 show_variable(&vr_die, pf);
514 DIE_IF(ret != DW_DLV_OK);
515 ret = attr_get_locdesc(attr, &pf->fbloc, (pf->addr - pf->cu_base));
516 DIE_IF(ret != DW_DLV_OK);
517 dwarf_dealloc(__dw_debug, attr, DW_DLA_ATTR);
518}
519
520static void free_current_frame_base(struct probe_finder *pf)
521{
522 free(pf->fbloc.ld_s);
523 memset(&pf->fbloc, 0, sizeof(Dwarf_Locdesc));
524} 390}
525 391
526/* Show a probe point to output buffer */ 392/* Show a probe point to output buffer */
527static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, 393static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf)
528 struct probe_finder *pf)
529{ 394{
530 struct probe_point *pp = pf->pp; 395 struct probe_point *pp = pf->pp;
531 char *name; 396 Dwarf_Addr eaddr;
397 Dwarf_Die die_mem;
398 const char *name;
532 char tmp[MAX_PROBE_BUFFER]; 399 char tmp[MAX_PROBE_BUFFER];
533 int ret, i, len; 400 int ret, i, len;
401 Dwarf_Attribute fb_attr;
402 size_t nops;
403
404 /* If no real subprogram, find a real one */
405 if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) {
406 sp_die = die_get_real_subprogram(&pf->cu_die,
407 pf->addr, &die_mem);
408 if (!sp_die)
409 die("Probe point is not found in subprograms.");
410 }
534 411
535 /* Output name of probe point */ 412 /* Output name of probe point */
536 ret = dwarf_diename(sp_die, &name, &__dw_error); 413 name = dwarf_diename(sp_die);
537 DIE_IF(ret == DW_DLV_ERROR); 414 if (name) {
538 if (ret == DW_DLV_OK) { 415 dwarf_entrypc(sp_die, &eaddr);
539 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%u", name, 416 ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name,
540 (unsigned int)offs); 417 (unsigned long)(pf->addr - eaddr));
541 /* Copy the function name if possible */ 418 /* Copy the function name if possible */
542 if (!pp->function) { 419 if (!pp->function) {
543 pp->function = strdup(name); 420 pp->function = strdup(name);
544 pp->offset = offs; 421 pp->offset = (size_t)(pf->addr - eaddr);
545 } 422 }
546 dwarf_dealloc(__dw_debug, name, DW_DLA_STRING);
547 } else { 423 } else {
548 /* This function has no name. */ 424 /* This function has no name. */
549 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%llx", pf->addr); 425 ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx",
426 (uintmax_t)pf->addr);
550 if (!pp->function) { 427 if (!pp->function) {
551 /* TODO: Use _stext */ 428 /* TODO: Use _stext */
552 pp->function = strdup(""); 429 pp->function = strdup("");
553 pp->offset = (int)pf->addr; 430 pp->offset = (size_t)pf->addr;
554 } 431 }
555 } 432 }
556 DIE_IF(ret < 0); 433 DIE_IF(ret < 0);
@@ -558,8 +435,15 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
558 len = ret; 435 len = ret;
559 pr_debug("Probe point found: %s\n", tmp); 436 pr_debug("Probe point found: %s\n", tmp);
560 437
438 /* Get the frame base attribute/ops */
439 dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr);
440 ret = dwarf_getlocation_addr(&fb_attr, (pf->addr - pf->cu_base),
441 &pf->fb_ops, &nops, 1);
442 if (ret <= 0 || nops == 0)
443 pf->fb_ops = NULL;
444
561 /* Find each argument */ 445 /* Find each argument */
562 get_current_frame_base(sp_die, pf); 446 /* TODO: use dwarf_cfi_addrframe */
563 for (i = 0; i < pp->nr_args; i++) { 447 for (i = 0; i < pp->nr_args; i++) {
564 pf->var = pp->args[i]; 448 pf->var = pp->args[i];
565 pf->buf = &tmp[len]; 449 pf->buf = &tmp[len];
@@ -567,289 +451,327 @@ static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs,
567 find_variable(sp_die, pf); 451 find_variable(sp_die, pf);
568 len += strlen(pf->buf); 452 len += strlen(pf->buf);
569 } 453 }
570 free_current_frame_base(pf); 454
455 /* *pf->fb_ops will be cached in libdw. Don't free it. */
456 pf->fb_ops = NULL;
571 457
572 pp->probes[pp->found] = strdup(tmp); 458 pp->probes[pp->found] = strdup(tmp);
573 pp->found++; 459 pp->found++;
574} 460}
575 461
576static int probeaddr_callback(struct die_link *dlink, void *data) 462/* Find probe point from its line number */
463static void find_probe_point_by_line(struct probe_finder *pf)
577{ 464{
578 struct probe_finder *pf = (struct probe_finder *)data; 465 Dwarf_Lines *lines;
579 Dwarf_Half tag; 466 Dwarf_Line *line;
580 Dwarf_Signed offs; 467 size_t nlines, i;
468 Dwarf_Addr addr;
469 int lineno;
581 int ret; 470 int ret;
582 471
583 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 472 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
584 DIE_IF(ret == DW_DLV_ERROR); 473 DIE_IF(ret != 0);
585 /* Check the address is in this subprogram */ 474
586 if (tag == DW_TAG_subprogram && 475 for (i = 0; i < nlines; i++) {
587 die_within_subprogram(dlink->die, pf->addr, &offs)) { 476 line = dwarf_onesrcline(lines, i);
588 show_probepoint(dlink->die, offs, pf); 477 dwarf_lineno(line, &lineno);
589 return 1; 478 if (lineno != pf->lno)
479 continue;
480
481 /* TODO: Get fileno from line, but how? */
482 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
483 continue;
484
485 ret = dwarf_lineaddr(line, &addr);
486 DIE_IF(ret != 0);
487 pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n",
488 (int)i, lineno, (uintmax_t)addr);
489 pf->addr = addr;
490
491 show_probe_point(NULL, pf);
492 /* Continuing, because target line might be inlined. */
590 } 493 }
591 return 0;
592} 494}
593 495
594/* Find probe point from its line number */ 496/* Find lines which match lazy pattern */
595static void find_probe_point_by_line(struct probe_finder *pf) 497static int find_lazy_match_lines(struct list_head *head,
498 const char *fname, const char *pat)
596{ 499{
597 Dwarf_Signed cnt, i, clm; 500 char *fbuf, *p1, *p2;
598 Dwarf_Line *lines; 501 int fd, line, nlines = 0;
599 Dwarf_Unsigned lineno = 0; 502 struct stat st;
503
504 fd = open(fname, O_RDONLY);
505 if (fd < 0)
506 die("failed to open %s", fname);
507 DIE_IF(fstat(fd, &st) < 0);
508 fbuf = malloc(st.st_size + 2);
509 DIE_IF(fbuf == NULL);
510 DIE_IF(read(fd, fbuf, st.st_size) < 0);
511 close(fd);
512 fbuf[st.st_size] = '\n'; /* Dummy line */
513 fbuf[st.st_size + 1] = '\0';
514 p1 = fbuf;
515 line = 1;
516 while ((p2 = strchr(p1, '\n')) != NULL) {
517 *p2 = '\0';
518 if (strlazymatch(p1, pat)) {
519 line_list__add_line(head, line);
520 nlines++;
521 }
522 line++;
523 p1 = p2 + 1;
524 }
525 free(fbuf);
526 return nlines;
527}
528
529/* Find probe points from lazy pattern */
530static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
531{
532 Dwarf_Lines *lines;
533 Dwarf_Line *line;
534 size_t nlines, i;
600 Dwarf_Addr addr; 535 Dwarf_Addr addr;
601 Dwarf_Unsigned fno; 536 Dwarf_Die die_mem;
537 int lineno;
602 int ret; 538 int ret;
603 539
604 ret = dwarf_srclines(pf->cu_die, &lines, &cnt, &__dw_error); 540 if (list_empty(&pf->lcache)) {
605 DIE_IF(ret != DW_DLV_OK); 541 /* Matching lazy line pattern */
542 ret = find_lazy_match_lines(&pf->lcache, pf->fname,
543 pf->pp->lazy_line);
544 if (ret <= 0)
545 die("No matched lines found in %s.", pf->fname);
546 }
547
548 ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines);
549 DIE_IF(ret != 0);
550 for (i = 0; i < nlines; i++) {
551 line = dwarf_onesrcline(lines, i);
606 552
607 for (i = 0; i < cnt; i++) { 553 dwarf_lineno(line, &lineno);
608 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 554 if (!line_list__has_line(&pf->lcache, lineno))
609 DIE_IF(ret != DW_DLV_OK);
610 if (fno != pf->fno)
611 continue; 555 continue;
612 556
613 ret = dwarf_lineno(lines[i], &lineno, &__dw_error); 557 /* TODO: Get fileno from line, but how? */
614 DIE_IF(ret != DW_DLV_OK); 558 if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0)
615 if (lineno != pf->lno)
616 continue; 559 continue;
617 560
618 ret = dwarf_lineoff(lines[i], &clm, &__dw_error); 561 ret = dwarf_lineaddr(line, &addr);
619 DIE_IF(ret != DW_DLV_OK); 562 DIE_IF(ret != 0);
563 if (sp_die) {
564 /* Address filtering 1: does sp_die include addr? */
565 if (!dwarf_haspc(sp_die, addr))
566 continue;
567 /* Address filtering 2: No child include addr? */
568 if (die_get_inlinefunc(sp_die, addr, &die_mem))
569 continue;
570 }
620 571
621 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 572 pr_debug("Probe line found: line[%d]:%d addr:0x%llx\n",
622 DIE_IF(ret != DW_DLV_OK); 573 (int)i, lineno, (unsigned long long)addr);
623 pr_debug("Probe line found: line[%d]:%u,%d addr:0x%llx\n",
624 (int)i, (unsigned)lineno, (int)clm, addr);
625 pf->addr = addr; 574 pf->addr = addr;
626 /* Search a real subprogram including this line, */ 575
627 ret = search_die_from_children(pf->cu_die, 576 show_probe_point(sp_die, pf);
628 probeaddr_callback, pf);
629 if (ret == 0)
630 die("Probe point is not found in subprograms.");
631 /* Continuing, because target line might be inlined. */ 577 /* Continuing, because target line might be inlined. */
632 } 578 }
633 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 579 /* TODO: deallocate lines, but how? */
580}
581
582static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
583{
584 struct probe_finder *pf = (struct probe_finder *)data;
585 struct probe_point *pp = pf->pp;
586
587 if (pp->lazy_line)
588 find_probe_point_lazy(in_die, pf);
589 else {
590 /* Get probe address */
591 pf->addr = die_get_entrypc(in_die);
592 pf->addr += pp->offset;
593 pr_debug("found inline addr: 0x%jx\n",
594 (uintmax_t)pf->addr);
595
596 show_probe_point(in_die, pf);
597 }
598
599 return DWARF_CB_OK;
634} 600}
635 601
636/* Search function from function name */ 602/* Search function from function name */
637static int probefunc_callback(struct die_link *dlink, void *data) 603static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
638{ 604{
639 struct probe_finder *pf = (struct probe_finder *)data; 605 struct probe_finder *pf = (struct probe_finder *)data;
640 struct probe_point *pp = pf->pp; 606 struct probe_point *pp = pf->pp;
641 struct die_link *lk;
642 Dwarf_Signed offs;
643 Dwarf_Half tag;
644 int ret;
645 607
646 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 608 /* Check tag and diename */
647 DIE_IF(ret == DW_DLV_ERROR); 609 if (dwarf_tag(sp_die) != DW_TAG_subprogram ||
648 if (tag == DW_TAG_subprogram) { 610 die_compare_name(sp_die, pp->function) != 0)
649 if (die_compare_name(dlink->die, pp->function) == 0) { 611 return 0;
650 if (pp->line) { /* Function relative line */ 612
651 pf->fno = die_get_decl_file(dlink->die); 613 pf->fname = dwarf_decl_file(sp_die);
652 pf->lno = die_get_decl_line(dlink->die) 614 if (pp->line) { /* Function relative line */
653 + pp->line; 615 dwarf_decl_line(sp_die, &pf->lno);
654 find_probe_point_by_line(pf); 616 pf->lno += pp->line;
655 return 1; 617 find_probe_point_by_line(pf);
656 } 618 } else if (!dwarf_func_inline(sp_die)) {
657 if (die_inlined_subprogram(dlink->die)) { 619 /* Real function */
658 /* Inlined function, save it. */ 620 if (pp->lazy_line)
659 ret = dwarf_die_CU_offset(dlink->die, 621 find_probe_point_lazy(sp_die, pf);
660 &pf->inl_offs, 622 else {
661 &__dw_error); 623 pf->addr = die_get_entrypc(sp_die);
662 DIE_IF(ret != DW_DLV_OK);
663 pr_debug("inline definition offset %lld\n",
664 pf->inl_offs);
665 return 0; /* Continue to search */
666 }
667 /* Get probe address */
668 pf->addr = die_get_entrypc(dlink->die);
669 pf->addr += pp->offset; 624 pf->addr += pp->offset;
670 /* TODO: Check the address in this function */ 625 /* TODO: Check the address in this function */
671 show_probepoint(dlink->die, pp->offset, pf); 626 show_probe_point(sp_die, pf);
672 return 1; /* Exit; no same symbol in this CU. */
673 }
674 } else if (tag == DW_TAG_inlined_subroutine && pf->inl_offs) {
675 if (die_get_abstract_origin(dlink->die) == pf->inl_offs) {
676 /* Get probe address */
677 pf->addr = die_get_entrypc(dlink->die);
678 pf->addr += pp->offset;
679 pr_debug("found inline addr: 0x%llx\n", pf->addr);
680 /* Inlined function. Get a real subprogram */
681 for (lk = dlink->parent; lk != NULL; lk = lk->parent) {
682 tag = 0;
683 dwarf_tag(lk->die, &tag, &__dw_error);
684 DIE_IF(ret == DW_DLV_ERROR);
685 if (tag == DW_TAG_subprogram &&
686 !die_inlined_subprogram(lk->die))
687 goto found;
688 }
689 die("Failed to find real subprogram.");
690found:
691 /* Get offset from subprogram */
692 ret = die_within_subprogram(lk->die, pf->addr, &offs);
693 DIE_IF(!ret);
694 show_probepoint(lk->die, offs, pf);
695 /* Continue to search */
696 } 627 }
697 } 628 } else
698 return 0; 629 /* Inlined function: search instances */
630 dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf);
631
632 return 1; /* Exit; no same symbol in this CU. */
699} 633}
700 634
701static void find_probe_point_by_func(struct probe_finder *pf) 635static void find_probe_point_by_func(struct probe_finder *pf)
702{ 636{
703 search_die_from_children(pf->cu_die, probefunc_callback, pf); 637 dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0);
704} 638}
705 639
706/* Find a probe point */ 640/* Find a probe point */
707int find_probepoint(int fd, struct probe_point *pp) 641int find_probe_point(int fd, struct probe_point *pp)
708{ 642{
709 Dwarf_Half addr_size = 0;
710 Dwarf_Unsigned next_cuh = 0;
711 int cu_number = 0, ret;
712 struct probe_finder pf = {.pp = pp}; 643 struct probe_finder pf = {.pp = pp};
644 int ret;
645 Dwarf_Off off, noff;
646 size_t cuhl;
647 Dwarf_Die *diep;
648 Dwarf *dbg;
713 649
714 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 650 dbg = dwarf_begin(fd, DWARF_C_READ);
715 if (ret != DW_DLV_OK) 651 if (!dbg)
716 return -ENOENT; 652 return -ENOENT;
717 653
718 pp->found = 0; 654 pp->found = 0;
719 while (++cu_number) { 655 off = 0;
720 /* Search CU (Compilation Unit) */ 656 line_list__init(&pf.lcache);
721 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 657 /* Loop on CUs (Compilation Unit) */
722 &addr_size, &next_cuh, &__dw_error); 658 while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) {
723 DIE_IF(ret == DW_DLV_ERROR);
724 if (ret == DW_DLV_NO_ENTRY)
725 break;
726
727 /* Get the DIE(Debugging Information Entry) of this CU */ 659 /* Get the DIE(Debugging Information Entry) of this CU */
728 ret = dwarf_siblingof(__dw_debug, 0, &pf.cu_die, &__dw_error); 660 diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die);
729 DIE_IF(ret != DW_DLV_OK); 661 if (!diep)
662 continue;
730 663
731 /* Check if target file is included. */ 664 /* Check if target file is included. */
732 if (pp->file) 665 if (pp->file)
733 pf.fno = cu_find_fileno(pf.cu_die, pp->file); 666 pf.fname = cu_find_realpath(&pf.cu_die, pp->file);
667 else
668 pf.fname = NULL;
734 669
735 if (!pp->file || pf.fno) { 670 if (!pp->file || pf.fname) {
736 /* Save CU base address (for frame_base) */ 671 /* Save CU base address (for frame_base) */
737 ret = dwarf_lowpc(pf.cu_die, &pf.cu_base, &__dw_error); 672 ret = dwarf_lowpc(&pf.cu_die, &pf.cu_base);
738 DIE_IF(ret == DW_DLV_ERROR); 673 if (ret != 0)
739 if (ret == DW_DLV_NO_ENTRY)
740 pf.cu_base = 0; 674 pf.cu_base = 0;
741 if (pp->function) 675 if (pp->function)
742 find_probe_point_by_func(&pf); 676 find_probe_point_by_func(&pf);
677 else if (pp->lazy_line)
678 find_probe_point_lazy(NULL, &pf);
743 else { 679 else {
744 pf.lno = pp->line; 680 pf.lno = pp->line;
745 find_probe_point_by_line(&pf); 681 find_probe_point_by_line(&pf);
746 } 682 }
747 } 683 }
748 dwarf_dealloc(__dw_debug, pf.cu_die, DW_DLA_DIE); 684 off = noff;
749 } 685 }
750 ret = dwarf_finish(__dw_debug, &__dw_error); 686 line_list__free(&pf.lcache);
751 DIE_IF(ret != DW_DLV_OK); 687 dwarf_end(dbg);
752 688
753 return pp->found; 689 return pp->found;
754} 690}
755 691
756
757static void line_range_add_line(struct line_range *lr, unsigned int line)
758{
759 struct line_node *ln;
760 struct list_head *p;
761
762 /* Reverse search, because new line will be the last one */
763 list_for_each_entry_reverse(ln, &lr->line_list, list) {
764 if (ln->line < line) {
765 p = &ln->list;
766 goto found;
767 } else if (ln->line == line) /* Already exist */
768 return ;
769 }
770 /* List is empty, or the smallest entry */
771 p = &lr->line_list;
772found:
773 pr_debug("Debug: add a line %u\n", line);
774 ln = zalloc(sizeof(struct line_node));
775 DIE_IF(ln == NULL);
776 ln->line = line;
777 INIT_LIST_HEAD(&ln->list);
778 list_add(&ln->list, p);
779}
780
781/* Find line range from its line number */ 692/* Find line range from its line number */
782static void find_line_range_by_line(struct line_finder *lf) 693static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf)
783{ 694{
784 Dwarf_Signed cnt, i; 695 Dwarf_Lines *lines;
785 Dwarf_Line *lines; 696 Dwarf_Line *line;
786 Dwarf_Unsigned lineno = 0; 697 size_t nlines, i;
787 Dwarf_Unsigned fno;
788 Dwarf_Addr addr; 698 Dwarf_Addr addr;
699 int lineno;
789 int ret; 700 int ret;
701 const char *src;
702 Dwarf_Die die_mem;
790 703
791 ret = dwarf_srclines(lf->cu_die, &lines, &cnt, &__dw_error); 704 line_list__init(&lf->lr->line_list);
792 DIE_IF(ret != DW_DLV_OK); 705 ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines);
706 DIE_IF(ret != 0);
793 707
794 for (i = 0; i < cnt; i++) { 708 for (i = 0; i < nlines; i++) {
795 ret = dwarf_line_srcfileno(lines[i], &fno, &__dw_error); 709 line = dwarf_onesrcline(lines, i);
796 DIE_IF(ret != DW_DLV_OK); 710 ret = dwarf_lineno(line, &lineno);
797 if (fno != lf->fno) 711 DIE_IF(ret != 0);
798 continue;
799
800 ret = dwarf_lineno(lines[i], &lineno, &__dw_error);
801 DIE_IF(ret != DW_DLV_OK);
802 if (lf->lno_s > lineno || lf->lno_e < lineno) 712 if (lf->lno_s > lineno || lf->lno_e < lineno)
803 continue; 713 continue;
804 714
805 /* Filter line in the function address range */ 715 if (sp_die) {
806 if (lf->addr_s && lf->addr_e) { 716 /* Address filtering 1: does sp_die include addr? */
807 ret = dwarf_lineaddr(lines[i], &addr, &__dw_error); 717 ret = dwarf_lineaddr(line, &addr);
808 DIE_IF(ret != DW_DLV_OK); 718 DIE_IF(ret != 0);
809 if (lf->addr_s > addr || lf->addr_e <= addr) 719 if (!dwarf_haspc(sp_die, addr))
720 continue;
721
722 /* Address filtering 2: No child include addr? */
723 if (die_get_inlinefunc(sp_die, addr, &die_mem))
810 continue; 724 continue;
811 } 725 }
812 line_range_add_line(lf->lr, (unsigned int)lineno); 726
727 /* TODO: Get fileno from line, but how? */
728 src = dwarf_linesrc(line, NULL, NULL);
729 if (strtailcmp(src, lf->fname) != 0)
730 continue;
731
732 /* Copy real path */
733 if (!lf->lr->path)
734 lf->lr->path = strdup(src);
735 line_list__add_line(&lf->lr->line_list, (unsigned int)lineno);
813 } 736 }
814 dwarf_srclines_dealloc(__dw_debug, lines, cnt); 737 /* Update status */
815 if (!list_empty(&lf->lr->line_list)) 738 if (!list_empty(&lf->lr->line_list))
816 lf->found = 1; 739 lf->found = 1;
740 else {
741 free(lf->lr->path);
742 lf->lr->path = NULL;
743 }
744}
745
746static int line_range_inline_cb(Dwarf_Die *in_die, void *data)
747{
748 find_line_range_by_line(in_die, (struct line_finder *)data);
749 return DWARF_CB_ABORT; /* No need to find other instances */
817} 750}
818 751
819/* Search function from function name */ 752/* Search function from function name */
820static int linefunc_callback(struct die_link *dlink, void *data) 753static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
821{ 754{
822 struct line_finder *lf = (struct line_finder *)data; 755 struct line_finder *lf = (struct line_finder *)data;
823 struct line_range *lr = lf->lr; 756 struct line_range *lr = lf->lr;
824 Dwarf_Half tag;
825 int ret;
826 757
827 ret = dwarf_tag(dlink->die, &tag, &__dw_error); 758 if (dwarf_tag(sp_die) == DW_TAG_subprogram &&
828 DIE_IF(ret == DW_DLV_ERROR); 759 die_compare_name(sp_die, lr->function) == 0) {
829 if (tag == DW_TAG_subprogram && 760 lf->fname = dwarf_decl_file(sp_die);
830 die_compare_name(dlink->die, lr->function) == 0) { 761 dwarf_decl_line(sp_die, &lr->offset);
831 /* Get the address range of this function */ 762 pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
832 ret = dwarf_highpc(dlink->die, &lf->addr_e, &__dw_error);
833 if (ret == DW_DLV_OK)
834 ret = dwarf_lowpc(dlink->die, &lf->addr_s, &__dw_error);
835 DIE_IF(ret == DW_DLV_ERROR);
836 if (ret == DW_DLV_NO_ENTRY) {
837 lf->addr_s = 0;
838 lf->addr_e = 0;
839 }
840
841 lf->fno = die_get_decl_file(dlink->die);
842 lr->offset = die_get_decl_line(dlink->die);;
843 lf->lno_s = lr->offset + lr->start; 763 lf->lno_s = lr->offset + lr->start;
844 if (!lr->end) 764 if (!lr->end)
845 lf->lno_e = (Dwarf_Unsigned)-1; 765 lf->lno_e = INT_MAX;
846 else 766 else
847 lf->lno_e = lr->offset + lr->end; 767 lf->lno_e = lr->offset + lr->end;
848 lr->start = lf->lno_s; 768 lr->start = lf->lno_s;
849 lr->end = lf->lno_e; 769 lr->end = lf->lno_e;
850 find_line_range_by_line(lf); 770 if (dwarf_func_inline(sp_die))
851 /* If we find a target function, this should be end. */ 771 dwarf_func_inline_instances(sp_die,
852 lf->found = 1; 772 line_range_inline_cb, lf);
773 else
774 find_line_range_by_line(sp_die, lf);
853 return 1; 775 return 1;
854 } 776 }
855 return 0; 777 return 0;
@@ -857,55 +779,55 @@ static int linefunc_callback(struct die_link *dlink, void *data)
857 779
858static void find_line_range_by_func(struct line_finder *lf) 780static void find_line_range_by_func(struct line_finder *lf)
859{ 781{
860 search_die_from_children(lf->cu_die, linefunc_callback, lf); 782 dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0);
861} 783}
862 784
863int find_line_range(int fd, struct line_range *lr) 785int find_line_range(int fd, struct line_range *lr)
864{ 786{
865 Dwarf_Half addr_size = 0; 787 struct line_finder lf = {.lr = lr, .found = 0};
866 Dwarf_Unsigned next_cuh = 0;
867 int ret; 788 int ret;
868 struct line_finder lf = {.lr = lr}; 789 Dwarf_Off off = 0, noff;
790 size_t cuhl;
791 Dwarf_Die *diep;
792 Dwarf *dbg;
869 793
870 ret = dwarf_init(fd, DW_DLC_READ, 0, 0, &__dw_debug, &__dw_error); 794 dbg = dwarf_begin(fd, DWARF_C_READ);
871 if (ret != DW_DLV_OK) 795 if (!dbg)
872 return -ENOENT; 796 return -ENOENT;
873 797
798 /* Loop on CUs (Compilation Unit) */
874 while (!lf.found) { 799 while (!lf.found) {
875 /* Search CU (Compilation Unit) */ 800 ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL);
876 ret = dwarf_next_cu_header(__dw_debug, NULL, NULL, NULL, 801 if (ret != 0)
877 &addr_size, &next_cuh, &__dw_error);
878 DIE_IF(ret == DW_DLV_ERROR);
879 if (ret == DW_DLV_NO_ENTRY)
880 break; 802 break;
881 803
882 /* Get the DIE(Debugging Information Entry) of this CU */ 804 /* Get the DIE(Debugging Information Entry) of this CU */
883 ret = dwarf_siblingof(__dw_debug, 0, &lf.cu_die, &__dw_error); 805 diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die);
884 DIE_IF(ret != DW_DLV_OK); 806 if (!diep)
807 continue;
885 808
886 /* Check if target file is included. */ 809 /* Check if target file is included. */
887 if (lr->file) 810 if (lr->file)
888 lf.fno = cu_find_fileno(lf.cu_die, lr->file); 811 lf.fname = cu_find_realpath(&lf.cu_die, lr->file);
812 else
813 lf.fname = 0;
889 814
890 if (!lr->file || lf.fno) { 815 if (!lr->file || lf.fname) {
891 if (lr->function) 816 if (lr->function)
892 find_line_range_by_func(&lf); 817 find_line_range_by_func(&lf);
893 else { 818 else {
894 lf.lno_s = lr->start; 819 lf.lno_s = lr->start;
895 if (!lr->end) 820 if (!lr->end)
896 lf.lno_e = (Dwarf_Unsigned)-1; 821 lf.lno_e = INT_MAX;
897 else 822 else
898 lf.lno_e = lr->end; 823 lf.lno_e = lr->end;
899 find_line_range_by_line(&lf); 824 find_line_range_by_line(NULL, &lf);
900 } 825 }
901 /* Get the real file path */
902 if (lf.found)
903 cu_get_filename(lf.cu_die, lf.fno, &lr->path);
904 } 826 }
905 dwarf_dealloc(__dw_debug, lf.cu_die, DW_DLA_DIE); 827 off = noff;
906 } 828 }
907 ret = dwarf_finish(__dw_debug, &__dw_error); 829 pr_debug("path: %lx\n", (unsigned long)lr->path);
908 DIE_IF(ret != DW_DLV_OK); 830 dwarf_end(dbg);
909 return lf.found; 831 return lf.found;
910} 832}
911 833
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 972b386116f1..d1a651793ba6 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -1,6 +1,7 @@
1#ifndef _PROBE_FINDER_H 1#ifndef _PROBE_FINDER_H
2#define _PROBE_FINDER_H 2#define _PROBE_FINDER_H
3 3
4#include <stdbool.h>
4#include "util.h" 5#include "util.h"
5 6
6#define MAX_PATH_LEN 256 7#define MAX_PATH_LEN 256
@@ -20,6 +21,7 @@ struct probe_point {
20 /* Inputs */ 21 /* Inputs */
21 char *file; /* File name */ 22 char *file; /* File name */
22 int line; /* Line number */ 23 int line; /* Line number */
24 char *lazy_line; /* Lazy line pattern */
23 25
24 char *function; /* Function name */ 26 char *function; /* Function name */
25 int offset; /* Offset bytes */ 27 int offset; /* Offset bytes */
@@ -46,53 +48,46 @@ struct line_range {
46 char *function; /* Function name */ 48 char *function; /* Function name */
47 unsigned int start; /* Start line number */ 49 unsigned int start; /* Start line number */
48 unsigned int end; /* End line number */ 50 unsigned int end; /* End line number */
49 unsigned int offset; /* Start line offset */ 51 int offset; /* Start line offset */
50 char *path; /* Real path name */ 52 char *path; /* Real path name */
51 struct list_head line_list; /* Visible lines */ 53 struct list_head line_list; /* Visible lines */
52}; 54};
53 55
54#ifndef NO_LIBDWARF 56#ifndef NO_DWARF_SUPPORT
55extern int find_probepoint(int fd, struct probe_point *pp); 57extern int find_probe_point(int fd, struct probe_point *pp);
56extern int find_line_range(int fd, struct line_range *lr); 58extern int find_line_range(int fd, struct line_range *lr);
57 59
58/* Workaround for undefined _MIPS_SZLONG bug in libdwarf.h: */
59#ifndef _MIPS_SZLONG
60# define _MIPS_SZLONG 0
61#endif
62
63#include <dwarf.h> 60#include <dwarf.h>
64#include <libdwarf.h> 61#include <libdw.h>
65 62
66struct probe_finder { 63struct probe_finder {
67 struct probe_point *pp; /* Target probe point */ 64 struct probe_point *pp; /* Target probe point */
68 65
69 /* For function searching */ 66 /* For function searching */
70 Dwarf_Addr addr; /* Address */ 67 Dwarf_Addr addr; /* Address */
71 Dwarf_Unsigned fno; /* File number */ 68 const char *fname; /* File name */
72 Dwarf_Unsigned lno; /* Line number */ 69 int lno; /* Line number */
73 Dwarf_Off inl_offs; /* Inline offset */ 70 Dwarf_Die cu_die; /* Current CU */
74 Dwarf_Die cu_die; /* Current CU */
75 71
76 /* For variable searching */ 72 /* For variable searching */
77 Dwarf_Addr cu_base; /* Current CU base address */ 73 Dwarf_Op *fb_ops; /* Frame base attribute */
78 Dwarf_Locdesc fbloc; /* Location of Current Frame Base */ 74 Dwarf_Addr cu_base; /* Current CU base address */
79 const char *var; /* Current variable name */ 75 const char *var; /* Current variable name */
80 char *buf; /* Current output buffer */ 76 char *buf; /* Current output buffer */
81 int len; /* Length of output buffer */ 77 int len; /* Length of output buffer */
78 struct list_head lcache; /* Line cache for lazy match */
82}; 79};
83 80
84struct line_finder { 81struct line_finder {
85 struct line_range *lr; /* Target line range */ 82 struct line_range *lr; /* Target line range */
86 83
87 Dwarf_Unsigned fno; /* File number */ 84 const char *fname; /* File name */
88 Dwarf_Unsigned lno_s; /* Start line number */ 85 int lno_s; /* Start line number */
89 Dwarf_Unsigned lno_e; /* End line number */ 86 int lno_e; /* End line number */
90 Dwarf_Addr addr_s; /* Start address */ 87 Dwarf_Die cu_die; /* Current CU */
91 Dwarf_Addr addr_e; /* End address */
92 Dwarf_Die cu_die; /* Current CU */
93 int found; 88 int found;
94}; 89};
95 90
96#endif /* NO_LIBDWARF */ 91#endif /* NO_DWARF_SUPPORT */
97 92
98#endif /*_PROBE_FINDER_H */ 93#endif /*_PROBE_FINDER_H */
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index c397d4f6f748..a175949ed216 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -265,21 +265,21 @@ error:
265 return false; 265 return false;
266} 266}
267 267
268/** 268/* Glob/lazy pattern matching */
269 * strglobmatch - glob expression pattern matching 269static bool __match_glob(const char *str, const char *pat, bool ignore_space)
270 * @str: the target string to match
271 * @pat: the pattern string to match
272 *
273 * This returns true if the @str matches @pat. @pat can includes wildcards
274 * ('*','?') and character classes ([CHARS], complementation and ranges are
275 * also supported). Also, this supports escape character ('\') to use special
276 * characters as normal character.
277 *
278 * Note: if @pat syntax is broken, this always returns false.
279 */
280bool strglobmatch(const char *str, const char *pat)
281{ 270{
282 while (*str && *pat && *pat != '*') { 271 while (*str && *pat && *pat != '*') {
272 if (ignore_space) {
273 /* Ignore spaces for lazy matching */
274 if (isspace(*str)) {
275 str++;
276 continue;
277 }
278 if (isspace(*pat)) {
279 pat++;
280 continue;
281 }
282 }
283 if (*pat == '?') { /* Matches any single character */ 283 if (*pat == '?') { /* Matches any single character */
284 str++; 284 str++;
285 pat++; 285 pat++;
@@ -308,3 +308,32 @@ bool strglobmatch(const char *str, const char *pat)
308 return !*str && !*pat; 308 return !*str && !*pat;
309} 309}
310 310
311/**
312 * strglobmatch - glob expression pattern matching
313 * @str: the target string to match
314 * @pat: the pattern string to match
315 *
316 * This returns true if the @str matches @pat. @pat can includes wildcards
317 * ('*','?') and character classes ([CHARS], complementation and ranges are
318 * also supported). Also, this supports escape character ('\') to use special
319 * characters as normal character.
320 *
321 * Note: if @pat syntax is broken, this always returns false.
322 */
323bool strglobmatch(const char *str, const char *pat)
324{
325 return __match_glob(str, pat, false);
326}
327
328/**
329 * strlazymatch - matching pattern strings lazily with glob pattern
330 * @str: the target string to match
331 * @pat: the pattern string to match
332 *
333 * This is similar to strglobmatch, except this ignores spaces in
334 * the target string.
335 */
336bool strlazymatch(const char *str, const char *pat)
337{
338 return __match_glob(str, pat, true);
339}
diff --git a/tools/perf/util/string.h b/tools/perf/util/string.h
index 02ede58c54b4..542e44de3719 100644
--- a/tools/perf/util/string.h
+++ b/tools/perf/util/string.h
@@ -10,6 +10,7 @@ s64 perf_atoll(const char *str);
10char **argv_split(const char *str, int *argcp); 10char **argv_split(const char *str, int *argcp);
11void argv_free(char **argv); 11void argv_free(char **argv);
12bool strglobmatch(const char *str, const char *pat); 12bool strglobmatch(const char *str, const char *pat);
13bool strlazymatch(const char *str, const char *pat);
13 14
14#define _STR(x) #x 15#define _STR(x) #x
15#define STR(x) _STR(x) 16#define STR(x) _STR(x)