diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 981 |
1 files changed, 243 insertions, 738 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3b9d0b800d5..5d732621a46 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -43,21 +43,6 @@ | |||
43 | /* Kprobe tracer basic type is up to u64 */ | 43 | /* Kprobe tracer basic type is up to u64 */ |
44 | #define MAX_BASIC_TYPE_BITS 64 | 44 | #define MAX_BASIC_TYPE_BITS 64 |
45 | 45 | ||
46 | /* | ||
47 | * Compare the tail of two strings. | ||
48 | * Return 0 if whole of either string is same as another's tail part. | ||
49 | */ | ||
50 | static int strtailcmp(const char *s1, const char *s2) | ||
51 | { | ||
52 | int i1 = strlen(s1); | ||
53 | int i2 = strlen(s2); | ||
54 | while (--i1 >= 0 && --i2 >= 0) { | ||
55 | if (s1[i1] != s2[i2]) | ||
56 | return s1[i1] - s2[i2]; | ||
57 | } | ||
58 | return 0; | ||
59 | } | ||
60 | |||
61 | /* Line number list operations */ | 46 | /* Line number list operations */ |
62 | 47 | ||
63 | /* Add a line to line number list */ | 48 | /* Add a line to line number list */ |
@@ -131,29 +116,37 @@ static const Dwfl_Callbacks offline_callbacks = { | |||
131 | }; | 116 | }; |
132 | 117 | ||
133 | /* Get a Dwarf from offline image */ | 118 | /* Get a Dwarf from offline image */ |
134 | static Dwarf *dwfl_init_offline_dwarf(int fd, Dwfl **dwflp, Dwarf_Addr *bias) | 119 | static int debuginfo__init_offline_dwarf(struct debuginfo *self, |
120 | const char *path) | ||
135 | { | 121 | { |
136 | Dwfl_Module *mod; | 122 | Dwfl_Module *mod; |
137 | Dwarf *dbg = NULL; | 123 | int fd; |
138 | 124 | ||
139 | if (!dwflp) | 125 | fd = open(path, O_RDONLY); |
140 | return NULL; | 126 | if (fd < 0) |
127 | return fd; | ||
141 | 128 | ||
142 | *dwflp = dwfl_begin(&offline_callbacks); | 129 | self->dwfl = dwfl_begin(&offline_callbacks); |
143 | if (!*dwflp) | 130 | if (!self->dwfl) |
144 | return NULL; | 131 | goto error; |
145 | 132 | ||
146 | mod = dwfl_report_offline(*dwflp, "", "", fd); | 133 | mod = dwfl_report_offline(self->dwfl, "", "", fd); |
147 | if (!mod) | 134 | if (!mod) |
148 | goto error; | 135 | goto error; |
149 | 136 | ||
150 | dbg = dwfl_module_getdwarf(mod, bias); | 137 | self->dbg = dwfl_module_getdwarf(mod, &self->bias); |
151 | if (!dbg) { | 138 | if (!self->dbg) |
139 | goto error; | ||
140 | |||
141 | return 0; | ||
152 | error: | 142 | error: |
153 | dwfl_end(*dwflp); | 143 | if (self->dwfl) |
154 | *dwflp = NULL; | 144 | dwfl_end(self->dwfl); |
155 | } | 145 | else |
156 | return dbg; | 146 | close(fd); |
147 | memset(self, 0, sizeof(*self)); | ||
148 | |||
149 | return -ENOENT; | ||
157 | } | 150 | } |
158 | 151 | ||
159 | #if _ELFUTILS_PREREQ(0, 148) | 152 | #if _ELFUTILS_PREREQ(0, 148) |
@@ -189,597 +182,81 @@ static const Dwfl_Callbacks kernel_callbacks = { | |||
189 | }; | 182 | }; |
190 | 183 | ||
191 | /* Get a Dwarf from live kernel image */ | 184 | /* Get a Dwarf from live kernel image */ |
192 | static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr, Dwfl **dwflp, | 185 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, |
193 | Dwarf_Addr *bias) | 186 | Dwarf_Addr addr) |
194 | { | 187 | { |
195 | Dwarf *dbg; | 188 | self->dwfl = dwfl_begin(&kernel_callbacks); |
196 | 189 | if (!self->dwfl) | |
197 | if (!dwflp) | 190 | return -EINVAL; |
198 | return NULL; | ||
199 | |||
200 | *dwflp = dwfl_begin(&kernel_callbacks); | ||
201 | if (!*dwflp) | ||
202 | return NULL; | ||
203 | 191 | ||
204 | /* Load the kernel dwarves: Don't care the result here */ | 192 | /* Load the kernel dwarves: Don't care the result here */ |
205 | dwfl_linux_kernel_report_kernel(*dwflp); | 193 | dwfl_linux_kernel_report_kernel(self->dwfl); |
206 | dwfl_linux_kernel_report_modules(*dwflp); | 194 | dwfl_linux_kernel_report_modules(self->dwfl); |
207 | 195 | ||
208 | dbg = dwfl_addrdwarf(*dwflp, addr, bias); | 196 | self->dbg = dwfl_addrdwarf(self->dwfl, addr, &self->bias); |
209 | /* Here, check whether we could get a real dwarf */ | 197 | /* Here, check whether we could get a real dwarf */ |
210 | if (!dbg) { | 198 | if (!self->dbg) { |
211 | pr_debug("Failed to find kernel dwarf at %lx\n", | 199 | pr_debug("Failed to find kernel dwarf at %lx\n", |
212 | (unsigned long)addr); | 200 | (unsigned long)addr); |
213 | dwfl_end(*dwflp); | 201 | dwfl_end(self->dwfl); |
214 | *dwflp = NULL; | 202 | memset(self, 0, sizeof(*self)); |
203 | return -ENOENT; | ||
215 | } | 204 | } |
216 | return dbg; | 205 | |
206 | return 0; | ||
217 | } | 207 | } |
218 | #else | 208 | #else |
219 | /* With older elfutils, this just support kernel module... */ | 209 | /* With older elfutils, this just support kernel module... */ |
220 | static Dwarf *dwfl_init_live_kernel_dwarf(Dwarf_Addr addr __used, Dwfl **dwflp, | 210 | static int debuginfo__init_online_kernel_dwarf(struct debuginfo *self, |
221 | Dwarf_Addr *bias) | 211 | Dwarf_Addr addr __used) |
222 | { | 212 | { |
223 | int fd; | ||
224 | const char *path = kernel_get_module_path("kernel"); | 213 | const char *path = kernel_get_module_path("kernel"); |
225 | 214 | ||
226 | if (!path) { | 215 | if (!path) { |
227 | pr_err("Failed to find vmlinux path\n"); | 216 | pr_err("Failed to find vmlinux path\n"); |
228 | return NULL; | 217 | return -ENOENT; |
229 | } | 218 | } |
230 | 219 | ||
231 | pr_debug2("Use file %s for debuginfo\n", path); | 220 | pr_debug2("Use file %s for debuginfo\n", path); |
232 | fd = open(path, O_RDONLY); | 221 | return debuginfo__init_offline_dwarf(self, path); |
233 | if (fd < 0) | ||
234 | return NULL; | ||
235 | |||
236 | return dwfl_init_offline_dwarf(fd, dwflp, bias); | ||
237 | } | 222 | } |
238 | #endif | 223 | #endif |
239 | 224 | ||
240 | /* Dwarf wrappers */ | 225 | struct debuginfo *debuginfo__new(const char *path) |
241 | |||
242 | /* Find the realpath of the target file. */ | ||
243 | static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | ||
244 | { | 226 | { |
245 | Dwarf_Files *files; | 227 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); |
246 | size_t nfiles, i; | 228 | if (!self) |
247 | const char *src = NULL; | ||
248 | int ret; | ||
249 | |||
250 | if (!fname) | ||
251 | return NULL; | 229 | return NULL; |
252 | 230 | ||
253 | ret = dwarf_getsrcfiles(cu_die, &files, &nfiles); | 231 | if (debuginfo__init_offline_dwarf(self, path) < 0) { |
254 | if (ret != 0) | 232 | free(self); |
255 | return NULL; | 233 | self = NULL; |
256 | |||
257 | for (i = 0; i < nfiles; i++) { | ||
258 | src = dwarf_filesrc(files, i, NULL, NULL); | ||
259 | if (strtailcmp(src, fname) == 0) | ||
260 | break; | ||
261 | } | 234 | } |
262 | if (i == nfiles) | ||
263 | return NULL; | ||
264 | return src; | ||
265 | } | ||
266 | 235 | ||
267 | /* Get DW_AT_comp_dir (should be NULL with older gcc) */ | 236 | return self; |
268 | static const char *cu_get_comp_dir(Dwarf_Die *cu_die) | ||
269 | { | ||
270 | Dwarf_Attribute attr; | ||
271 | if (dwarf_attr(cu_die, DW_AT_comp_dir, &attr) == NULL) | ||
272 | return NULL; | ||
273 | return dwarf_formstring(&attr); | ||
274 | } | 237 | } |
275 | 238 | ||
276 | /* Get a line number and file name for given address */ | 239 | struct debuginfo *debuginfo__new_online_kernel(unsigned long addr) |
277 | static int cu_find_lineinfo(Dwarf_Die *cudie, unsigned long addr, | ||
278 | const char **fname, int *lineno) | ||
279 | { | 240 | { |
280 | Dwarf_Line *line; | 241 | struct debuginfo *self = zalloc(sizeof(struct debuginfo)); |
281 | Dwarf_Addr laddr; | 242 | if (!self) |
282 | |||
283 | line = dwarf_getsrc_die(cudie, (Dwarf_Addr)addr); | ||
284 | if (line && dwarf_lineaddr(line, &laddr) == 0 && | ||
285 | addr == (unsigned long)laddr && dwarf_lineno(line, lineno) == 0) { | ||
286 | *fname = dwarf_linesrc(line, NULL, NULL); | ||
287 | if (!*fname) | ||
288 | /* line number is useless without filename */ | ||
289 | *lineno = 0; | ||
290 | } | ||
291 | |||
292 | return *lineno ?: -ENOENT; | ||
293 | } | ||
294 | |||
295 | /* Compare diename and tname */ | ||
296 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | ||
297 | { | ||
298 | const char *name; | ||
299 | name = dwarf_diename(dw_die); | ||
300 | return name ? (strcmp(tname, name) == 0) : false; | ||
301 | } | ||
302 | |||
303 | /* Get callsite line number of inline-function instance */ | ||
304 | static int die_get_call_lineno(Dwarf_Die *in_die) | ||
305 | { | ||
306 | Dwarf_Attribute attr; | ||
307 | Dwarf_Word ret; | ||
308 | |||
309 | if (!dwarf_attr(in_die, DW_AT_call_line, &attr)) | ||
310 | return -ENOENT; | ||
311 | |||
312 | dwarf_formudata(&attr, &ret); | ||
313 | return (int)ret; | ||
314 | } | ||
315 | |||
316 | /* Get type die */ | ||
317 | static Dwarf_Die *die_get_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | ||
318 | { | ||
319 | Dwarf_Attribute attr; | ||
320 | |||
321 | if (dwarf_attr_integrate(vr_die, DW_AT_type, &attr) && | ||
322 | dwarf_formref_die(&attr, die_mem)) | ||
323 | return die_mem; | ||
324 | else | ||
325 | return NULL; | 243 | return NULL; |
326 | } | ||
327 | |||
328 | /* Get a type die, but skip qualifiers */ | ||
329 | static Dwarf_Die *__die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | ||
330 | { | ||
331 | int tag; | ||
332 | |||
333 | do { | ||
334 | vr_die = die_get_type(vr_die, die_mem); | ||
335 | if (!vr_die) | ||
336 | break; | ||
337 | tag = dwarf_tag(vr_die); | ||
338 | } while (tag == DW_TAG_const_type || | ||
339 | tag == DW_TAG_restrict_type || | ||
340 | tag == DW_TAG_volatile_type || | ||
341 | tag == DW_TAG_shared_type); | ||
342 | |||
343 | return vr_die; | ||
344 | } | ||
345 | |||
346 | /* Get a type die, but skip qualifiers and typedef */ | ||
347 | static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | ||
348 | { | ||
349 | do { | ||
350 | vr_die = __die_get_real_type(vr_die, die_mem); | ||
351 | } while (vr_die && dwarf_tag(vr_die) == DW_TAG_typedef); | ||
352 | |||
353 | return vr_die; | ||
354 | } | ||
355 | |||
356 | static int die_get_attr_udata(Dwarf_Die *tp_die, unsigned int attr_name, | ||
357 | Dwarf_Word *result) | ||
358 | { | ||
359 | Dwarf_Attribute attr; | ||
360 | |||
361 | if (dwarf_attr(tp_die, attr_name, &attr) == NULL || | ||
362 | dwarf_formudata(&attr, result) != 0) | ||
363 | return -ENOENT; | ||
364 | |||
365 | return 0; | ||
366 | } | ||
367 | 244 | ||
368 | static bool die_is_signed_type(Dwarf_Die *tp_die) | 245 | if (debuginfo__init_online_kernel_dwarf(self, (Dwarf_Addr)addr) < 0) { |
369 | { | 246 | free(self); |
370 | Dwarf_Word ret; | 247 | self = NULL; |
371 | |||
372 | if (die_get_attr_udata(tp_die, DW_AT_encoding, &ret)) | ||
373 | return false; | ||
374 | |||
375 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || | ||
376 | ret == DW_ATE_signed_fixed); | ||
377 | } | ||
378 | |||
379 | static int die_get_byte_size(Dwarf_Die *tp_die) | ||
380 | { | ||
381 | Dwarf_Word ret; | ||
382 | |||
383 | if (die_get_attr_udata(tp_die, DW_AT_byte_size, &ret)) | ||
384 | return 0; | ||
385 | |||
386 | return (int)ret; | ||
387 | } | ||
388 | |||
389 | static int die_get_bit_size(Dwarf_Die *tp_die) | ||
390 | { | ||
391 | Dwarf_Word ret; | ||
392 | |||
393 | if (die_get_attr_udata(tp_die, DW_AT_bit_size, &ret)) | ||
394 | return 0; | ||
395 | |||
396 | return (int)ret; | ||
397 | } | ||
398 | |||
399 | static int die_get_bit_offset(Dwarf_Die *tp_die) | ||
400 | { | ||
401 | Dwarf_Word ret; | ||
402 | |||
403 | if (die_get_attr_udata(tp_die, DW_AT_bit_offset, &ret)) | ||
404 | return 0; | ||
405 | |||
406 | return (int)ret; | ||
407 | } | ||
408 | |||
409 | /* Get data_member_location offset */ | ||
410 | static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | ||
411 | { | ||
412 | Dwarf_Attribute attr; | ||
413 | Dwarf_Op *expr; | ||
414 | size_t nexpr; | ||
415 | int ret; | ||
416 | |||
417 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) | ||
418 | return -ENOENT; | ||
419 | |||
420 | if (dwarf_formudata(&attr, offs) != 0) { | ||
421 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ | ||
422 | ret = dwarf_getlocation(&attr, &expr, &nexpr); | ||
423 | if (ret < 0 || nexpr == 0) | ||
424 | return -ENOENT; | ||
425 | |||
426 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { | ||
427 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", | ||
428 | expr[0].atom, nexpr); | ||
429 | return -ENOTSUP; | ||
430 | } | ||
431 | *offs = (Dwarf_Word)expr[0].number; | ||
432 | } | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | /* Return values for die_find callbacks */ | ||
437 | enum { | ||
438 | DIE_FIND_CB_FOUND = 0, /* End of Search */ | ||
439 | DIE_FIND_CB_CHILD = 1, /* Search only children */ | ||
440 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ | ||
441 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ | ||
442 | }; | ||
443 | |||
444 | /* Search a child die */ | ||
445 | static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | ||
446 | int (*callback)(Dwarf_Die *, void *), | ||
447 | void *data, Dwarf_Die *die_mem) | ||
448 | { | ||
449 | Dwarf_Die child_die; | ||
450 | int ret; | ||
451 | |||
452 | ret = dwarf_child(rt_die, die_mem); | ||
453 | if (ret != 0) | ||
454 | return NULL; | ||
455 | |||
456 | do { | ||
457 | ret = callback(die_mem, data); | ||
458 | if (ret == DIE_FIND_CB_FOUND) | ||
459 | return die_mem; | ||
460 | |||
461 | if ((ret & DIE_FIND_CB_CHILD) && | ||
462 | die_find_child(die_mem, callback, data, &child_die)) { | ||
463 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | ||
464 | return die_mem; | ||
465 | } | ||
466 | } while ((ret & DIE_FIND_CB_SIBLING) && | ||
467 | dwarf_siblingof(die_mem, die_mem) == 0); | ||
468 | |||
469 | return NULL; | ||
470 | } | ||
471 | |||
472 | struct __addr_die_search_param { | ||
473 | Dwarf_Addr addr; | ||
474 | Dwarf_Die *die_mem; | ||
475 | }; | ||
476 | |||
477 | static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | ||
478 | { | ||
479 | struct __addr_die_search_param *ad = data; | ||
480 | |||
481 | if (dwarf_tag(fn_die) == DW_TAG_subprogram && | ||
482 | dwarf_haspc(fn_die, ad->addr)) { | ||
483 | memcpy(ad->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
484 | return DWARF_CB_ABORT; | ||
485 | } | 248 | } |
486 | return DWARF_CB_OK; | ||
487 | } | ||
488 | 249 | ||
489 | /* Search a real subprogram including this line, */ | 250 | return self; |
490 | static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, | ||
491 | Dwarf_Die *die_mem) | ||
492 | { | ||
493 | struct __addr_die_search_param ad; | ||
494 | ad.addr = addr; | ||
495 | ad.die_mem = die_mem; | ||
496 | /* dwarf_getscopes can't find subprogram. */ | ||
497 | if (!dwarf_getfuncs(cu_die, __die_search_func_cb, &ad, 0)) | ||
498 | return NULL; | ||
499 | else | ||
500 | return die_mem; | ||
501 | } | 251 | } |
502 | 252 | ||
503 | /* die_find callback for inline function search */ | 253 | void debuginfo__delete(struct debuginfo *self) |
504 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) | ||
505 | { | 254 | { |
506 | Dwarf_Addr *addr = data; | 255 | if (self) { |
507 | 256 | if (self->dwfl) | |
508 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && | 257 | dwfl_end(self->dwfl); |
509 | dwarf_haspc(die_mem, *addr)) | 258 | free(self); |
510 | return DIE_FIND_CB_FOUND; | ||
511 | |||
512 | return DIE_FIND_CB_CONTINUE; | ||
513 | } | ||
514 | |||
515 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ | ||
516 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | ||
517 | Dwarf_Die *die_mem) | ||
518 | { | ||
519 | Dwarf_Die tmp_die; | ||
520 | |||
521 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, &tmp_die); | ||
522 | if (!sp_die) | ||
523 | return NULL; | ||
524 | |||
525 | /* Inlined function could be recursive. Trace it until fail */ | ||
526 | while (sp_die) { | ||
527 | memcpy(die_mem, sp_die, sizeof(Dwarf_Die)); | ||
528 | sp_die = die_find_child(sp_die, __die_find_inline_cb, &addr, | ||
529 | &tmp_die); | ||
530 | } | ||
531 | |||
532 | return die_mem; | ||
533 | } | ||
534 | |||
535 | /* Walker on lines (Note: line number will not be sorted) */ | ||
536 | typedef int (* line_walk_handler_t) (const char *fname, int lineno, | ||
537 | Dwarf_Addr addr, void *data); | ||
538 | |||
539 | struct __line_walk_param { | ||
540 | const char *fname; | ||
541 | line_walk_handler_t handler; | ||
542 | void *data; | ||
543 | int retval; | ||
544 | }; | ||
545 | |||
546 | static int __die_walk_funclines_cb(Dwarf_Die *in_die, void *data) | ||
547 | { | ||
548 | struct __line_walk_param *lw = data; | ||
549 | Dwarf_Addr addr; | ||
550 | int lineno; | ||
551 | |||
552 | if (dwarf_tag(in_die) == DW_TAG_inlined_subroutine) { | ||
553 | lineno = die_get_call_lineno(in_die); | ||
554 | if (lineno > 0 && dwarf_entrypc(in_die, &addr) == 0) { | ||
555 | lw->retval = lw->handler(lw->fname, lineno, addr, | ||
556 | lw->data); | ||
557 | if (lw->retval != 0) | ||
558 | return DIE_FIND_CB_FOUND; | ||
559 | } | ||
560 | } | 259 | } |
561 | return DIE_FIND_CB_SIBLING; | ||
562 | } | ||
563 | |||
564 | /* Walk on lines of blocks included in given DIE */ | ||
565 | static int __die_walk_funclines(Dwarf_Die *sp_die, | ||
566 | line_walk_handler_t handler, void *data) | ||
567 | { | ||
568 | struct __line_walk_param lw = { | ||
569 | .handler = handler, | ||
570 | .data = data, | ||
571 | .retval = 0, | ||
572 | }; | ||
573 | Dwarf_Die die_mem; | ||
574 | Dwarf_Addr addr; | ||
575 | int lineno; | ||
576 | |||
577 | /* Handle function declaration line */ | ||
578 | lw.fname = dwarf_decl_file(sp_die); | ||
579 | if (lw.fname && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
580 | dwarf_entrypc(sp_die, &addr) == 0) { | ||
581 | lw.retval = handler(lw.fname, lineno, addr, data); | ||
582 | if (lw.retval != 0) | ||
583 | goto done; | ||
584 | } | ||
585 | die_find_child(sp_die, __die_walk_funclines_cb, &lw, &die_mem); | ||
586 | done: | ||
587 | return lw.retval; | ||
588 | } | ||
589 | |||
590 | static int __die_walk_culines_cb(Dwarf_Die *sp_die, void *data) | ||
591 | { | ||
592 | struct __line_walk_param *lw = data; | ||
593 | |||
594 | lw->retval = __die_walk_funclines(sp_die, lw->handler, lw->data); | ||
595 | if (lw->retval != 0) | ||
596 | return DWARF_CB_ABORT; | ||
597 | |||
598 | return DWARF_CB_OK; | ||
599 | } | ||
600 | |||
601 | /* | ||
602 | * Walk on lines inside given PDIE. If the PDIE is subprogram, walk only on | ||
603 | * the lines inside the subprogram, otherwise PDIE must be a CU DIE. | ||
604 | */ | ||
605 | static int die_walk_lines(Dwarf_Die *pdie, line_walk_handler_t handler, | ||
606 | void *data) | ||
607 | { | ||
608 | Dwarf_Lines *lines; | ||
609 | Dwarf_Line *line; | ||
610 | Dwarf_Addr addr; | ||
611 | const char *fname; | ||
612 | int lineno, ret = 0; | ||
613 | Dwarf_Die die_mem, *cu_die; | ||
614 | size_t nlines, i; | ||
615 | |||
616 | /* Get the CU die */ | ||
617 | if (dwarf_tag(pdie) == DW_TAG_subprogram) | ||
618 | cu_die = dwarf_diecu(pdie, &die_mem, NULL, NULL); | ||
619 | else | ||
620 | cu_die = pdie; | ||
621 | if (!cu_die) { | ||
622 | pr_debug2("Failed to get CU from subprogram\n"); | ||
623 | return -EINVAL; | ||
624 | } | ||
625 | |||
626 | /* Get lines list in the CU */ | ||
627 | if (dwarf_getsrclines(cu_die, &lines, &nlines) != 0) { | ||
628 | pr_debug2("Failed to get source lines on this CU.\n"); | ||
629 | return -ENOENT; | ||
630 | } | ||
631 | pr_debug2("Get %zd lines from this CU\n", nlines); | ||
632 | |||
633 | /* Walk on the lines on lines list */ | ||
634 | for (i = 0; i < nlines; i++) { | ||
635 | line = dwarf_onesrcline(lines, i); | ||
636 | if (line == NULL || | ||
637 | dwarf_lineno(line, &lineno) != 0 || | ||
638 | dwarf_lineaddr(line, &addr) != 0) { | ||
639 | pr_debug2("Failed to get line info. " | ||
640 | "Possible error in debuginfo.\n"); | ||
641 | continue; | ||
642 | } | ||
643 | /* Filter lines based on address */ | ||
644 | if (pdie != cu_die) | ||
645 | /* | ||
646 | * Address filtering | ||
647 | * The line is included in given function, and | ||
648 | * no inline block includes it. | ||
649 | */ | ||
650 | if (!dwarf_haspc(pdie, addr) || | ||
651 | die_find_inlinefunc(pdie, addr, &die_mem)) | ||
652 | continue; | ||
653 | /* Get source line */ | ||
654 | fname = dwarf_linesrc(line, NULL, NULL); | ||
655 | |||
656 | ret = handler(fname, lineno, addr, data); | ||
657 | if (ret != 0) | ||
658 | return ret; | ||
659 | } | ||
660 | |||
661 | /* | ||
662 | * Dwarf lines doesn't include function declarations and inlined | ||
663 | * subroutines. We have to check functions list or given function. | ||
664 | */ | ||
665 | if (pdie != cu_die) | ||
666 | ret = __die_walk_funclines(pdie, handler, data); | ||
667 | else { | ||
668 | struct __line_walk_param param = { | ||
669 | .handler = handler, | ||
670 | .data = data, | ||
671 | .retval = 0, | ||
672 | }; | ||
673 | dwarf_getfuncs(cu_die, __die_walk_culines_cb, ¶m, 0); | ||
674 | ret = param.retval; | ||
675 | } | ||
676 | |||
677 | return ret; | ||
678 | } | ||
679 | |||
680 | struct __find_variable_param { | ||
681 | const char *name; | ||
682 | Dwarf_Addr addr; | ||
683 | }; | ||
684 | |||
685 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) | ||
686 | { | ||
687 | struct __find_variable_param *fvp = data; | ||
688 | int tag; | ||
689 | |||
690 | tag = dwarf_tag(die_mem); | ||
691 | if ((tag == DW_TAG_formal_parameter || | ||
692 | tag == DW_TAG_variable) && | ||
693 | die_compare_name(die_mem, fvp->name)) | ||
694 | return DIE_FIND_CB_FOUND; | ||
695 | |||
696 | if (dwarf_haspc(die_mem, fvp->addr)) | ||
697 | return DIE_FIND_CB_CONTINUE; | ||
698 | else | ||
699 | return DIE_FIND_CB_SIBLING; | ||
700 | } | ||
701 | |||
702 | /* Find a variable called 'name' at given address */ | ||
703 | static Dwarf_Die *die_find_variable_at(Dwarf_Die *sp_die, const char *name, | ||
704 | Dwarf_Addr addr, Dwarf_Die *die_mem) | ||
705 | { | ||
706 | struct __find_variable_param fvp = { .name = name, .addr = addr}; | ||
707 | |||
708 | return die_find_child(sp_die, __die_find_variable_cb, (void *)&fvp, | ||
709 | die_mem); | ||
710 | } | ||
711 | |||
712 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) | ||
713 | { | ||
714 | const char *name = data; | ||
715 | |||
716 | if ((dwarf_tag(die_mem) == DW_TAG_member) && | ||
717 | die_compare_name(die_mem, name)) | ||
718 | return DIE_FIND_CB_FOUND; | ||
719 | |||
720 | return DIE_FIND_CB_SIBLING; | ||
721 | } | ||
722 | |||
723 | /* Find a member called 'name' */ | ||
724 | static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | ||
725 | Dwarf_Die *die_mem) | ||
726 | { | ||
727 | return die_find_child(st_die, __die_find_member_cb, (void *)name, | ||
728 | die_mem); | ||
729 | } | ||
730 | |||
731 | /* Get the name of given variable DIE */ | ||
732 | static int die_get_typename(Dwarf_Die *vr_die, char *buf, int len) | ||
733 | { | ||
734 | Dwarf_Die type; | ||
735 | int tag, ret, ret2; | ||
736 | const char *tmp = ""; | ||
737 | |||
738 | if (__die_get_real_type(vr_die, &type) == NULL) | ||
739 | return -ENOENT; | ||
740 | |||
741 | tag = dwarf_tag(&type); | ||
742 | if (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type) | ||
743 | tmp = "*"; | ||
744 | else if (tag == DW_TAG_subroutine_type) { | ||
745 | /* Function pointer */ | ||
746 | ret = snprintf(buf, len, "(function_type)"); | ||
747 | return (ret >= len) ? -E2BIG : ret; | ||
748 | } else { | ||
749 | if (!dwarf_diename(&type)) | ||
750 | return -ENOENT; | ||
751 | if (tag == DW_TAG_union_type) | ||
752 | tmp = "union "; | ||
753 | else if (tag == DW_TAG_structure_type) | ||
754 | tmp = "struct "; | ||
755 | /* Write a base name */ | ||
756 | ret = snprintf(buf, len, "%s%s", tmp, dwarf_diename(&type)); | ||
757 | return (ret >= len) ? -E2BIG : ret; | ||
758 | } | ||
759 | ret = die_get_typename(&type, buf, len); | ||
760 | if (ret > 0) { | ||
761 | ret2 = snprintf(buf + ret, len - ret, "%s", tmp); | ||
762 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; | ||
763 | } | ||
764 | return ret; | ||
765 | } | ||
766 | |||
767 | /* Get the name and type of given variable DIE, stored as "type\tname" */ | ||
768 | static int die_get_varname(Dwarf_Die *vr_die, char *buf, int len) | ||
769 | { | ||
770 | int ret, ret2; | ||
771 | |||
772 | ret = die_get_typename(vr_die, buf, len); | ||
773 | if (ret < 0) { | ||
774 | pr_debug("Failed to get type, make it unknown.\n"); | ||
775 | ret = snprintf(buf, len, "(unknown_type)"); | ||
776 | } | ||
777 | if (ret > 0) { | ||
778 | ret2 = snprintf(buf + ret, len - ret, "\t%s", | ||
779 | dwarf_diename(vr_die)); | ||
780 | ret = (ret2 >= len - ret) ? -E2BIG : ret2 + ret; | ||
781 | } | ||
782 | return ret; | ||
783 | } | 260 | } |
784 | 261 | ||
785 | /* | 262 | /* |
@@ -897,6 +374,7 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
897 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; | 374 | struct probe_trace_arg_ref **ref_ptr = &tvar->ref; |
898 | Dwarf_Die type; | 375 | Dwarf_Die type; |
899 | char buf[16]; | 376 | char buf[16]; |
377 | int bsize, boffs, total; | ||
900 | int ret; | 378 | int ret; |
901 | 379 | ||
902 | /* TODO: check all types */ | 380 | /* TODO: check all types */ |
@@ -906,11 +384,15 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
906 | return (tvar->type == NULL) ? -ENOMEM : 0; | 384 | return (tvar->type == NULL) ? -ENOMEM : 0; |
907 | } | 385 | } |
908 | 386 | ||
909 | if (die_get_bit_size(vr_die) != 0) { | 387 | bsize = dwarf_bitsize(vr_die); |
388 | if (bsize > 0) { | ||
910 | /* This is a bitfield */ | 389 | /* This is a bitfield */ |
911 | ret = snprintf(buf, 16, "b%d@%d/%zd", die_get_bit_size(vr_die), | 390 | boffs = dwarf_bitoffset(vr_die); |
912 | die_get_bit_offset(vr_die), | 391 | total = dwarf_bytesize(vr_die); |
913 | BYTES_TO_BITS(die_get_byte_size(vr_die))); | 392 | if (boffs < 0 || total < 0) |
393 | return -ENOENT; | ||
394 | ret = snprintf(buf, 16, "b%d@%d/%zd", bsize, boffs, | ||
395 | BYTES_TO_BITS(total)); | ||
914 | goto formatted; | 396 | goto formatted; |
915 | } | 397 | } |
916 | 398 | ||
@@ -958,10 +440,11 @@ static int convert_variable_type(Dwarf_Die *vr_die, | |||
958 | return (tvar->type == NULL) ? -ENOMEM : 0; | 440 | return (tvar->type == NULL) ? -ENOMEM : 0; |
959 | } | 441 | } |
960 | 442 | ||
961 | ret = BYTES_TO_BITS(die_get_byte_size(&type)); | 443 | ret = dwarf_bytesize(&type); |
962 | if (!ret) | 444 | if (ret <= 0) |
963 | /* No size ... try to use default type */ | 445 | /* No size ... try to use default type */ |
964 | return 0; | 446 | return 0; |
447 | ret = BYTES_TO_BITS(ret); | ||
965 | 448 | ||
966 | /* Check the bitwidth */ | 449 | /* Check the bitwidth */ |
967 | if (ret > MAX_BASIC_TYPE_BITS) { | 450 | if (ret > MAX_BASIC_TYPE_BITS) { |
@@ -1025,7 +508,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
1025 | else | 508 | else |
1026 | *ref_ptr = ref; | 509 | *ref_ptr = ref; |
1027 | } | 510 | } |
1028 | ref->offset += die_get_byte_size(&type) * field->index; | 511 | ref->offset += dwarf_bytesize(&type) * field->index; |
1029 | if (!field->next) | 512 | if (!field->next) |
1030 | /* Save vr_die for converting types */ | 513 | /* Save vr_die for converting types */ |
1031 | memcpy(die_mem, vr_die, sizeof(*die_mem)); | 514 | memcpy(die_mem, vr_die, sizeof(*die_mem)); |
@@ -1129,12 +612,12 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
1129 | return ret; | 612 | return ret; |
1130 | } | 613 | } |
1131 | 614 | ||
1132 | /* Find a variable in a subprogram die */ | 615 | /* Find a variable in a scope DIE */ |
1133 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 616 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
1134 | { | 617 | { |
1135 | Dwarf_Die vr_die, *scopes; | 618 | Dwarf_Die vr_die; |
1136 | char buf[32], *ptr; | 619 | char buf[32], *ptr; |
1137 | int ret, nscopes; | 620 | int ret = 0; |
1138 | 621 | ||
1139 | if (!is_c_varname(pf->pvar->var)) { | 622 | if (!is_c_varname(pf->pvar->var)) { |
1140 | /* Copy raw parameters */ | 623 | /* Copy raw parameters */ |
@@ -1169,30 +652,16 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1169 | if (pf->tvar->name == NULL) | 652 | if (pf->tvar->name == NULL) |
1170 | return -ENOMEM; | 653 | return -ENOMEM; |
1171 | 654 | ||
1172 | pr_debug("Searching '%s' variable in context.\n", | 655 | pr_debug("Searching '%s' variable in context.\n", pf->pvar->var); |
1173 | pf->pvar->var); | ||
1174 | /* Search child die for local variables and parameters. */ | 656 | /* Search child die for local variables and parameters. */ |
1175 | if (die_find_variable_at(sp_die, pf->pvar->var, pf->addr, &vr_die)) | 657 | if (!die_find_variable_at(sc_die, pf->pvar->var, pf->addr, &vr_die)) { |
1176 | ret = convert_variable(&vr_die, pf); | 658 | /* Search again in global variables */ |
1177 | else { | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
1178 | /* Search upper class */ | 660 | ret = -ENOENT; |
1179 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | ||
1180 | while (nscopes-- > 1) { | ||
1181 | pr_debug("Searching variables in %s\n", | ||
1182 | dwarf_diename(&scopes[nscopes])); | ||
1183 | /* We should check this scope, so give dummy address */ | ||
1184 | if (die_find_variable_at(&scopes[nscopes], | ||
1185 | pf->pvar->var, 0, | ||
1186 | &vr_die)) { | ||
1187 | ret = convert_variable(&vr_die, pf); | ||
1188 | goto found; | ||
1189 | } | ||
1190 | } | ||
1191 | if (scopes) | ||
1192 | free(scopes); | ||
1193 | ret = -ENOENT; | ||
1194 | } | 661 | } |
1195 | found: | 662 | if (ret >= 0) |
663 | ret = convert_variable(&vr_die, pf); | ||
664 | |||
1196 | if (ret < 0) | 665 | if (ret < 0) |
1197 | pr_warning("Failed to find '%s' in this function.\n", | 666 | pr_warning("Failed to find '%s' in this function.\n", |
1198 | pf->pvar->var); | 667 | pf->pvar->var); |
@@ -1235,27 +704,30 @@ static int convert_to_trace_point(Dwarf_Die *sp_die, Dwarf_Addr paddr, | |||
1235 | return 0; | 704 | return 0; |
1236 | } | 705 | } |
1237 | 706 | ||
1238 | /* Call probe_finder callback with real subprogram DIE */ | 707 | /* Call probe_finder callback with scope DIE */ |
1239 | static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | 708 | static int call_probe_finder(Dwarf_Die *sc_die, struct probe_finder *pf) |
1240 | { | 709 | { |
1241 | Dwarf_Die die_mem; | ||
1242 | Dwarf_Attribute fb_attr; | 710 | Dwarf_Attribute fb_attr; |
1243 | size_t nops; | 711 | size_t nops; |
1244 | int ret; | 712 | int ret; |
1245 | 713 | ||
1246 | /* If no real subprogram, find a real one */ | 714 | if (!sc_die) { |
1247 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 715 | pr_err("Caller must pass a scope DIE. Program error.\n"); |
1248 | sp_die = die_find_real_subprogram(&pf->cu_die, | 716 | return -EINVAL; |
1249 | pf->addr, &die_mem); | 717 | } |
1250 | if (!sp_die) { | 718 | |
719 | /* If not a real subprogram, find a real one */ | ||
720 | if (dwarf_tag(sc_die) != DW_TAG_subprogram) { | ||
721 | if (!die_find_realfunc(&pf->cu_die, pf->addr, &pf->sp_die)) { | ||
1251 | pr_warning("Failed to find probe point in any " | 722 | pr_warning("Failed to find probe point in any " |
1252 | "functions.\n"); | 723 | "functions.\n"); |
1253 | return -ENOENT; | 724 | return -ENOENT; |
1254 | } | 725 | } |
1255 | } | 726 | } else |
727 | memcpy(&pf->sp_die, sc_die, sizeof(Dwarf_Die)); | ||
1256 | 728 | ||
1257 | /* Get the frame base attribute/ops */ | 729 | /* Get the frame base attribute/ops from subprogram */ |
1258 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 730 | dwarf_attr(&pf->sp_die, DW_AT_frame_base, &fb_attr); |
1259 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 731 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
1260 | if (ret <= 0 || nops == 0) { | 732 | if (ret <= 0 || nops == 0) { |
1261 | pf->fb_ops = NULL; | 733 | pf->fb_ops = NULL; |
@@ -1273,7 +745,7 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1273 | } | 745 | } |
1274 | 746 | ||
1275 | /* Call finder's callback handler */ | 747 | /* Call finder's callback handler */ |
1276 | ret = pf->callback(sp_die, pf); | 748 | ret = pf->callback(sc_die, pf); |
1277 | 749 | ||
1278 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 750 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
1279 | pf->fb_ops = NULL; | 751 | pf->fb_ops = NULL; |
@@ -1281,17 +753,82 @@ static int call_probe_finder(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1281 | return ret; | 753 | return ret; |
1282 | } | 754 | } |
1283 | 755 | ||
756 | struct find_scope_param { | ||
757 | const char *function; | ||
758 | const char *file; | ||
759 | int line; | ||
760 | int diff; | ||
761 | Dwarf_Die *die_mem; | ||
762 | bool found; | ||
763 | }; | ||
764 | |||
765 | static int find_best_scope_cb(Dwarf_Die *fn_die, void *data) | ||
766 | { | ||
767 | struct find_scope_param *fsp = data; | ||
768 | const char *file; | ||
769 | int lno; | ||
770 | |||
771 | /* Skip if declared file name does not match */ | ||
772 | if (fsp->file) { | ||
773 | file = dwarf_decl_file(fn_die); | ||
774 | if (!file || strcmp(fsp->file, file) != 0) | ||
775 | return 0; | ||
776 | } | ||
777 | /* If the function name is given, that's what user expects */ | ||
778 | if (fsp->function) { | ||
779 | if (die_compare_name(fn_die, fsp->function)) { | ||
780 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
781 | fsp->found = true; | ||
782 | return 1; | ||
783 | } | ||
784 | } else { | ||
785 | /* With the line number, find the nearest declared DIE */ | ||
786 | dwarf_decl_line(fn_die, &lno); | ||
787 | if (lno < fsp->line && fsp->diff > fsp->line - lno) { | ||
788 | /* Keep a candidate and continue */ | ||
789 | fsp->diff = fsp->line - lno; | ||
790 | memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die)); | ||
791 | fsp->found = true; | ||
792 | } | ||
793 | } | ||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | /* Find an appropriate scope fits to given conditions */ | ||
798 | static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem) | ||
799 | { | ||
800 | struct find_scope_param fsp = { | ||
801 | .function = pf->pev->point.function, | ||
802 | .file = pf->fname, | ||
803 | .line = pf->lno, | ||
804 | .diff = INT_MAX, | ||
805 | .die_mem = die_mem, | ||
806 | .found = false, | ||
807 | }; | ||
808 | |||
809 | cu_walk_functions_at(&pf->cu_die, pf->addr, find_best_scope_cb, &fsp); | ||
810 | |||
811 | return fsp.found ? die_mem : NULL; | ||
812 | } | ||
813 | |||
1284 | static int probe_point_line_walker(const char *fname, int lineno, | 814 | static int probe_point_line_walker(const char *fname, int lineno, |
1285 | Dwarf_Addr addr, void *data) | 815 | Dwarf_Addr addr, void *data) |
1286 | { | 816 | { |
1287 | struct probe_finder *pf = data; | 817 | struct probe_finder *pf = data; |
818 | Dwarf_Die *sc_die, die_mem; | ||
1288 | int ret; | 819 | int ret; |
1289 | 820 | ||
1290 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) | 821 | if (lineno != pf->lno || strtailcmp(fname, pf->fname) != 0) |
1291 | return 0; | 822 | return 0; |
1292 | 823 | ||
1293 | pf->addr = addr; | 824 | pf->addr = addr; |
1294 | ret = call_probe_finder(NULL, pf); | 825 | sc_die = find_best_scope(pf, &die_mem); |
826 | if (!sc_die) { | ||
827 | pr_warning("Failed to find scope of probe point.\n"); | ||
828 | return -ENOENT; | ||
829 | } | ||
830 | |||
831 | ret = call_probe_finder(sc_die, pf); | ||
1295 | 832 | ||
1296 | /* Continue if no error, because the line will be in inline function */ | 833 | /* Continue if no error, because the line will be in inline function */ |
1297 | return ret < 0 ? ret : 0; | 834 | return ret < 0 ? ret : 0; |
@@ -1345,6 +882,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
1345 | Dwarf_Addr addr, void *data) | 882 | Dwarf_Addr addr, void *data) |
1346 | { | 883 | { |
1347 | struct probe_finder *pf = data; | 884 | struct probe_finder *pf = data; |
885 | Dwarf_Die *sc_die, die_mem; | ||
1348 | int ret; | 886 | int ret; |
1349 | 887 | ||
1350 | if (!line_list__has_line(&pf->lcache, lineno) || | 888 | if (!line_list__has_line(&pf->lcache, lineno) || |
@@ -1354,7 +892,14 @@ static int probe_point_lazy_walker(const char *fname, int lineno, | |||
1354 | pr_debug("Probe line found: line:%d addr:0x%llx\n", | 892 | pr_debug("Probe line found: line:%d addr:0x%llx\n", |
1355 | lineno, (unsigned long long)addr); | 893 | lineno, (unsigned long long)addr); |
1356 | pf->addr = addr; | 894 | pf->addr = addr; |
1357 | ret = call_probe_finder(NULL, pf); | 895 | pf->lno = lineno; |
896 | sc_die = find_best_scope(pf, &die_mem); | ||
897 | if (!sc_die) { | ||
898 | pr_warning("Failed to find scope of probe point.\n"); | ||
899 | return -ENOENT; | ||
900 | } | ||
901 | |||
902 | ret = call_probe_finder(sc_die, pf); | ||
1358 | 903 | ||
1359 | /* | 904 | /* |
1360 | * Continue if no error, because the lazy pattern will match | 905 | * Continue if no error, because the lazy pattern will match |
@@ -1379,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1379 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
1380 | } | 925 | } |
1381 | 926 | ||
1382 | /* Callback parameter with return value */ | ||
1383 | struct dwarf_callback_param { | ||
1384 | void *data; | ||
1385 | int retval; | ||
1386 | }; | ||
1387 | |||
1388 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
1389 | { | 928 | { |
1390 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
1391 | struct probe_finder *pf = param->data; | ||
1392 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
1393 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
932 | int ret; | ||
1394 | 933 | ||
1395 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
1396 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
1397 | else { | 936 | else { |
1398 | /* Get probe address */ | 937 | /* Get probe address */ |
1399 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
1400 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
1401 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
1402 | param->retval = -ENOENT; | 941 | return -ENOENT; |
1403 | return DWARF_CB_ABORT; | ||
1404 | } | 942 | } |
1405 | pf->addr = addr; | 943 | pf->addr = addr; |
1406 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
1407 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
1408 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
1409 | 947 | ||
1410 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
1411 | if (param->retval < 0) | ||
1412 | return DWARF_CB_ABORT; | ||
1413 | } | 949 | } |
1414 | 950 | ||
1415 | return DWARF_CB_OK; | 951 | return ret; |
1416 | } | 952 | } |
1417 | 953 | ||
954 | /* Callback parameter with return value for libdw */ | ||
955 | struct dwarf_callback_param { | ||
956 | void *data; | ||
957 | int retval; | ||
958 | }; | ||
959 | |||
1418 | /* Search function from function name */ | 960 | /* Search function from function name */ |
1419 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
1420 | { | 962 | { |
@@ -1451,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
1451 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
1452 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
1453 | } | 995 | } |
1454 | } else { | 996 | } else |
1455 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
1456 | .retval = 0}; | ||
1457 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
1458 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
1459 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
1460 | param->retval = _param.retval; | ||
1461 | } | ||
1462 | 1000 | ||
1463 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
1464 | } | 1002 | } |
@@ -1504,28 +1042,18 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data) | |||
1504 | } | 1042 | } |
1505 | 1043 | ||
1506 | /* Find probe points from debuginfo */ | 1044 | /* Find probe points from debuginfo */ |
1507 | static int find_probes(int fd, struct probe_finder *pf) | 1045 | static int debuginfo__find_probes(struct debuginfo *self, |
1046 | struct probe_finder *pf) | ||
1508 | { | 1047 | { |
1509 | struct perf_probe_point *pp = &pf->pev->point; | 1048 | struct perf_probe_point *pp = &pf->pev->point; |
1510 | Dwarf_Off off, noff; | 1049 | Dwarf_Off off, noff; |
1511 | size_t cuhl; | 1050 | size_t cuhl; |
1512 | Dwarf_Die *diep; | 1051 | Dwarf_Die *diep; |
1513 | Dwarf *dbg = NULL; | ||
1514 | Dwfl *dwfl; | ||
1515 | Dwarf_Addr bias; /* Currently ignored */ | ||
1516 | int ret = 0; | 1052 | int ret = 0; |
1517 | 1053 | ||
1518 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); | ||
1519 | if (!dbg) { | ||
1520 | pr_warning("No debug information found in the vmlinux - " | ||
1521 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1522 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
1523 | return -EBADF; | ||
1524 | } | ||
1525 | |||
1526 | #if _ELFUTILS_PREREQ(0, 142) | 1054 | #if _ELFUTILS_PREREQ(0, 142) |
1527 | /* Get the call frame information from this dwarf */ | 1055 | /* Get the call frame information from this dwarf */ |
1528 | pf->cfi = dwarf_getcfi(dbg); | 1056 | pf->cfi = dwarf_getcfi(self->dbg); |
1529 | #endif | 1057 | #endif |
1530 | 1058 | ||
1531 | off = 0; | 1059 | off = 0; |
@@ -1544,7 +1072,8 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1544 | .data = pf, | 1072 | .data = pf, |
1545 | }; | 1073 | }; |
1546 | 1074 | ||
1547 | dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); | 1075 | dwarf_getpubnames(self->dbg, pubname_search_cb, |
1076 | &pubname_param, 0); | ||
1548 | if (pubname_param.found) { | 1077 | if (pubname_param.found) { |
1549 | ret = probe_point_search_cb(&pf->sp_die, &probe_param); | 1078 | ret = probe_point_search_cb(&pf->sp_die, &probe_param); |
1550 | if (ret) | 1079 | if (ret) |
@@ -1553,9 +1082,9 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1553 | } | 1082 | } |
1554 | 1083 | ||
1555 | /* Loop on CUs (Compilation Unit) */ | 1084 | /* Loop on CUs (Compilation Unit) */ |
1556 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | 1085 | while (!dwarf_nextcu(self->dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { |
1557 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1086 | /* Get the DIE(Debugging Information Entry) of this CU */ |
1558 | diep = dwarf_offdie(dbg, off + cuhl, &pf->cu_die); | 1087 | diep = dwarf_offdie(self->dbg, off + cuhl, &pf->cu_die); |
1559 | if (!diep) | 1088 | if (!diep) |
1560 | continue; | 1089 | continue; |
1561 | 1090 | ||
@@ -1582,14 +1111,12 @@ static int find_probes(int fd, struct probe_finder *pf) | |||
1582 | 1111 | ||
1583 | found: | 1112 | found: |
1584 | line_list__free(&pf->lcache); | 1113 | line_list__free(&pf->lcache); |
1585 | if (dwfl) | ||
1586 | dwfl_end(dwfl); | ||
1587 | 1114 | ||
1588 | return ret; | 1115 | return ret; |
1589 | } | 1116 | } |
1590 | 1117 | ||
1591 | /* Add a found probe point into trace event list */ | 1118 | /* Add a found probe point into trace event list */ |
1592 | static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | 1119 | static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf) |
1593 | { | 1120 | { |
1594 | struct trace_event_finder *tf = | 1121 | struct trace_event_finder *tf = |
1595 | container_of(pf, struct trace_event_finder, pf); | 1122 | container_of(pf, struct trace_event_finder, pf); |
@@ -1604,8 +1131,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1604 | } | 1131 | } |
1605 | tev = &tf->tevs[tf->ntevs++]; | 1132 | tev = &tf->tevs[tf->ntevs++]; |
1606 | 1133 | ||
1607 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1134 | /* Trace point should be converted from subprogram DIE */ |
1608 | &tev->point); | 1135 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1136 | pf->pev->point.retprobe, &tev->point); | ||
1609 | if (ret < 0) | 1137 | if (ret < 0) |
1610 | return ret; | 1138 | return ret; |
1611 | 1139 | ||
@@ -1620,7 +1148,8 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1620 | for (i = 0; i < pf->pev->nargs; i++) { | 1148 | for (i = 0; i < pf->pev->nargs; i++) { |
1621 | pf->pvar = &pf->pev->args[i]; | 1149 | pf->pvar = &pf->pev->args[i]; |
1622 | pf->tvar = &tev->args[i]; | 1150 | pf->tvar = &tev->args[i]; |
1623 | ret = find_variable(sp_die, pf); | 1151 | /* Variable should be found from scope DIE */ |
1152 | ret = find_variable(sc_die, pf); | ||
1624 | if (ret != 0) | 1153 | if (ret != 0) |
1625 | return ret; | 1154 | return ret; |
1626 | } | 1155 | } |
@@ -1629,8 +1158,9 @@ static int add_probe_trace_event(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1629 | } | 1158 | } |
1630 | 1159 | ||
1631 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ | 1160 | /* Find probe_trace_events specified by perf_probe_event from debuginfo */ |
1632 | int find_probe_trace_events(int fd, struct perf_probe_event *pev, | 1161 | int debuginfo__find_trace_events(struct debuginfo *self, |
1633 | struct probe_trace_event **tevs, int max_tevs) | 1162 | struct perf_probe_event *pev, |
1163 | struct probe_trace_event **tevs, int max_tevs) | ||
1634 | { | 1164 | { |
1635 | struct trace_event_finder tf = { | 1165 | struct trace_event_finder tf = { |
1636 | .pf = {.pev = pev, .callback = add_probe_trace_event}, | 1166 | .pf = {.pev = pev, .callback = add_probe_trace_event}, |
@@ -1645,7 +1175,7 @@ int find_probe_trace_events(int fd, struct perf_probe_event *pev, | |||
1645 | tf.tevs = *tevs; | 1175 | tf.tevs = *tevs; |
1646 | tf.ntevs = 0; | 1176 | tf.ntevs = 0; |
1647 | 1177 | ||
1648 | ret = find_probes(fd, &tf.pf); | 1178 | ret = debuginfo__find_probes(self, &tf.pf); |
1649 | if (ret < 0) { | 1179 | if (ret < 0) { |
1650 | free(*tevs); | 1180 | free(*tevs); |
1651 | *tevs = NULL; | 1181 | *tevs = NULL; |
@@ -1687,13 +1217,13 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1687 | } | 1217 | } |
1688 | 1218 | ||
1689 | /* Add a found vars into available variables list */ | 1219 | /* Add a found vars into available variables list */ |
1690 | static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | 1220 | static int add_available_vars(Dwarf_Die *sc_die, struct probe_finder *pf) |
1691 | { | 1221 | { |
1692 | struct available_var_finder *af = | 1222 | struct available_var_finder *af = |
1693 | container_of(pf, struct available_var_finder, pf); | 1223 | container_of(pf, struct available_var_finder, pf); |
1694 | struct variable_list *vl; | 1224 | struct variable_list *vl; |
1695 | Dwarf_Die die_mem, *scopes = NULL; | 1225 | Dwarf_Die die_mem; |
1696 | int ret, nscopes; | 1226 | int ret; |
1697 | 1227 | ||
1698 | /* Check number of tevs */ | 1228 | /* Check number of tevs */ |
1699 | if (af->nvls == af->max_vls) { | 1229 | if (af->nvls == af->max_vls) { |
@@ -1702,8 +1232,9 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1702 | } | 1232 | } |
1703 | vl = &af->vls[af->nvls++]; | 1233 | vl = &af->vls[af->nvls++]; |
1704 | 1234 | ||
1705 | ret = convert_to_trace_point(sp_die, pf->addr, pf->pev->point.retprobe, | 1235 | /* Trace point should be converted from subprogram DIE */ |
1706 | &vl->point); | 1236 | ret = convert_to_trace_point(&pf->sp_die, pf->addr, |
1237 | pf->pev->point.retprobe, &vl->point); | ||
1707 | if (ret < 0) | 1238 | if (ret < 0) |
1708 | return ret; | 1239 | return ret; |
1709 | 1240 | ||
@@ -1715,19 +1246,14 @@ static int add_available_vars(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
1715 | if (vl->vars == NULL) | 1246 | if (vl->vars == NULL) |
1716 | return -ENOMEM; | 1247 | return -ENOMEM; |
1717 | af->child = true; | 1248 | af->child = true; |
1718 | die_find_child(sp_die, collect_variables_cb, (void *)af, &die_mem); | 1249 | die_find_child(sc_die, collect_variables_cb, (void *)af, &die_mem); |
1719 | 1250 | ||
1720 | /* Find external variables */ | 1251 | /* Find external variables */ |
1721 | if (!af->externs) | 1252 | if (!af->externs) |
1722 | goto out; | 1253 | goto out; |
1723 | /* Don't need to search child DIE for externs. */ | 1254 | /* Don't need to search child DIE for externs. */ |
1724 | af->child = false; | 1255 | af->child = false; |
1725 | nscopes = dwarf_getscopes_die(sp_die, &scopes); | 1256 | die_find_child(&pf->cu_die, collect_variables_cb, (void *)af, &die_mem); |
1726 | while (nscopes-- > 1) | ||
1727 | die_find_child(&scopes[nscopes], collect_variables_cb, | ||
1728 | (void *)af, &die_mem); | ||
1729 | if (scopes) | ||
1730 | free(scopes); | ||
1731 | 1257 | ||
1732 | out: | 1258 | out: |
1733 | if (strlist__empty(vl->vars)) { | 1259 | if (strlist__empty(vl->vars)) { |
@@ -1739,9 +1265,10 @@ out: | |||
1739 | } | 1265 | } |
1740 | 1266 | ||
1741 | /* Find available variables at given probe point */ | 1267 | /* Find available variables at given probe point */ |
1742 | int find_available_vars_at(int fd, struct perf_probe_event *pev, | 1268 | int debuginfo__find_available_vars_at(struct debuginfo *self, |
1743 | struct variable_list **vls, int max_vls, | 1269 | struct perf_probe_event *pev, |
1744 | bool externs) | 1270 | struct variable_list **vls, |
1271 | int max_vls, bool externs) | ||
1745 | { | 1272 | { |
1746 | struct available_var_finder af = { | 1273 | struct available_var_finder af = { |
1747 | .pf = {.pev = pev, .callback = add_available_vars}, | 1274 | .pf = {.pev = pev, .callback = add_available_vars}, |
@@ -1756,7 +1283,7 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | |||
1756 | af.vls = *vls; | 1283 | af.vls = *vls; |
1757 | af.nvls = 0; | 1284 | af.nvls = 0; |
1758 | 1285 | ||
1759 | ret = find_probes(fd, &af.pf); | 1286 | ret = debuginfo__find_probes(self, &af.pf); |
1760 | if (ret < 0) { | 1287 | if (ret < 0) { |
1761 | /* Free vlist for error */ | 1288 | /* Free vlist for error */ |
1762 | while (af.nvls--) { | 1289 | while (af.nvls--) { |
@@ -1774,28 +1301,19 @@ int find_available_vars_at(int fd, struct perf_probe_event *pev, | |||
1774 | } | 1301 | } |
1775 | 1302 | ||
1776 | /* Reverse search */ | 1303 | /* Reverse search */ |
1777 | int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | 1304 | int debuginfo__find_probe_point(struct debuginfo *self, unsigned long addr, |
1305 | struct perf_probe_point *ppt) | ||
1778 | { | 1306 | { |
1779 | Dwarf_Die cudie, spdie, indie; | 1307 | Dwarf_Die cudie, spdie, indie; |
1780 | Dwarf *dbg = NULL; | 1308 | Dwarf_Addr _addr, baseaddr; |
1781 | Dwfl *dwfl = NULL; | ||
1782 | Dwarf_Addr _addr, baseaddr, bias = 0; | ||
1783 | const char *fname = NULL, *func = NULL, *tmp; | 1309 | const char *fname = NULL, *func = NULL, *tmp; |
1784 | int baseline = 0, lineno = 0, ret = 0; | 1310 | int baseline = 0, lineno = 0, ret = 0; |
1785 | 1311 | ||
1786 | /* Open the live linux kernel */ | ||
1787 | dbg = dwfl_init_live_kernel_dwarf(addr, &dwfl, &bias); | ||
1788 | if (!dbg) { | ||
1789 | pr_warning("No debug information found in the vmlinux - " | ||
1790 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1791 | ret = -EINVAL; | ||
1792 | goto end; | ||
1793 | } | ||
1794 | |||
1795 | /* Adjust address with bias */ | 1312 | /* Adjust address with bias */ |
1796 | addr += bias; | 1313 | addr += self->bias; |
1314 | |||
1797 | /* Find cu die */ | 1315 | /* Find cu die */ |
1798 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr - bias, &cudie)) { | 1316 | if (!dwarf_addrdie(self->dbg, (Dwarf_Addr)addr - self->bias, &cudie)) { |
1799 | pr_warning("Failed to find debug information for address %lx\n", | 1317 | pr_warning("Failed to find debug information for address %lx\n", |
1800 | addr); | 1318 | addr); |
1801 | ret = -EINVAL; | 1319 | ret = -EINVAL; |
@@ -1807,7 +1325,7 @@ int find_perf_probe_point(unsigned long addr, struct perf_probe_point *ppt) | |||
1807 | /* Don't care whether it failed or not */ | 1325 | /* Don't care whether it failed or not */ |
1808 | 1326 | ||
1809 | /* Find a corresponding function (name, baseline and baseaddr) */ | 1327 | /* Find a corresponding function (name, baseline and baseaddr) */ |
1810 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1328 | if (die_find_realfunc(&cudie, (Dwarf_Addr)addr, &spdie)) { |
1811 | /* Get function entry information */ | 1329 | /* Get function entry information */ |
1812 | tmp = dwarf_diename(&spdie); | 1330 | tmp = dwarf_diename(&spdie); |
1813 | if (!tmp || | 1331 | if (!tmp || |
@@ -1871,8 +1389,6 @@ post: | |||
1871 | } | 1389 | } |
1872 | } | 1390 | } |
1873 | end: | 1391 | end: |
1874 | if (dwfl) | ||
1875 | dwfl_end(dwfl); | ||
1876 | if (ret == 0 && (fname || func)) | 1392 | if (ret == 0 && (fname || func)) |
1877 | ret = 1; /* Found a point */ | 1393 | ret = 1; /* Found a point */ |
1878 | return ret; | 1394 | return ret; |
@@ -1929,10 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1929 | 1445 | ||
1930 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1931 | { | 1447 | { |
1932 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
1933 | 1449 | ||
1934 | param->retval = find_line_range_by_line(in_die, param->data); | 1450 | /* |
1935 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1451 | * We have to check all instances of inlined function, because |
1452 | * some execution paths can be optimized out depends on the | ||
1453 | * function argument of instances | ||
1454 | */ | ||
1455 | return 0; | ||
1936 | } | 1456 | } |
1937 | 1457 | ||
1938 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
@@ -1960,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1960 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1961 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
1962 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
1963 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
1964 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
1965 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
1966 | _param.retval = 0; | 1486 | else |
1967 | dwarf_func_inline_instances(sp_die, | ||
1968 | line_range_inline_cb, | ||
1969 | &_param); | ||
1970 | param->retval = _param.retval; | ||
1971 | } else | ||
1972 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
1973 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
1974 | } | 1489 | } |
@@ -1982,26 +1497,15 @@ static int find_line_range_by_func(struct line_finder *lf) | |||
1982 | return param.retval; | 1497 | return param.retval; |
1983 | } | 1498 | } |
1984 | 1499 | ||
1985 | int find_line_range(int fd, struct line_range *lr) | 1500 | int debuginfo__find_line_range(struct debuginfo *self, struct line_range *lr) |
1986 | { | 1501 | { |
1987 | struct line_finder lf = {.lr = lr, .found = 0}; | 1502 | struct line_finder lf = {.lr = lr, .found = 0}; |
1988 | int ret = 0; | 1503 | int ret = 0; |
1989 | Dwarf_Off off = 0, noff; | 1504 | Dwarf_Off off = 0, noff; |
1990 | size_t cuhl; | 1505 | size_t cuhl; |
1991 | Dwarf_Die *diep; | 1506 | Dwarf_Die *diep; |
1992 | Dwarf *dbg = NULL; | ||
1993 | Dwfl *dwfl; | ||
1994 | Dwarf_Addr bias; /* Currently ignored */ | ||
1995 | const char *comp_dir; | 1507 | const char *comp_dir; |
1996 | 1508 | ||
1997 | dbg = dwfl_init_offline_dwarf(fd, &dwfl, &bias); | ||
1998 | if (!dbg) { | ||
1999 | pr_warning("No debug information found in the vmlinux - " | ||
2000 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
2001 | close(fd); /* Without dwfl_end(), fd isn't closed. */ | ||
2002 | return -EBADF; | ||
2003 | } | ||
2004 | |||
2005 | /* Fastpath: lookup by function name from .debug_pubnames section */ | 1509 | /* Fastpath: lookup by function name from .debug_pubnames section */ |
2006 | if (lr->function) { | 1510 | if (lr->function) { |
2007 | struct pubname_callback_param pubname_param = { | 1511 | struct pubname_callback_param pubname_param = { |
@@ -2010,7 +1514,8 @@ int find_line_range(int fd, struct line_range *lr) | |||
2010 | struct dwarf_callback_param line_range_param = { | 1514 | struct dwarf_callback_param line_range_param = { |
2011 | .data = (void *)&lf, .retval = 0}; | 1515 | .data = (void *)&lf, .retval = 0}; |
2012 | 1516 | ||
2013 | dwarf_getpubnames(dbg, pubname_search_cb, &pubname_param, 0); | 1517 | dwarf_getpubnames(self->dbg, pubname_search_cb, |
1518 | &pubname_param, 0); | ||
2014 | if (pubname_param.found) { | 1519 | if (pubname_param.found) { |
2015 | line_range_search_cb(&lf.sp_die, &line_range_param); | 1520 | line_range_search_cb(&lf.sp_die, &line_range_param); |
2016 | if (lf.found) | 1521 | if (lf.found) |
@@ -2020,11 +1525,12 @@ int find_line_range(int fd, struct line_range *lr) | |||
2020 | 1525 | ||
2021 | /* Loop on CUs (Compilation Unit) */ | 1526 | /* Loop on CUs (Compilation Unit) */ |
2022 | while (!lf.found && ret >= 0) { | 1527 | while (!lf.found && ret >= 0) { |
2023 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) | 1528 | if (dwarf_nextcu(self->dbg, off, &noff, &cuhl, |
1529 | NULL, NULL, NULL) != 0) | ||
2024 | break; | 1530 | break; |
2025 | 1531 | ||
2026 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1532 | /* Get the DIE(Debugging Information Entry) of this CU */ |
2027 | diep = dwarf_offdie(dbg, off + cuhl, &lf.cu_die); | 1533 | diep = dwarf_offdie(self->dbg, off + cuhl, &lf.cu_die); |
2028 | if (!diep) | 1534 | if (!diep) |
2029 | continue; | 1535 | continue; |
2030 | 1536 | ||
@@ -2058,7 +1564,6 @@ found: | |||
2058 | } | 1564 | } |
2059 | 1565 | ||
2060 | pr_debug("path: %s\n", lr->path); | 1566 | pr_debug("path: %s\n", lr->path); |
2061 | dwfl_end(dwfl); | ||
2062 | return (ret < 0) ? ret : lf.found; | 1567 | return (ret < 0) ? ret : lf.found; |
2063 | } | 1568 | } |
2064 | 1569 | ||