diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 990 |
1 files changed, 750 insertions, 240 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index c171a243d05b..3e7977560be5 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -84,6 +84,9 @@ const char *x86_64_regs_table[X86_64_MAX_REGS] = { | |||
84 | #define arch_regs_table x86_32_regs_table | 84 | #define arch_regs_table x86_32_regs_table |
85 | #endif | 85 | #endif |
86 | 86 | ||
87 | /* Kprobe tracer basic type is up to u64 */ | ||
88 | #define MAX_BASIC_TYPE_BITS 64 | ||
89 | |||
87 | /* Return architecture dependent register string (for kprobe-tracer) */ | 90 | /* Return architecture dependent register string (for kprobe-tracer) */ |
88 | static const char *get_arch_regstr(unsigned int n) | 91 | static const char *get_arch_regstr(unsigned int n) |
89 | { | 92 | { |
@@ -108,7 +111,7 @@ static int strtailcmp(const char *s1, const char *s2) | |||
108 | /* Line number list operations */ | 111 | /* Line number list operations */ |
109 | 112 | ||
110 | /* Add a line to line number list */ | 113 | /* Add a line to line number list */ |
111 | static void line_list__add_line(struct list_head *head, unsigned int line) | 114 | static int line_list__add_line(struct list_head *head, int line) |
112 | { | 115 | { |
113 | struct line_node *ln; | 116 | struct line_node *ln; |
114 | struct list_head *p; | 117 | struct list_head *p; |
@@ -119,21 +122,23 @@ static void line_list__add_line(struct list_head *head, unsigned int line) | |||
119 | p = &ln->list; | 122 | p = &ln->list; |
120 | goto found; | 123 | goto found; |
121 | } else if (ln->line == line) /* Already exist */ | 124 | } else if (ln->line == line) /* Already exist */ |
122 | return ; | 125 | return 1; |
123 | } | 126 | } |
124 | /* List is empty, or the smallest entry */ | 127 | /* List is empty, or the smallest entry */ |
125 | p = head; | 128 | p = head; |
126 | found: | 129 | found: |
127 | pr_debug("line list: add a line %u\n", line); | 130 | pr_debug("line list: add a line %u\n", line); |
128 | ln = zalloc(sizeof(struct line_node)); | 131 | ln = zalloc(sizeof(struct line_node)); |
129 | DIE_IF(ln == NULL); | 132 | if (ln == NULL) |
133 | return -ENOMEM; | ||
130 | ln->line = line; | 134 | ln->line = line; |
131 | INIT_LIST_HEAD(&ln->list); | 135 | INIT_LIST_HEAD(&ln->list); |
132 | list_add(&ln->list, p); | 136 | list_add(&ln->list, p); |
137 | return 0; | ||
133 | } | 138 | } |
134 | 139 | ||
135 | /* Check if the line in line number list */ | 140 | /* Check if the line in line number list */ |
136 | static int line_list__has_line(struct list_head *head, unsigned int line) | 141 | static int line_list__has_line(struct list_head *head, int line) |
137 | { | 142 | { |
138 | struct line_node *ln; | 143 | struct line_node *ln; |
139 | 144 | ||
@@ -184,9 +189,129 @@ static const char *cu_find_realpath(Dwarf_Die *cu_die, const char *fname) | |||
184 | if (strtailcmp(src, fname) == 0) | 189 | if (strtailcmp(src, fname) == 0) |
185 | break; | 190 | break; |
186 | } | 191 | } |
192 | if (i == nfiles) | ||
193 | return NULL; | ||
187 | return src; | 194 | return src; |
188 | } | 195 | } |
189 | 196 | ||
197 | /* Compare diename and tname */ | ||
198 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | ||
199 | { | ||
200 | const char *name; | ||
201 | name = dwarf_diename(dw_die); | ||
202 | return name ? strcmp(tname, name) : -1; | ||
203 | } | ||
204 | |||
205 | /* Get type die, but skip qualifiers and typedef */ | ||
206 | static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | ||
207 | { | ||
208 | Dwarf_Attribute attr; | ||
209 | int tag; | ||
210 | |||
211 | do { | ||
212 | if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || | ||
213 | dwarf_formref_die(&attr, die_mem) == NULL) | ||
214 | return NULL; | ||
215 | |||
216 | tag = dwarf_tag(die_mem); | ||
217 | vr_die = die_mem; | ||
218 | } while (tag == DW_TAG_const_type || | ||
219 | tag == DW_TAG_restrict_type || | ||
220 | tag == DW_TAG_volatile_type || | ||
221 | tag == DW_TAG_shared_type || | ||
222 | tag == DW_TAG_typedef); | ||
223 | |||
224 | return die_mem; | ||
225 | } | ||
226 | |||
227 | static bool die_is_signed_type(Dwarf_Die *tp_die) | ||
228 | { | ||
229 | Dwarf_Attribute attr; | ||
230 | Dwarf_Word ret; | ||
231 | |||
232 | if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL || | ||
233 | dwarf_formudata(&attr, &ret) != 0) | ||
234 | return false; | ||
235 | |||
236 | return (ret == DW_ATE_signed_char || ret == DW_ATE_signed || | ||
237 | ret == DW_ATE_signed_fixed); | ||
238 | } | ||
239 | |||
240 | static int die_get_byte_size(Dwarf_Die *tp_die) | ||
241 | { | ||
242 | Dwarf_Attribute attr; | ||
243 | Dwarf_Word ret; | ||
244 | |||
245 | if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL || | ||
246 | dwarf_formudata(&attr, &ret) != 0) | ||
247 | return 0; | ||
248 | |||
249 | return (int)ret; | ||
250 | } | ||
251 | |||
252 | /* Get data_member_location offset */ | ||
253 | static int die_get_data_member_location(Dwarf_Die *mb_die, Dwarf_Word *offs) | ||
254 | { | ||
255 | Dwarf_Attribute attr; | ||
256 | Dwarf_Op *expr; | ||
257 | size_t nexpr; | ||
258 | int ret; | ||
259 | |||
260 | if (dwarf_attr(mb_die, DW_AT_data_member_location, &attr) == NULL) | ||
261 | return -ENOENT; | ||
262 | |||
263 | if (dwarf_formudata(&attr, offs) != 0) { | ||
264 | /* DW_AT_data_member_location should be DW_OP_plus_uconst */ | ||
265 | ret = dwarf_getlocation(&attr, &expr, &nexpr); | ||
266 | if (ret < 0 || nexpr == 0) | ||
267 | return -ENOENT; | ||
268 | |||
269 | if (expr[0].atom != DW_OP_plus_uconst || nexpr != 1) { | ||
270 | pr_debug("Unable to get offset:Unexpected OP %x (%zd)\n", | ||
271 | expr[0].atom, nexpr); | ||
272 | return -ENOTSUP; | ||
273 | } | ||
274 | *offs = (Dwarf_Word)expr[0].number; | ||
275 | } | ||
276 | return 0; | ||
277 | } | ||
278 | |||
279 | /* Return values for die_find callbacks */ | ||
280 | enum { | ||
281 | DIE_FIND_CB_FOUND = 0, /* End of Search */ | ||
282 | DIE_FIND_CB_CHILD = 1, /* Search only children */ | ||
283 | DIE_FIND_CB_SIBLING = 2, /* Search only siblings */ | ||
284 | DIE_FIND_CB_CONTINUE = 3, /* Search children and siblings */ | ||
285 | }; | ||
286 | |||
287 | /* Search a child die */ | ||
288 | static Dwarf_Die *die_find_child(Dwarf_Die *rt_die, | ||
289 | int (*callback)(Dwarf_Die *, void *), | ||
290 | void *data, Dwarf_Die *die_mem) | ||
291 | { | ||
292 | Dwarf_Die child_die; | ||
293 | int ret; | ||
294 | |||
295 | ret = dwarf_child(rt_die, die_mem); | ||
296 | if (ret != 0) | ||
297 | return NULL; | ||
298 | |||
299 | do { | ||
300 | ret = callback(die_mem, data); | ||
301 | if (ret == DIE_FIND_CB_FOUND) | ||
302 | return die_mem; | ||
303 | |||
304 | if ((ret & DIE_FIND_CB_CHILD) && | ||
305 | die_find_child(die_mem, callback, data, &child_die)) { | ||
306 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | ||
307 | return die_mem; | ||
308 | } | ||
309 | } while ((ret & DIE_FIND_CB_SIBLING) && | ||
310 | dwarf_siblingof(die_mem, die_mem) == 0); | ||
311 | |||
312 | return NULL; | ||
313 | } | ||
314 | |||
190 | struct __addr_die_search_param { | 315 | struct __addr_die_search_param { |
191 | Dwarf_Addr addr; | 316 | Dwarf_Addr addr; |
192 | Dwarf_Die *die_mem; | 317 | Dwarf_Die *die_mem; |
@@ -205,8 +330,8 @@ static int __die_search_func_cb(Dwarf_Die *fn_die, void *data) | |||
205 | } | 330 | } |
206 | 331 | ||
207 | /* Search a real subprogram including this line, */ | 332 | /* Search a real subprogram including this line, */ |
208 | static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, | 333 | static Dwarf_Die *die_find_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, |
209 | Dwarf_Die *die_mem) | 334 | Dwarf_Die *die_mem) |
210 | { | 335 | { |
211 | struct __addr_die_search_param ad; | 336 | struct __addr_die_search_param ad; |
212 | ad.addr = addr; | 337 | ad.addr = addr; |
@@ -218,77 +343,64 @@ static Dwarf_Die *die_get_real_subprogram(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
218 | return die_mem; | 343 | return die_mem; |
219 | } | 344 | } |
220 | 345 | ||
221 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ | 346 | /* die_find callback for inline function search */ |
222 | static Dwarf_Die *die_get_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 347 | static int __die_find_inline_cb(Dwarf_Die *die_mem, void *data) |
223 | Dwarf_Die *die_mem) | ||
224 | { | 348 | { |
225 | Dwarf_Die child_die; | 349 | Dwarf_Addr *addr = data; |
226 | int ret; | ||
227 | 350 | ||
228 | ret = dwarf_child(sp_die, die_mem); | 351 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && |
229 | if (ret != 0) | 352 | dwarf_haspc(die_mem, *addr)) |
230 | return NULL; | 353 | return DIE_FIND_CB_FOUND; |
231 | 354 | ||
232 | do { | 355 | return DIE_FIND_CB_CONTINUE; |
233 | if (dwarf_tag(die_mem) == DW_TAG_inlined_subroutine && | ||
234 | dwarf_haspc(die_mem, addr)) | ||
235 | return die_mem; | ||
236 | |||
237 | if (die_get_inlinefunc(die_mem, addr, &child_die)) { | ||
238 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | ||
239 | return die_mem; | ||
240 | } | ||
241 | } while (dwarf_siblingof(die_mem, die_mem) == 0); | ||
242 | |||
243 | return NULL; | ||
244 | } | 356 | } |
245 | 357 | ||
246 | /* Compare diename and tname */ | 358 | /* Similar to dwarf_getfuncs, but returns inlined_subroutine if exists. */ |
247 | static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | 359 | static Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
360 | Dwarf_Die *die_mem) | ||
248 | { | 361 | { |
249 | const char *name; | 362 | return die_find_child(sp_die, __die_find_inline_cb, &addr, die_mem); |
250 | name = dwarf_diename(dw_die); | ||
251 | DIE_IF(name == NULL); | ||
252 | return strcmp(tname, name); | ||
253 | } | 363 | } |
254 | 364 | ||
255 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | 365 | static int __die_find_variable_cb(Dwarf_Die *die_mem, void *data) |
256 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | ||
257 | { | 366 | { |
258 | Dwarf_Addr epc; | 367 | const char *name = data; |
259 | int ret; | 368 | int tag; |
260 | 369 | ||
261 | ret = dwarf_entrypc(dw_die, &epc); | 370 | tag = dwarf_tag(die_mem); |
262 | DIE_IF(ret == -1); | 371 | if ((tag == DW_TAG_formal_parameter || |
263 | return epc; | 372 | tag == DW_TAG_variable) && |
373 | (die_compare_name(die_mem, name) == 0)) | ||
374 | return DIE_FIND_CB_FOUND; | ||
375 | |||
376 | return DIE_FIND_CB_CONTINUE; | ||
264 | } | 377 | } |
265 | 378 | ||
266 | /* Get a variable die */ | 379 | /* Find a variable called 'name' */ |
267 | static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, | 380 | static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, |
268 | Dwarf_Die *die_mem) | 381 | Dwarf_Die *die_mem) |
269 | { | 382 | { |
270 | Dwarf_Die child_die; | 383 | return die_find_child(sp_die, __die_find_variable_cb, (void *)name, |
271 | int tag; | 384 | die_mem); |
272 | int ret; | 385 | } |
273 | 386 | ||
274 | ret = dwarf_child(sp_die, die_mem); | 387 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) |
275 | if (ret != 0) | 388 | { |
276 | return NULL; | 389 | const char *name = data; |
277 | 390 | ||
278 | do { | 391 | if ((dwarf_tag(die_mem) == DW_TAG_member) && |
279 | tag = dwarf_tag(die_mem); | 392 | (die_compare_name(die_mem, name) == 0)) |
280 | if ((tag == DW_TAG_formal_parameter || | 393 | return DIE_FIND_CB_FOUND; |
281 | tag == DW_TAG_variable) && | ||
282 | (die_compare_name(die_mem, name) == 0)) | ||
283 | return die_mem; | ||
284 | 394 | ||
285 | if (die_find_variable(die_mem, name, &child_die)) { | 395 | return DIE_FIND_CB_SIBLING; |
286 | memcpy(die_mem, &child_die, sizeof(Dwarf_Die)); | 396 | } |
287 | return die_mem; | ||
288 | } | ||
289 | } while (dwarf_siblingof(die_mem, die_mem) == 0); | ||
290 | 397 | ||
291 | return NULL; | 398 | /* Find a member called 'name' */ |
399 | static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | ||
400 | Dwarf_Die *die_mem) | ||
401 | { | ||
402 | return die_find_child(st_die, __die_find_member_cb, (void *)name, | ||
403 | die_mem); | ||
292 | } | 404 | } |
293 | 405 | ||
294 | /* | 406 | /* |
@@ -296,19 +408,22 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, | |||
296 | */ | 408 | */ |
297 | 409 | ||
298 | /* Show a location */ | 410 | /* Show a location */ |
299 | static void show_location(Dwarf_Op *op, struct probe_finder *pf) | 411 | static int convert_location(Dwarf_Op *op, struct probe_finder *pf) |
300 | { | 412 | { |
301 | unsigned int regn; | 413 | unsigned int regn; |
302 | Dwarf_Word offs = 0; | 414 | Dwarf_Word offs = 0; |
303 | int deref = 0, ret; | 415 | bool ref = false; |
304 | const char *regs; | 416 | const char *regs; |
417 | struct kprobe_trace_arg *tvar = pf->tvar; | ||
305 | 418 | ||
306 | /* TODO: support CFA */ | ||
307 | /* If this is based on frame buffer, set the offset */ | 419 | /* If this is based on frame buffer, set the offset */ |
308 | if (op->atom == DW_OP_fbreg) { | 420 | if (op->atom == DW_OP_fbreg) { |
309 | if (pf->fb_ops == NULL) | 421 | if (pf->fb_ops == NULL) { |
310 | die("The attribute of frame base is not supported.\n"); | 422 | pr_warning("The attribute of frame base is not " |
311 | deref = 1; | 423 | "supported.\n"); |
424 | return -ENOTSUP; | ||
425 | } | ||
426 | ref = true; | ||
312 | offs = op->number; | 427 | offs = op->number; |
313 | op = &pf->fb_ops[0]; | 428 | op = &pf->fb_ops[0]; |
314 | } | 429 | } |
@@ -316,35 +431,164 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf) | |||
316 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { | 431 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { |
317 | regn = op->atom - DW_OP_breg0; | 432 | regn = op->atom - DW_OP_breg0; |
318 | offs += op->number; | 433 | offs += op->number; |
319 | deref = 1; | 434 | ref = true; |
320 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { | 435 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { |
321 | regn = op->atom - DW_OP_reg0; | 436 | regn = op->atom - DW_OP_reg0; |
322 | } else if (op->atom == DW_OP_bregx) { | 437 | } else if (op->atom == DW_OP_bregx) { |
323 | regn = op->number; | 438 | regn = op->number; |
324 | offs += op->number2; | 439 | offs += op->number2; |
325 | deref = 1; | 440 | ref = true; |
326 | } else if (op->atom == DW_OP_regx) { | 441 | } else if (op->atom == DW_OP_regx) { |
327 | regn = op->number; | 442 | regn = op->number; |
328 | } else | 443 | } else { |
329 | die("DW_OP %d is not supported.", op->atom); | 444 | pr_warning("DW_OP %x is not supported.\n", op->atom); |
445 | return -ENOTSUP; | ||
446 | } | ||
330 | 447 | ||
331 | regs = get_arch_regstr(regn); | 448 | regs = get_arch_regstr(regn); |
332 | if (!regs) | 449 | if (!regs) { |
333 | die("%u exceeds max register number.", regn); | 450 | pr_warning("%u exceeds max register number.\n", regn); |
451 | return -ERANGE; | ||
452 | } | ||
453 | |||
454 | tvar->value = strdup(regs); | ||
455 | if (tvar->value == NULL) | ||
456 | return -ENOMEM; | ||
457 | |||
458 | if (ref) { | ||
459 | tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); | ||
460 | if (tvar->ref == NULL) | ||
461 | return -ENOMEM; | ||
462 | tvar->ref->offset = (long)offs; | ||
463 | } | ||
464 | return 0; | ||
465 | } | ||
466 | |||
467 | static int convert_variable_type(Dwarf_Die *vr_die, | ||
468 | struct kprobe_trace_arg *targ) | ||
469 | { | ||
470 | Dwarf_Die type; | ||
471 | char buf[16]; | ||
472 | int ret; | ||
473 | |||
474 | if (die_get_real_type(vr_die, &type) == NULL) { | ||
475 | pr_warning("Failed to get a type information of %s.\n", | ||
476 | dwarf_diename(vr_die)); | ||
477 | return -ENOENT; | ||
478 | } | ||
479 | |||
480 | ret = die_get_byte_size(&type) * 8; | ||
481 | if (ret) { | ||
482 | /* Check the bitwidth */ | ||
483 | if (ret > MAX_BASIC_TYPE_BITS) { | ||
484 | pr_info("%s exceeds max-bitwidth." | ||
485 | " Cut down to %d bits.\n", | ||
486 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); | ||
487 | ret = MAX_BASIC_TYPE_BITS; | ||
488 | } | ||
489 | |||
490 | ret = snprintf(buf, 16, "%c%d", | ||
491 | die_is_signed_type(&type) ? 's' : 'u', ret); | ||
492 | if (ret < 0 || ret >= 16) { | ||
493 | if (ret >= 16) | ||
494 | ret = -E2BIG; | ||
495 | pr_warning("Failed to convert variable type: %s\n", | ||
496 | strerror(-ret)); | ||
497 | return ret; | ||
498 | } | ||
499 | targ->type = strdup(buf); | ||
500 | if (targ->type == NULL) | ||
501 | return -ENOMEM; | ||
502 | } | ||
503 | return 0; | ||
504 | } | ||
505 | |||
506 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | ||
507 | struct perf_probe_arg_field *field, | ||
508 | struct kprobe_trace_arg_ref **ref_ptr, | ||
509 | Dwarf_Die *die_mem) | ||
510 | { | ||
511 | struct kprobe_trace_arg_ref *ref = *ref_ptr; | ||
512 | Dwarf_Die type; | ||
513 | Dwarf_Word offs; | ||
514 | int ret; | ||
515 | |||
516 | pr_debug("converting %s in %s\n", field->name, varname); | ||
517 | if (die_get_real_type(vr_die, &type) == NULL) { | ||
518 | pr_warning("Failed to get the type of %s.\n", varname); | ||
519 | return -ENOENT; | ||
520 | } | ||
334 | 521 | ||
335 | if (deref) | 522 | /* Check the pointer and dereference */ |
336 | ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", | 523 | if (dwarf_tag(&type) == DW_TAG_pointer_type) { |
337 | pf->var, (intmax_t)offs, regs); | 524 | if (!field->ref) { |
525 | pr_err("Semantic error: %s must be referred by '->'\n", | ||
526 | field->name); | ||
527 | return -EINVAL; | ||
528 | } | ||
529 | /* Get the type pointed by this pointer */ | ||
530 | if (die_get_real_type(&type, &type) == NULL) { | ||
531 | pr_warning("Failed to get the type of %s.\n", varname); | ||
532 | return -ENOENT; | ||
533 | } | ||
534 | /* Verify it is a data structure */ | ||
535 | if (dwarf_tag(&type) != DW_TAG_structure_type) { | ||
536 | pr_warning("%s is not a data structure.\n", varname); | ||
537 | return -EINVAL; | ||
538 | } | ||
539 | |||
540 | ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); | ||
541 | if (ref == NULL) | ||
542 | return -ENOMEM; | ||
543 | if (*ref_ptr) | ||
544 | (*ref_ptr)->next = ref; | ||
545 | else | ||
546 | *ref_ptr = ref; | ||
547 | } else { | ||
548 | /* Verify it is a data structure */ | ||
549 | if (dwarf_tag(&type) != DW_TAG_structure_type) { | ||
550 | pr_warning("%s is not a data structure.\n", varname); | ||
551 | return -EINVAL; | ||
552 | } | ||
553 | if (field->ref) { | ||
554 | pr_err("Semantic error: %s must be referred by '.'\n", | ||
555 | field->name); | ||
556 | return -EINVAL; | ||
557 | } | ||
558 | if (!ref) { | ||
559 | pr_warning("Structure on a register is not " | ||
560 | "supported yet.\n"); | ||
561 | return -ENOTSUP; | ||
562 | } | ||
563 | } | ||
564 | |||
565 | if (die_find_member(&type, field->name, die_mem) == NULL) { | ||
566 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, | ||
567 | dwarf_diename(&type), field->name); | ||
568 | return -EINVAL; | ||
569 | } | ||
570 | |||
571 | /* Get the offset of the field */ | ||
572 | ret = die_get_data_member_location(die_mem, &offs); | ||
573 | if (ret < 0) { | ||
574 | pr_warning("Failed to get the offset of %s.\n", field->name); | ||
575 | return ret; | ||
576 | } | ||
577 | ref->offset += (long)offs; | ||
578 | |||
579 | /* Converting next field */ | ||
580 | if (field->next) | ||
581 | return convert_variable_fields(die_mem, field->name, | ||
582 | field->next, &ref, die_mem); | ||
338 | else | 583 | else |
339 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); | 584 | return 0; |
340 | DIE_IF(ret < 0); | ||
341 | DIE_IF(ret >= pf->len); | ||
342 | } | 585 | } |
343 | 586 | ||
344 | /* Show a variables in kprobe event format */ | 587 | /* Show a variables in kprobe event format */ |
345 | static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 588 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
346 | { | 589 | { |
347 | Dwarf_Attribute attr; | 590 | Dwarf_Attribute attr; |
591 | Dwarf_Die die_mem; | ||
348 | Dwarf_Op *expr; | 592 | Dwarf_Op *expr; |
349 | size_t nexpr; | 593 | size_t nexpr; |
350 | int ret; | 594 | int ret; |
@@ -356,142 +600,190 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
356 | if (ret <= 0 || nexpr == 0) | 600 | if (ret <= 0 || nexpr == 0) |
357 | goto error; | 601 | goto error; |
358 | 602 | ||
359 | show_location(expr, pf); | 603 | ret = convert_location(expr, pf); |
604 | if (ret == 0 && pf->pvar->field) { | ||
605 | ret = convert_variable_fields(vr_die, pf->pvar->var, | ||
606 | pf->pvar->field, &pf->tvar->ref, | ||
607 | &die_mem); | ||
608 | vr_die = &die_mem; | ||
609 | } | ||
610 | if (ret == 0) { | ||
611 | if (pf->pvar->type) { | ||
612 | pf->tvar->type = strdup(pf->pvar->type); | ||
613 | if (pf->tvar->type == NULL) | ||
614 | ret = -ENOMEM; | ||
615 | } else | ||
616 | ret = convert_variable_type(vr_die, pf->tvar); | ||
617 | } | ||
360 | /* *expr will be cached in libdw. Don't free it. */ | 618 | /* *expr will be cached in libdw. Don't free it. */ |
361 | return ; | 619 | return ret; |
362 | error: | 620 | error: |
363 | /* TODO: Support const_value */ | 621 | /* TODO: Support const_value */ |
364 | die("Failed to find the location of %s at this address.\n" | 622 | pr_err("Failed to find the location of %s at this address.\n" |
365 | " Perhaps, it has been optimized out.", pf->var); | 623 | " Perhaps, it has been optimized out.\n", pf->pvar->var); |
624 | return -ENOENT; | ||
366 | } | 625 | } |
367 | 626 | ||
368 | /* Find a variable in a subprogram die */ | 627 | /* Find a variable in a subprogram die */ |
369 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 628 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
370 | { | 629 | { |
371 | int ret; | ||
372 | Dwarf_Die vr_die; | 630 | Dwarf_Die vr_die; |
631 | char buf[32], *ptr; | ||
632 | int ret; | ||
373 | 633 | ||
374 | /* TODO: Support struct members and arrays */ | 634 | /* TODO: Support arrays */ |
375 | if (!is_c_varname(pf->var)) { | 635 | if (pf->pvar->name) |
376 | /* Output raw parameters */ | 636 | pf->tvar->name = strdup(pf->pvar->name); |
377 | ret = snprintf(pf->buf, pf->len, " %s", pf->var); | 637 | else { |
378 | DIE_IF(ret < 0); | 638 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); |
379 | DIE_IF(ret >= pf->len); | 639 | if (ret < 0) |
380 | return ; | 640 | return ret; |
641 | ptr = strchr(buf, ':'); /* Change type separator to _ */ | ||
642 | if (ptr) | ||
643 | *ptr = '_'; | ||
644 | pf->tvar->name = strdup(buf); | ||
645 | } | ||
646 | if (pf->tvar->name == NULL) | ||
647 | return -ENOMEM; | ||
648 | |||
649 | if (!is_c_varname(pf->pvar->var)) { | ||
650 | /* Copy raw parameters */ | ||
651 | pf->tvar->value = strdup(pf->pvar->var); | ||
652 | if (pf->tvar->value == NULL) | ||
653 | return -ENOMEM; | ||
654 | else | ||
655 | return 0; | ||
381 | } | 656 | } |
382 | 657 | ||
383 | pr_debug("Searching '%s' variable in context.\n", pf->var); | 658 | pr_debug("Searching '%s' variable in context.\n", |
659 | pf->pvar->var); | ||
384 | /* Search child die for local variables and parameters. */ | 660 | /* Search child die for local variables and parameters. */ |
385 | if (!die_find_variable(sp_die, pf->var, &vr_die)) | 661 | if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { |
386 | die("Failed to find '%s' in this function.", pf->var); | 662 | pr_warning("Failed to find '%s' in this function.\n", |
387 | 663 | pf->pvar->var); | |
388 | show_variable(&vr_die, pf); | 664 | return -ENOENT; |
665 | } | ||
666 | return convert_variable(&vr_die, pf); | ||
389 | } | 667 | } |
390 | 668 | ||
391 | /* Show a probe point to output buffer */ | 669 | /* Show a probe point to output buffer */ |
392 | static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | 670 | static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) |
393 | { | 671 | { |
394 | struct probe_point *pp = pf->pp; | 672 | struct kprobe_trace_event *tev; |
395 | Dwarf_Addr eaddr; | 673 | Dwarf_Addr eaddr; |
396 | Dwarf_Die die_mem; | 674 | Dwarf_Die die_mem; |
397 | const char *name; | 675 | const char *name; |
398 | char tmp[MAX_PROBE_BUFFER]; | 676 | int ret, i; |
399 | int ret, i, len; | ||
400 | Dwarf_Attribute fb_attr; | 677 | Dwarf_Attribute fb_attr; |
401 | size_t nops; | 678 | size_t nops; |
402 | 679 | ||
680 | if (pf->ntevs == MAX_PROBES) { | ||
681 | pr_warning("Too many( > %d) probe point found.\n", MAX_PROBES); | ||
682 | return -ERANGE; | ||
683 | } | ||
684 | tev = &pf->tevs[pf->ntevs++]; | ||
685 | |||
403 | /* If no real subprogram, find a real one */ | 686 | /* If no real subprogram, find a real one */ |
404 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 687 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { |
405 | sp_die = die_get_real_subprogram(&pf->cu_die, | 688 | sp_die = die_find_real_subprogram(&pf->cu_die, |
406 | pf->addr, &die_mem); | 689 | pf->addr, &die_mem); |
407 | if (!sp_die) | 690 | if (!sp_die) { |
408 | die("Probe point is not found in subprograms."); | 691 | pr_warning("Failed to find probe point in any " |
692 | "functions.\n"); | ||
693 | return -ENOENT; | ||
694 | } | ||
409 | } | 695 | } |
410 | 696 | ||
411 | /* Output name of probe point */ | 697 | /* Copy the name of probe point */ |
412 | name = dwarf_diename(sp_die); | 698 | name = dwarf_diename(sp_die); |
413 | if (name) { | 699 | if (name) { |
414 | dwarf_entrypc(sp_die, &eaddr); | 700 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
415 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name, | 701 | pr_warning("Failed to get entry pc of %s\n", |
416 | (unsigned long)(pf->addr - eaddr)); | 702 | dwarf_diename(sp_die)); |
417 | /* Copy the function name if possible */ | 703 | return -ENOENT; |
418 | if (!pp->function) { | ||
419 | pp->function = strdup(name); | ||
420 | pp->offset = (size_t)(pf->addr - eaddr); | ||
421 | } | 704 | } |
422 | } else { | 705 | tev->point.symbol = strdup(name); |
706 | if (tev->point.symbol == NULL) | ||
707 | return -ENOMEM; | ||
708 | tev->point.offset = (unsigned long)(pf->addr - eaddr); | ||
709 | } else | ||
423 | /* This function has no name. */ | 710 | /* This function has no name. */ |
424 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", | 711 | tev->point.offset = (unsigned long)pf->addr; |
425 | (uintmax_t)pf->addr); | 712 | |
426 | if (!pp->function) { | 713 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, |
427 | /* TODO: Use _stext */ | 714 | tev->point.offset); |
428 | pp->function = strdup(""); | ||
429 | pp->offset = (size_t)pf->addr; | ||
430 | } | ||
431 | } | ||
432 | DIE_IF(ret < 0); | ||
433 | DIE_IF(ret >= MAX_PROBE_BUFFER); | ||
434 | len = ret; | ||
435 | pr_debug("Probe point found: %s\n", tmp); | ||
436 | 715 | ||
437 | /* Get the frame base attribute/ops */ | 716 | /* Get the frame base attribute/ops */ |
438 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 717 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); |
439 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); | 718 | ret = dwarf_getlocation_addr(&fb_attr, pf->addr, &pf->fb_ops, &nops, 1); |
440 | if (ret <= 0 || nops == 0) | 719 | if (ret <= 0 || nops == 0) { |
441 | pf->fb_ops = NULL; | 720 | pf->fb_ops = NULL; |
721 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && | ||
722 | pf->cfi != NULL) { | ||
723 | Dwarf_Frame *frame; | ||
724 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || | ||
725 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { | ||
726 | pr_warning("Failed to get CFA on 0x%jx\n", | ||
727 | (uintmax_t)pf->addr); | ||
728 | return -ENOENT; | ||
729 | } | ||
730 | } | ||
442 | 731 | ||
443 | /* Find each argument */ | 732 | /* Find each argument */ |
444 | /* TODO: use dwarf_cfi_addrframe */ | 733 | tev->nargs = pf->pev->nargs; |
445 | for (i = 0; i < pp->nr_args; i++) { | 734 | tev->args = zalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); |
446 | pf->var = pp->args[i]; | 735 | if (tev->args == NULL) |
447 | pf->buf = &tmp[len]; | 736 | return -ENOMEM; |
448 | pf->len = MAX_PROBE_BUFFER - len; | 737 | for (i = 0; i < pf->pev->nargs; i++) { |
449 | find_variable(sp_die, pf); | 738 | pf->pvar = &pf->pev->args[i]; |
450 | len += strlen(pf->buf); | 739 | pf->tvar = &tev->args[i]; |
740 | ret = find_variable(sp_die, pf); | ||
741 | if (ret != 0) | ||
742 | return ret; | ||
451 | } | 743 | } |
452 | 744 | ||
453 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 745 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
454 | pf->fb_ops = NULL; | 746 | pf->fb_ops = NULL; |
455 | 747 | return 0; | |
456 | if (pp->found == MAX_PROBES) | ||
457 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | ||
458 | |||
459 | pp->probes[pp->found] = strdup(tmp); | ||
460 | pp->found++; | ||
461 | } | 748 | } |
462 | 749 | ||
463 | /* Find probe point from its line number */ | 750 | /* Find probe point from its line number */ |
464 | static void find_probe_point_by_line(struct probe_finder *pf) | 751 | static int find_probe_point_by_line(struct probe_finder *pf) |
465 | { | 752 | { |
466 | Dwarf_Lines *lines; | 753 | Dwarf_Lines *lines; |
467 | Dwarf_Line *line; | 754 | Dwarf_Line *line; |
468 | size_t nlines, i; | 755 | size_t nlines, i; |
469 | Dwarf_Addr addr; | 756 | Dwarf_Addr addr; |
470 | int lineno; | 757 | int lineno; |
471 | int ret; | 758 | int ret = 0; |
472 | 759 | ||
473 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); | 760 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
474 | DIE_IF(ret != 0); | 761 | pr_warning("No source lines found in this CU.\n"); |
762 | return -ENOENT; | ||
763 | } | ||
475 | 764 | ||
476 | for (i = 0; i < nlines; i++) { | 765 | for (i = 0; i < nlines && ret == 0; i++) { |
477 | line = dwarf_onesrcline(lines, i); | 766 | line = dwarf_onesrcline(lines, i); |
478 | dwarf_lineno(line, &lineno); | 767 | if (dwarf_lineno(line, &lineno) != 0 || |
479 | if (lineno != pf->lno) | 768 | lineno != pf->lno) |
480 | continue; | 769 | continue; |
481 | 770 | ||
482 | /* TODO: Get fileno from line, but how? */ | 771 | /* TODO: Get fileno from line, but how? */ |
483 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 772 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
484 | continue; | 773 | continue; |
485 | 774 | ||
486 | ret = dwarf_lineaddr(line, &addr); | 775 | if (dwarf_lineaddr(line, &addr) != 0) { |
487 | DIE_IF(ret != 0); | 776 | pr_warning("Failed to get the address of the line.\n"); |
777 | return -ENOENT; | ||
778 | } | ||
488 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", | 779 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", |
489 | (int)i, lineno, (uintmax_t)addr); | 780 | (int)i, lineno, (uintmax_t)addr); |
490 | pf->addr = addr; | 781 | pf->addr = addr; |
491 | 782 | ||
492 | show_probe_point(NULL, pf); | 783 | ret = convert_probe_point(NULL, pf); |
493 | /* Continuing, because target line might be inlined. */ | 784 | /* Continuing, because target line might be inlined. */ |
494 | } | 785 | } |
786 | return ret; | ||
495 | } | 787 | } |
496 | 788 | ||
497 | /* Find lines which match lazy pattern */ | 789 | /* Find lines which match lazy pattern */ |
@@ -499,16 +791,27 @@ static int find_lazy_match_lines(struct list_head *head, | |||
499 | const char *fname, const char *pat) | 791 | const char *fname, const char *pat) |
500 | { | 792 | { |
501 | char *fbuf, *p1, *p2; | 793 | char *fbuf, *p1, *p2; |
502 | int fd, line, nlines = 0; | 794 | int fd, ret, line, nlines = 0; |
503 | struct stat st; | 795 | struct stat st; |
504 | 796 | ||
505 | fd = open(fname, O_RDONLY); | 797 | fd = open(fname, O_RDONLY); |
506 | if (fd < 0) | 798 | if (fd < 0) { |
507 | die("failed to open %s", fname); | 799 | pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); |
508 | DIE_IF(fstat(fd, &st) < 0); | 800 | return fd; |
509 | fbuf = malloc(st.st_size + 2); | 801 | } |
510 | DIE_IF(fbuf == NULL); | 802 | |
511 | DIE_IF(read(fd, fbuf, st.st_size) < 0); | 803 | ret = fstat(fd, &st); |
804 | if (ret < 0) { | ||
805 | pr_warning("Failed to get the size of %s: %s\n", | ||
806 | fname, strerror(errno)); | ||
807 | return ret; | ||
808 | } | ||
809 | fbuf = xmalloc(st.st_size + 2); | ||
810 | ret = read(fd, fbuf, st.st_size); | ||
811 | if (ret < 0) { | ||
812 | pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); | ||
813 | return ret; | ||
814 | } | ||
512 | close(fd); | 815 | close(fd); |
513 | fbuf[st.st_size] = '\n'; /* Dummy line */ | 816 | fbuf[st.st_size] = '\n'; /* Dummy line */ |
514 | fbuf[st.st_size + 1] = '\0'; | 817 | fbuf[st.st_size + 1] = '\0'; |
@@ -528,7 +831,7 @@ static int find_lazy_match_lines(struct list_head *head, | |||
528 | } | 831 | } |
529 | 832 | ||
530 | /* Find probe points from lazy pattern */ | 833 | /* Find probe points from lazy pattern */ |
531 | static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 834 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
532 | { | 835 | { |
533 | Dwarf_Lines *lines; | 836 | Dwarf_Lines *lines; |
534 | Dwarf_Line *line; | 837 | Dwarf_Line *line; |
@@ -536,37 +839,46 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
536 | Dwarf_Addr addr; | 839 | Dwarf_Addr addr; |
537 | Dwarf_Die die_mem; | 840 | Dwarf_Die die_mem; |
538 | int lineno; | 841 | int lineno; |
539 | int ret; | 842 | int ret = 0; |
540 | 843 | ||
541 | if (list_empty(&pf->lcache)) { | 844 | if (list_empty(&pf->lcache)) { |
542 | /* Matching lazy line pattern */ | 845 | /* Matching lazy line pattern */ |
543 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 846 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
544 | pf->pp->lazy_line); | 847 | pf->pev->point.lazy_line); |
545 | if (ret <= 0) | 848 | if (ret == 0) { |
546 | die("No matched lines found in %s.", pf->fname); | 849 | pr_debug("No matched lines found in %s.\n", pf->fname); |
850 | return 0; | ||
851 | } else if (ret < 0) | ||
852 | return ret; | ||
547 | } | 853 | } |
548 | 854 | ||
549 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); | 855 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
550 | DIE_IF(ret != 0); | 856 | pr_warning("No source lines found in this CU.\n"); |
551 | for (i = 0; i < nlines; i++) { | 857 | return -ENOENT; |
858 | } | ||
859 | |||
860 | for (i = 0; i < nlines && ret >= 0; i++) { | ||
552 | line = dwarf_onesrcline(lines, i); | 861 | line = dwarf_onesrcline(lines, i); |
553 | 862 | ||
554 | dwarf_lineno(line, &lineno); | 863 | if (dwarf_lineno(line, &lineno) != 0 || |
555 | if (!line_list__has_line(&pf->lcache, lineno)) | 864 | !line_list__has_line(&pf->lcache, lineno)) |
556 | continue; | 865 | continue; |
557 | 866 | ||
558 | /* TODO: Get fileno from line, but how? */ | 867 | /* TODO: Get fileno from line, but how? */ |
559 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 868 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
560 | continue; | 869 | continue; |
561 | 870 | ||
562 | ret = dwarf_lineaddr(line, &addr); | 871 | if (dwarf_lineaddr(line, &addr) != 0) { |
563 | DIE_IF(ret != 0); | 872 | pr_debug("Failed to get the address of line %d.\n", |
873 | lineno); | ||
874 | continue; | ||
875 | } | ||
564 | if (sp_die) { | 876 | if (sp_die) { |
565 | /* Address filtering 1: does sp_die include addr? */ | 877 | /* Address filtering 1: does sp_die include addr? */ |
566 | if (!dwarf_haspc(sp_die, addr)) | 878 | if (!dwarf_haspc(sp_die, addr)) |
567 | continue; | 879 | continue; |
568 | /* Address filtering 2: No child include addr? */ | 880 | /* Address filtering 2: No child include addr? */ |
569 | if (die_get_inlinefunc(sp_die, addr, &die_mem)) | 881 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) |
570 | continue; | 882 | continue; |
571 | } | 883 | } |
572 | 884 | ||
@@ -574,27 +886,42 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
574 | (int)i, lineno, (unsigned long long)addr); | 886 | (int)i, lineno, (unsigned long long)addr); |
575 | pf->addr = addr; | 887 | pf->addr = addr; |
576 | 888 | ||
577 | show_probe_point(sp_die, pf); | 889 | ret = convert_probe_point(sp_die, pf); |
578 | /* Continuing, because target line might be inlined. */ | 890 | /* Continuing, because target line might be inlined. */ |
579 | } | 891 | } |
580 | /* TODO: deallocate lines, but how? */ | 892 | /* TODO: deallocate lines, but how? */ |
893 | return ret; | ||
581 | } | 894 | } |
582 | 895 | ||
896 | /* Callback parameter with return value */ | ||
897 | struct dwarf_callback_param { | ||
898 | void *data; | ||
899 | int retval; | ||
900 | }; | ||
901 | |||
583 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 902 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
584 | { | 903 | { |
585 | struct probe_finder *pf = (struct probe_finder *)data; | 904 | struct dwarf_callback_param *param = data; |
586 | struct probe_point *pp = pf->pp; | 905 | struct probe_finder *pf = param->data; |
906 | struct perf_probe_point *pp = &pf->pev->point; | ||
907 | Dwarf_Addr addr; | ||
587 | 908 | ||
588 | if (pp->lazy_line) | 909 | if (pp->lazy_line) |
589 | find_probe_point_lazy(in_die, pf); | 910 | param->retval = find_probe_point_lazy(in_die, pf); |
590 | else { | 911 | else { |
591 | /* Get probe address */ | 912 | /* Get probe address */ |
592 | pf->addr = die_get_entrypc(in_die); | 913 | if (dwarf_entrypc(in_die, &addr) != 0) { |
914 | pr_warning("Failed to get entry pc of %s.\n", | ||
915 | dwarf_diename(in_die)); | ||
916 | param->retval = -ENOENT; | ||
917 | return DWARF_CB_ABORT; | ||
918 | } | ||
919 | pf->addr = addr; | ||
593 | pf->addr += pp->offset; | 920 | pf->addr += pp->offset; |
594 | pr_debug("found inline addr: 0x%jx\n", | 921 | pr_debug("found inline addr: 0x%jx\n", |
595 | (uintmax_t)pf->addr); | 922 | (uintmax_t)pf->addr); |
596 | 923 | ||
597 | show_probe_point(in_die, pf); | 924 | param->retval = convert_probe_point(in_die, pf); |
598 | } | 925 | } |
599 | 926 | ||
600 | return DWARF_CB_OK; | 927 | return DWARF_CB_OK; |
@@ -603,59 +930,88 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | |||
603 | /* Search function from function name */ | 930 | /* Search function from function name */ |
604 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 931 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
605 | { | 932 | { |
606 | struct probe_finder *pf = (struct probe_finder *)data; | 933 | struct dwarf_callback_param *param = data; |
607 | struct probe_point *pp = pf->pp; | 934 | struct probe_finder *pf = param->data; |
935 | struct perf_probe_point *pp = &pf->pev->point; | ||
608 | 936 | ||
609 | /* Check tag and diename */ | 937 | /* Check tag and diename */ |
610 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 938 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
611 | die_compare_name(sp_die, pp->function) != 0) | 939 | die_compare_name(sp_die, pp->function) != 0) |
612 | return 0; | 940 | return DWARF_CB_OK; |
613 | 941 | ||
614 | pf->fname = dwarf_decl_file(sp_die); | 942 | pf->fname = dwarf_decl_file(sp_die); |
615 | if (pp->line) { /* Function relative line */ | 943 | if (pp->line) { /* Function relative line */ |
616 | dwarf_decl_line(sp_die, &pf->lno); | 944 | dwarf_decl_line(sp_die, &pf->lno); |
617 | pf->lno += pp->line; | 945 | pf->lno += pp->line; |
618 | find_probe_point_by_line(pf); | 946 | param->retval = find_probe_point_by_line(pf); |
619 | } else if (!dwarf_func_inline(sp_die)) { | 947 | } else if (!dwarf_func_inline(sp_die)) { |
620 | /* Real function */ | 948 | /* Real function */ |
621 | if (pp->lazy_line) | 949 | if (pp->lazy_line) |
622 | find_probe_point_lazy(sp_die, pf); | 950 | param->retval = find_probe_point_lazy(sp_die, pf); |
623 | else { | 951 | else { |
624 | pf->addr = die_get_entrypc(sp_die); | 952 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { |
953 | pr_warning("Failed to get entry pc of %s.\n", | ||
954 | dwarf_diename(sp_die)); | ||
955 | param->retval = -ENOENT; | ||
956 | return DWARF_CB_ABORT; | ||
957 | } | ||
625 | pf->addr += pp->offset; | 958 | pf->addr += pp->offset; |
626 | /* TODO: Check the address in this function */ | 959 | /* TODO: Check the address in this function */ |
627 | show_probe_point(sp_die, pf); | 960 | param->retval = convert_probe_point(sp_die, pf); |
628 | } | 961 | } |
629 | } else | 962 | } else { |
963 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
964 | .retval = 0}; | ||
630 | /* Inlined function: search instances */ | 965 | /* Inlined function: search instances */ |
631 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); | 966 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, |
967 | &_param); | ||
968 | param->retval = _param.retval; | ||
969 | } | ||
632 | 970 | ||
633 | return 1; /* Exit; no same symbol in this CU. */ | 971 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
634 | } | 972 | } |
635 | 973 | ||
636 | static void find_probe_point_by_func(struct probe_finder *pf) | 974 | static int find_probe_point_by_func(struct probe_finder *pf) |
637 | { | 975 | { |
638 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); | 976 | struct dwarf_callback_param _param = {.data = (void *)pf, |
977 | .retval = 0}; | ||
978 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); | ||
979 | return _param.retval; | ||
639 | } | 980 | } |
640 | 981 | ||
641 | /* Find a probe point */ | 982 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ |
642 | int find_probe_point(int fd, struct probe_point *pp) | 983 | int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, |
984 | struct kprobe_trace_event **tevs) | ||
643 | { | 985 | { |
644 | struct probe_finder pf = {.pp = pp}; | 986 | struct probe_finder pf = {.pev = pev}; |
987 | struct perf_probe_point *pp = &pev->point; | ||
645 | Dwarf_Off off, noff; | 988 | Dwarf_Off off, noff; |
646 | size_t cuhl; | 989 | size_t cuhl; |
647 | Dwarf_Die *diep; | 990 | Dwarf_Die *diep; |
648 | Dwarf *dbg; | 991 | Dwarf *dbg; |
992 | int ret = 0; | ||
993 | |||
994 | pf.tevs = zalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); | ||
995 | if (pf.tevs == NULL) | ||
996 | return -ENOMEM; | ||
997 | *tevs = pf.tevs; | ||
998 | pf.ntevs = 0; | ||
649 | 999 | ||
650 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1000 | dbg = dwarf_begin(fd, DWARF_C_READ); |
651 | if (!dbg) | 1001 | if (!dbg) { |
652 | return -ENOENT; | 1002 | pr_warning("No dwarf info found in the vmlinux - " |
1003 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1004 | return -EBADF; | ||
1005 | } | ||
1006 | |||
1007 | /* Get the call frame information from this dwarf */ | ||
1008 | pf.cfi = dwarf_getcfi(dbg); | ||
653 | 1009 | ||
654 | pp->found = 0; | ||
655 | off = 0; | 1010 | off = 0; |
656 | line_list__init(&pf.lcache); | 1011 | line_list__init(&pf.lcache); |
657 | /* Loop on CUs (Compilation Unit) */ | 1012 | /* Loop on CUs (Compilation Unit) */ |
658 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | 1013 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && |
1014 | ret >= 0) { | ||
659 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1015 | /* Get the DIE(Debugging Information Entry) of this CU */ |
660 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); | 1016 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); |
661 | if (!diep) | 1017 | if (!diep) |
@@ -669,12 +1025,12 @@ int find_probe_point(int fd, struct probe_point *pp) | |||
669 | 1025 | ||
670 | if (!pp->file || pf.fname) { | 1026 | if (!pp->file || pf.fname) { |
671 | if (pp->function) | 1027 | if (pp->function) |
672 | find_probe_point_by_func(&pf); | 1028 | ret = find_probe_point_by_func(&pf); |
673 | else if (pp->lazy_line) | 1029 | else if (pp->lazy_line) |
674 | find_probe_point_lazy(NULL, &pf); | 1030 | ret = find_probe_point_lazy(NULL, &pf); |
675 | else { | 1031 | else { |
676 | pf.lno = pp->line; | 1032 | pf.lno = pp->line; |
677 | find_probe_point_by_line(&pf); | 1033 | ret = find_probe_point_by_line(&pf); |
678 | } | 1034 | } |
679 | } | 1035 | } |
680 | off = noff; | 1036 | off = noff; |
@@ -682,41 +1038,167 @@ int find_probe_point(int fd, struct probe_point *pp) | |||
682 | line_list__free(&pf.lcache); | 1038 | line_list__free(&pf.lcache); |
683 | dwarf_end(dbg); | 1039 | dwarf_end(dbg); |
684 | 1040 | ||
685 | return pp->found; | 1041 | return (ret < 0) ? ret : pf.ntevs; |
1042 | } | ||
1043 | |||
1044 | /* Reverse search */ | ||
1045 | int find_perf_probe_point(int fd, unsigned long addr, | ||
1046 | struct perf_probe_point *ppt) | ||
1047 | { | ||
1048 | Dwarf_Die cudie, spdie, indie; | ||
1049 | Dwarf *dbg; | ||
1050 | Dwarf_Line *line; | ||
1051 | Dwarf_Addr laddr, eaddr; | ||
1052 | const char *tmp; | ||
1053 | int lineno, ret = 0; | ||
1054 | bool found = false; | ||
1055 | |||
1056 | dbg = dwarf_begin(fd, DWARF_C_READ); | ||
1057 | if (!dbg) | ||
1058 | return -EBADF; | ||
1059 | |||
1060 | /* Find cu die */ | ||
1061 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { | ||
1062 | ret = -EINVAL; | ||
1063 | goto end; | ||
1064 | } | ||
1065 | |||
1066 | /* Find a corresponding line */ | ||
1067 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | ||
1068 | if (line) { | ||
1069 | if (dwarf_lineaddr(line, &laddr) == 0 && | ||
1070 | (Dwarf_Addr)addr == laddr && | ||
1071 | dwarf_lineno(line, &lineno) == 0) { | ||
1072 | tmp = dwarf_linesrc(line, NULL, NULL); | ||
1073 | if (tmp) { | ||
1074 | ppt->line = lineno; | ||
1075 | ppt->file = strdup(tmp); | ||
1076 | if (ppt->file == NULL) { | ||
1077 | ret = -ENOMEM; | ||
1078 | goto end; | ||
1079 | } | ||
1080 | found = true; | ||
1081 | } | ||
1082 | } | ||
1083 | } | ||
1084 | |||
1085 | /* Find a corresponding function */ | ||
1086 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | ||
1087 | tmp = dwarf_diename(&spdie); | ||
1088 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) | ||
1089 | goto end; | ||
1090 | |||
1091 | if (ppt->line) { | ||
1092 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, | ||
1093 | &indie)) { | ||
1094 | /* addr in an inline function */ | ||
1095 | tmp = dwarf_diename(&indie); | ||
1096 | if (!tmp) | ||
1097 | goto end; | ||
1098 | ret = dwarf_decl_line(&indie, &lineno); | ||
1099 | } else { | ||
1100 | if (eaddr == addr) { /* Function entry */ | ||
1101 | lineno = ppt->line; | ||
1102 | ret = 0; | ||
1103 | } else | ||
1104 | ret = dwarf_decl_line(&spdie, &lineno); | ||
1105 | } | ||
1106 | if (ret == 0) { | ||
1107 | /* Make a relative line number */ | ||
1108 | ppt->line -= lineno; | ||
1109 | goto found; | ||
1110 | } | ||
1111 | } | ||
1112 | /* We don't have a line number, let's use offset */ | ||
1113 | ppt->offset = addr - (unsigned long)eaddr; | ||
1114 | found: | ||
1115 | ppt->function = strdup(tmp); | ||
1116 | if (ppt->function == NULL) { | ||
1117 | ret = -ENOMEM; | ||
1118 | goto end; | ||
1119 | } | ||
1120 | found = true; | ||
1121 | } | ||
1122 | |||
1123 | end: | ||
1124 | dwarf_end(dbg); | ||
1125 | if (ret >= 0) | ||
1126 | ret = found ? 1 : 0; | ||
1127 | return ret; | ||
1128 | } | ||
1129 | |||
1130 | /* Add a line and store the src path */ | ||
1131 | static int line_range_add_line(const char *src, unsigned int lineno, | ||
1132 | struct line_range *lr) | ||
1133 | { | ||
1134 | /* Copy real path */ | ||
1135 | if (!lr->path) { | ||
1136 | lr->path = strdup(src); | ||
1137 | if (lr->path == NULL) | ||
1138 | return -ENOMEM; | ||
1139 | } | ||
1140 | return line_list__add_line(&lr->line_list, lineno); | ||
1141 | } | ||
1142 | |||
1143 | /* Search function declaration lines */ | ||
1144 | static int line_range_funcdecl_cb(Dwarf_Die *sp_die, void *data) | ||
1145 | { | ||
1146 | struct dwarf_callback_param *param = data; | ||
1147 | struct line_finder *lf = param->data; | ||
1148 | const char *src; | ||
1149 | int lineno; | ||
1150 | |||
1151 | src = dwarf_decl_file(sp_die); | ||
1152 | if (src && strtailcmp(src, lf->fname) != 0) | ||
1153 | return DWARF_CB_OK; | ||
1154 | |||
1155 | if (dwarf_decl_line(sp_die, &lineno) != 0 || | ||
1156 | (lf->lno_s > lineno || lf->lno_e < lineno)) | ||
1157 | return DWARF_CB_OK; | ||
1158 | |||
1159 | param->retval = line_range_add_line(src, lineno, lf->lr); | ||
1160 | return DWARF_CB_OK; | ||
1161 | } | ||
1162 | |||
1163 | static int find_line_range_func_decl_lines(struct line_finder *lf) | ||
1164 | { | ||
1165 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; | ||
1166 | dwarf_getfuncs(&lf->cu_die, line_range_funcdecl_cb, ¶m, 0); | ||
1167 | return param.retval; | ||
686 | } | 1168 | } |
687 | 1169 | ||
688 | /* Find line range from its line number */ | 1170 | /* Find line range from its line number */ |
689 | static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1171 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
690 | { | 1172 | { |
691 | Dwarf_Lines *lines; | 1173 | Dwarf_Lines *lines; |
692 | Dwarf_Line *line; | 1174 | Dwarf_Line *line; |
693 | size_t nlines, i; | 1175 | size_t nlines, i; |
694 | Dwarf_Addr addr; | 1176 | Dwarf_Addr addr; |
695 | int lineno; | 1177 | int lineno, ret = 0; |
696 | int ret; | ||
697 | const char *src; | 1178 | const char *src; |
698 | Dwarf_Die die_mem; | 1179 | Dwarf_Die die_mem; |
699 | 1180 | ||
700 | line_list__init(&lf->lr->line_list); | 1181 | line_list__init(&lf->lr->line_list); |
701 | ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); | 1182 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { |
702 | DIE_IF(ret != 0); | 1183 | pr_warning("No source lines found in this CU.\n"); |
1184 | return -ENOENT; | ||
1185 | } | ||
703 | 1186 | ||
1187 | /* Search probable lines on lines list */ | ||
704 | for (i = 0; i < nlines; i++) { | 1188 | for (i = 0; i < nlines; i++) { |
705 | line = dwarf_onesrcline(lines, i); | 1189 | line = dwarf_onesrcline(lines, i); |
706 | ret = dwarf_lineno(line, &lineno); | 1190 | if (dwarf_lineno(line, &lineno) != 0 || |
707 | DIE_IF(ret != 0); | 1191 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
708 | if (lf->lno_s > lineno || lf->lno_e < lineno) | ||
709 | continue; | 1192 | continue; |
710 | 1193 | ||
711 | if (sp_die) { | 1194 | if (sp_die) { |
712 | /* Address filtering 1: does sp_die include addr? */ | 1195 | /* Address filtering 1: does sp_die include addr? */ |
713 | ret = dwarf_lineaddr(line, &addr); | 1196 | if (dwarf_lineaddr(line, &addr) != 0 || |
714 | DIE_IF(ret != 0); | 1197 | !dwarf_haspc(sp_die, addr)) |
715 | if (!dwarf_haspc(sp_die, addr)) | ||
716 | continue; | 1198 | continue; |
717 | 1199 | ||
718 | /* Address filtering 2: No child include addr? */ | 1200 | /* Address filtering 2: No child include addr? */ |
719 | if (die_get_inlinefunc(sp_die, addr, &die_mem)) | 1201 | if (die_find_inlinefunc(sp_die, addr, &die_mem)) |
720 | continue; | 1202 | continue; |
721 | } | 1203 | } |
722 | 1204 | ||
@@ -725,30 +1207,49 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
725 | if (strtailcmp(src, lf->fname) != 0) | 1207 | if (strtailcmp(src, lf->fname) != 0) |
726 | continue; | 1208 | continue; |
727 | 1209 | ||
728 | /* Copy real path */ | 1210 | ret = line_range_add_line(src, lineno, lf->lr); |
729 | if (!lf->lr->path) | 1211 | if (ret < 0) |
730 | lf->lr->path = strdup(src); | 1212 | return ret; |
731 | line_list__add_line(&lf->lr->line_list, (unsigned int)lineno); | ||
732 | } | 1213 | } |
1214 | |||
1215 | /* | ||
1216 | * Dwarf lines doesn't include function declarations. We have to | ||
1217 | * check functions list or given function. | ||
1218 | */ | ||
1219 | if (sp_die) { | ||
1220 | src = dwarf_decl_file(sp_die); | ||
1221 | if (src && dwarf_decl_line(sp_die, &lineno) == 0 && | ||
1222 | (lf->lno_s <= lineno && lf->lno_e >= lineno)) | ||
1223 | ret = line_range_add_line(src, lineno, lf->lr); | ||
1224 | } else | ||
1225 | ret = find_line_range_func_decl_lines(lf); | ||
1226 | |||
733 | /* Update status */ | 1227 | /* Update status */ |
734 | if (!list_empty(&lf->lr->line_list)) | 1228 | if (ret >= 0) |
735 | lf->found = 1; | 1229 | if (!list_empty(&lf->lr->line_list)) |
1230 | ret = lf->found = 1; | ||
1231 | else | ||
1232 | ret = 0; /* Lines are not found */ | ||
736 | else { | 1233 | else { |
737 | free(lf->lr->path); | 1234 | free(lf->lr->path); |
738 | lf->lr->path = NULL; | 1235 | lf->lr->path = NULL; |
739 | } | 1236 | } |
1237 | return ret; | ||
740 | } | 1238 | } |
741 | 1239 | ||
742 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1240 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
743 | { | 1241 | { |
744 | find_line_range_by_line(in_die, (struct line_finder *)data); | 1242 | struct dwarf_callback_param *param = data; |
1243 | |||
1244 | param->retval = find_line_range_by_line(in_die, param->data); | ||
745 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1245 | return DWARF_CB_ABORT; /* No need to find other instances */ |
746 | } | 1246 | } |
747 | 1247 | ||
748 | /* Search function from function name */ | 1248 | /* Search function from function name */ |
749 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1249 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
750 | { | 1250 | { |
751 | struct line_finder *lf = (struct line_finder *)data; | 1251 | struct dwarf_callback_param *param = data; |
1252 | struct line_finder *lf = param->data; | ||
752 | struct line_range *lr = lf->lr; | 1253 | struct line_range *lr = lf->lr; |
753 | 1254 | ||
754 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1255 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
@@ -757,44 +1258,55 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
757 | dwarf_decl_line(sp_die, &lr->offset); | 1258 | dwarf_decl_line(sp_die, &lr->offset); |
758 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); | 1259 | pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset); |
759 | lf->lno_s = lr->offset + lr->start; | 1260 | lf->lno_s = lr->offset + lr->start; |
760 | if (!lr->end) | 1261 | if (lf->lno_s < 0) /* Overflow */ |
1262 | lf->lno_s = INT_MAX; | ||
1263 | lf->lno_e = lr->offset + lr->end; | ||
1264 | if (lf->lno_e < 0) /* Overflow */ | ||
761 | lf->lno_e = INT_MAX; | 1265 | lf->lno_e = INT_MAX; |
762 | else | 1266 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
763 | lf->lno_e = lr->offset + lr->end; | ||
764 | lr->start = lf->lno_s; | 1267 | lr->start = lf->lno_s; |
765 | lr->end = lf->lno_e; | 1268 | lr->end = lf->lno_e; |
766 | if (dwarf_func_inline(sp_die)) | 1269 | if (dwarf_func_inline(sp_die)) { |
1270 | struct dwarf_callback_param _param; | ||
1271 | _param.data = (void *)lf; | ||
1272 | _param.retval = 0; | ||
767 | dwarf_func_inline_instances(sp_die, | 1273 | dwarf_func_inline_instances(sp_die, |
768 | line_range_inline_cb, lf); | 1274 | line_range_inline_cb, |
769 | else | 1275 | &_param); |
770 | find_line_range_by_line(sp_die, lf); | 1276 | param->retval = _param.retval; |
771 | return 1; | 1277 | } else |
1278 | param->retval = find_line_range_by_line(sp_die, lf); | ||
1279 | return DWARF_CB_ABORT; | ||
772 | } | 1280 | } |
773 | return 0; | 1281 | return DWARF_CB_OK; |
774 | } | 1282 | } |
775 | 1283 | ||
776 | static void find_line_range_by_func(struct line_finder *lf) | 1284 | static int find_line_range_by_func(struct line_finder *lf) |
777 | { | 1285 | { |
778 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0); | 1286 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; |
1287 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); | ||
1288 | return param.retval; | ||
779 | } | 1289 | } |
780 | 1290 | ||
781 | int find_line_range(int fd, struct line_range *lr) | 1291 | int find_line_range(int fd, struct line_range *lr) |
782 | { | 1292 | { |
783 | struct line_finder lf = {.lr = lr, .found = 0}; | 1293 | struct line_finder lf = {.lr = lr, .found = 0}; |
784 | int ret; | 1294 | int ret = 0; |
785 | Dwarf_Off off = 0, noff; | 1295 | Dwarf_Off off = 0, noff; |
786 | size_t cuhl; | 1296 | size_t cuhl; |
787 | Dwarf_Die *diep; | 1297 | Dwarf_Die *diep; |
788 | Dwarf *dbg; | 1298 | Dwarf *dbg; |
789 | 1299 | ||
790 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1300 | dbg = dwarf_begin(fd, DWARF_C_READ); |
791 | if (!dbg) | 1301 | if (!dbg) { |
792 | return -ENOENT; | 1302 | pr_warning("No dwarf info found in the vmlinux - " |
1303 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1304 | return -EBADF; | ||
1305 | } | ||
793 | 1306 | ||
794 | /* Loop on CUs (Compilation Unit) */ | 1307 | /* Loop on CUs (Compilation Unit) */ |
795 | while (!lf.found) { | 1308 | while (!lf.found && ret >= 0) { |
796 | ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); | 1309 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) |
797 | if (ret != 0) | ||
798 | break; | 1310 | break; |
799 | 1311 | ||
800 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1312 | /* Get the DIE(Debugging Information Entry) of this CU */ |
@@ -810,20 +1322,18 @@ int find_line_range(int fd, struct line_range *lr) | |||
810 | 1322 | ||
811 | if (!lr->file || lf.fname) { | 1323 | if (!lr->file || lf.fname) { |
812 | if (lr->function) | 1324 | if (lr->function) |
813 | find_line_range_by_func(&lf); | 1325 | ret = find_line_range_by_func(&lf); |
814 | else { | 1326 | else { |
815 | lf.lno_s = lr->start; | 1327 | lf.lno_s = lr->start; |
816 | if (!lr->end) | 1328 | lf.lno_e = lr->end; |
817 | lf.lno_e = INT_MAX; | 1329 | ret = find_line_range_by_line(NULL, &lf); |
818 | else | ||
819 | lf.lno_e = lr->end; | ||
820 | find_line_range_by_line(NULL, &lf); | ||
821 | } | 1330 | } |
822 | } | 1331 | } |
823 | off = noff; | 1332 | off = noff; |
824 | } | 1333 | } |
825 | pr_debug("path: %lx\n", (unsigned long)lr->path); | 1334 | pr_debug("path: %lx\n", (unsigned long)lr->path); |
826 | dwarf_end(dbg); | 1335 | dwarf_end(dbg); |
827 | return lf.found; | 1336 | |
1337 | return (ret < 0) ? ret : lf.found; | ||
828 | } | 1338 | } |
829 | 1339 | ||