diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/probe-event.c | 55 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 1002 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 53 | ||||
-rw-r--r-- | tools/perf/util/string.c | 55 | ||||
-rw-r--r-- | tools/perf/util/string.h | 1 |
5 files changed, 566 insertions, 600 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8f0568849691..c971e81e9cbf 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 | ||
723 | static void show_one_line(FILE *fp, unsigned int l, bool skip, bool show_num) | 736 | static 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 */ | ||
42 | struct die_link { | ||
43 | struct die_link *parent; /* Parent die */ | ||
44 | Dwarf_Die die; /* Current die */ | ||
45 | }; | ||
46 | |||
47 | static Dwarf_Debug __dw_debug; | ||
48 | static 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 */ |
117 | static 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; | 111 | static 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; | 126 | found: |
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 | ||
143 | static int cu_get_filename(Dwarf_Die cu_die, Dwarf_Unsigned fno, char **buf) | 135 | /* Check if the line in line number list */ |
136 | static 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 */ |
169 | static int die_compare_name(Dwarf_Die dw_die, const char *tname) | 149 | static 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 */ |
184 | static int die_within_subprogram(Dwarf_Die sp_die, Dwarf_Addr addr, | 155 | static 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 */ |
205 | static Dwarf_Bool die_inlined_subprogram(Dwarf_Die dw_die) | 166 | |
167 | /* Find the realpath of the target file. */ | ||
168 | static 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); |
217 | static 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 */ | 190 | struct __addr_die_search_param { |
232 | static Dwarf_Addr die_get_entrypc(Dwarf_Die dw_die) | 191 | Dwarf_Addr addr; |
192 | Dwarf_Die *die_mem; | ||
193 | }; | ||
194 | |||
195 | static 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); | 208 | static 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. | 222 | static 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 | */ | ||
274 | static 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)) { |
312 | static 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 */ |
329 | static int attr_get_locdesc(Dwarf_Attribute attr, Dwarf_Locdesc *desc, | 247 | static 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 */ |
364 | static Dwarf_Unsigned die_get_decl_file(Dwarf_Die sp_die) | 256 | static 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 */ |
379 | static Dwarf_Unsigned die_get_decl_line(Dwarf_Die sp_die) | 267 | static 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 */ |
398 | static void show_location(Dwarf_Loc *loc, struct probe_finder *pf) | 299 | static 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 */ |
446 | static void show_variable(Dwarf_Die vr_die, struct probe_finder *pf) | 345 | static 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 ; |
464 | error: | 363 | error: |
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 | ||
469 | static 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 */ |
488 | static void find_variable(Dwarf_Die sp_die, struct probe_finder *pf) | 370 | static 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 */ | ||
508 | static 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 | |||
520 | static 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 */ |
527 | static void show_probepoint(Dwarf_Die sp_die, Dwarf_Signed offs, | 393 | static 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 | ||
576 | static int probeaddr_callback(struct die_link *dlink, void *data) | 462 | /* Find probe point from its line number */ |
463 | static 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 */ |
595 | static void find_probe_point_by_line(struct probe_finder *pf) | 497 | static 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 */ | ||
530 | static 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 | |||
582 | static 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 */ |
637 | static int probefunc_callback(struct die_link *dlink, void *data) | 603 | static 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."); | ||
690 | found: | ||
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 | ||
701 | static void find_probe_point_by_func(struct probe_finder *pf) | 635 | static 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 */ |
707 | int find_probepoint(int fd, struct probe_point *pp) | 641 | int 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 | |||
757 | static 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; | ||
772 | found: | ||
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 */ |
782 | static void find_line_range_by_line(struct line_finder *lf) | 693 | static 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 | |||
746 | static 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 */ |
820 | static int linefunc_callback(struct die_link *dlink, void *data) | 753 | static 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 | ||
858 | static void find_line_range_by_func(struct line_finder *lf) | 780 | static 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 | ||
863 | int find_line_range(int fd, struct line_range *lr) | 785 | int 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 |
55 | extern int find_probepoint(int fd, struct probe_point *pp); | 57 | extern int find_probe_point(int fd, struct probe_point *pp); |
56 | extern int find_line_range(int fd, struct line_range *lr); | 58 | extern 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 | ||
66 | struct probe_finder { | 63 | struct 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 | ||
84 | struct line_finder { | 81 | struct 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 | 269 | static 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 | */ | ||
280 | bool 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 | */ | ||
323 | bool 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 | */ | ||
336 | bool 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); | |||
10 | char **argv_split(const char *str, int *argcp); | 10 | char **argv_split(const char *str, int *argcp); |
11 | void argv_free(char **argv); | 11 | void argv_free(char **argv); |
12 | bool strglobmatch(const char *str, const char *pat); | 12 | bool strglobmatch(const char *str, const char *pat); |
13 | bool 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) |