diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-04-12 13:17:35 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2010-04-14 16:28:30 -0400 |
commit | b55a87ade3839c33ab94768a0b5955734073f987 (patch) | |
tree | 7e4d2f9e49b4c4a99257bdf1ee61164d12e3ba7e /tools/perf/util/probe-finder.c | |
parent | a34a985499895a46a4dacff727d0fbc63cdc75e8 (diff) |
perf probe: Remove die() from probe-finder code
Remove die() and DIE_IF() code from util/probe-finder.c since
these 'sudden death' in utility functions make reusing it from
other code (especially tui/gui) difficult.
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
LKML-Reference: <20100412171735.3790.88853.stgit@localhost6.localdomain6>
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 517 |
1 files changed, 320 insertions, 197 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 1f4528555d42..54daa91e901d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -196,19 +196,7 @@ static bool die_compare_name(Dwarf_Die *dw_die, const char *tname) | |||
196 | { | 196 | { |
197 | const char *name; | 197 | const char *name; |
198 | name = dwarf_diename(dw_die); | 198 | name = dwarf_diename(dw_die); |
199 | DIE_IF(name == NULL); | 199 | return name ? strcmp(tname, name) : -1; |
200 | return strcmp(tname, name); | ||
201 | } | ||
202 | |||
203 | /* Get entry pc(or low pc, 1st entry of ranges) of the die */ | ||
204 | static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | ||
205 | { | ||
206 | Dwarf_Addr epc; | ||
207 | int ret; | ||
208 | |||
209 | ret = dwarf_entrypc(dw_die, &epc); | ||
210 | DIE_IF(ret == -1); | ||
211 | return epc; | ||
212 | } | 200 | } |
213 | 201 | ||
214 | /* Get type die, but skip qualifiers and typedef */ | 202 | /* Get type die, but skip qualifiers and typedef */ |
@@ -390,7 +378,7 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | |||
390 | */ | 378 | */ |
391 | 379 | ||
392 | /* Show a location */ | 380 | /* Show a location */ |
393 | static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | 381 | static int convert_location(Dwarf_Op *op, struct probe_finder *pf) |
394 | { | 382 | { |
395 | unsigned int regn; | 383 | unsigned int regn; |
396 | Dwarf_Word offs = 0; | 384 | Dwarf_Word offs = 0; |
@@ -400,8 +388,11 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | |||
400 | 388 | ||
401 | /* If this is based on frame buffer, set the offset */ | 389 | /* If this is based on frame buffer, set the offset */ |
402 | if (op->atom == DW_OP_fbreg) { | 390 | if (op->atom == DW_OP_fbreg) { |
403 | if (pf->fb_ops == NULL) | 391 | if (pf->fb_ops == NULL) { |
404 | die("The attribute of frame base is not supported.\n"); | 392 | pr_warning("The attribute of frame base is not " |
393 | "supported.\n"); | ||
394 | return -ENOTSUP; | ||
395 | } | ||
405 | ref = true; | 396 | ref = true; |
406 | offs = op->number; | 397 | offs = op->number; |
407 | op = &pf->fb_ops[0]; | 398 | op = &pf->fb_ops[0]; |
@@ -419,50 +410,63 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | |||
419 | ref = true; | 410 | ref = true; |
420 | } else if (op->atom == DW_OP_regx) { | 411 | } else if (op->atom == DW_OP_regx) { |
421 | regn = op->number; | 412 | regn = op->number; |
422 | } else | 413 | } else { |
423 | die("DW_OP %d is not supported.", op->atom); | 414 | pr_warning("DW_OP %x is not supported.\n", op->atom); |
415 | return -ENOTSUP; | ||
416 | } | ||
424 | 417 | ||
425 | regs = get_arch_regstr(regn); | 418 | regs = get_arch_regstr(regn); |
426 | if (!regs) | 419 | if (!regs) { |
427 | die("%u exceeds max register number.", regn); | 420 | pr_warning("%u exceeds max register number.\n", regn); |
421 | return -ERANGE; | ||
422 | } | ||
428 | 423 | ||
429 | tvar->value = xstrdup(regs); | 424 | tvar->value = xstrdup(regs); |
430 | if (ref) { | 425 | if (ref) { |
431 | tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); | 426 | tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); |
432 | tvar->ref->offset = (long)offs; | 427 | tvar->ref->offset = (long)offs; |
433 | } | 428 | } |
429 | return 0; | ||
434 | } | 430 | } |
435 | 431 | ||
436 | static void convert_variable_type(Dwarf_Die *vr_die, | 432 | static int convert_variable_type(Dwarf_Die *vr_die, |
437 | struct kprobe_trace_arg *targ) | 433 | struct kprobe_trace_arg *targ) |
438 | { | 434 | { |
439 | Dwarf_Die type; | 435 | Dwarf_Die type; |
440 | char buf[16]; | 436 | char buf[16]; |
441 | int ret; | 437 | int ret; |
442 | 438 | ||
443 | if (die_get_real_type(vr_die, &type) == NULL) | 439 | if (die_get_real_type(vr_die, &type) == NULL) { |
444 | die("Failed to get a type information of %s.", | 440 | pr_warning("Failed to get a type information of %s.\n", |
445 | dwarf_diename(vr_die)); | 441 | dwarf_diename(vr_die)); |
442 | return -ENOENT; | ||
443 | } | ||
446 | 444 | ||
447 | ret = die_get_byte_size(&type) * 8; | 445 | ret = die_get_byte_size(&type) * 8; |
448 | if (ret) { | 446 | if (ret) { |
449 | /* Check the bitwidth */ | 447 | /* Check the bitwidth */ |
450 | if (ret > MAX_BASIC_TYPE_BITS) { | 448 | if (ret > MAX_BASIC_TYPE_BITS) { |
451 | pr_warning(" Warning: %s exceeds max-bitwidth." | 449 | pr_info("%s exceeds max-bitwidth." |
452 | " Cut down to %d bits.\n", | 450 | " Cut down to %d bits.\n", |
453 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); | 451 | dwarf_diename(&type), MAX_BASIC_TYPE_BITS); |
454 | ret = MAX_BASIC_TYPE_BITS; | 452 | ret = MAX_BASIC_TYPE_BITS; |
455 | } | 453 | } |
456 | 454 | ||
457 | ret = snprintf(buf, 16, "%c%d", | 455 | ret = snprintf(buf, 16, "%c%d", |
458 | die_is_signed_type(&type) ? 's' : 'u', ret); | 456 | die_is_signed_type(&type) ? 's' : 'u', ret); |
459 | if (ret < 0 || ret >= 16) | 457 | if (ret < 0 || ret >= 16) { |
460 | die("Failed to convert variable type."); | 458 | if (ret >= 16) |
459 | ret = -E2BIG; | ||
460 | pr_warning("Failed to convert variable type: %s\n", | ||
461 | strerror(-ret)); | ||
462 | return ret; | ||
463 | } | ||
461 | targ->type = xstrdup(buf); | 464 | targ->type = xstrdup(buf); |
462 | } | 465 | } |
466 | return 0; | ||
463 | } | 467 | } |
464 | 468 | ||
465 | static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | 469 | static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname, |
466 | struct perf_probe_arg_field *field, | 470 | struct perf_probe_arg_field *field, |
467 | struct kprobe_trace_arg_ref **ref_ptr, | 471 | struct kprobe_trace_arg_ref **ref_ptr, |
468 | Dwarf_Die *die_mem) | 472 | Dwarf_Die *die_mem) |
@@ -473,21 +477,28 @@ static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
473 | Dwarf_Word offs; | 477 | Dwarf_Word offs; |
474 | 478 | ||
475 | pr_debug("converting %s in %s\n", field->name, varname); | 479 | pr_debug("converting %s in %s\n", field->name, varname); |
476 | if (die_get_real_type(vr_die, &type) == NULL) | 480 | if (die_get_real_type(vr_die, &type) == NULL) { |
477 | die("Failed to get a type information of %s.", varname); | 481 | pr_warning("Failed to get the type of %s.\n", varname); |
482 | return -ENOENT; | ||
483 | } | ||
478 | 484 | ||
479 | /* Check the pointer and dereference */ | 485 | /* Check the pointer and dereference */ |
480 | if (dwarf_tag(&type) == DW_TAG_pointer_type) { | 486 | if (dwarf_tag(&type) == DW_TAG_pointer_type) { |
481 | if (!field->ref) | 487 | if (!field->ref) { |
482 | die("Semantic error: %s must be referred by '->'", | 488 | pr_err("Semantic error: %s must be referred by '->'\n", |
483 | field->name); | 489 | field->name); |
490 | return -EINVAL; | ||
491 | } | ||
484 | /* Get the type pointed by this pointer */ | 492 | /* Get the type pointed by this pointer */ |
485 | if (die_get_real_type(&type, &type) == NULL) | 493 | if (die_get_real_type(&type, &type) == NULL) { |
486 | die("Failed to get a type information of %s.", varname); | 494 | pr_warning("Failed to get the type of %s.\n", varname); |
487 | 495 | return -ENOENT; | |
496 | } | ||
488 | /* Verify it is a data structure */ | 497 | /* Verify it is a data structure */ |
489 | if (dwarf_tag(&type) != DW_TAG_structure_type) | 498 | if (dwarf_tag(&type) != DW_TAG_structure_type) { |
490 | die("%s is not a data structure.", varname); | 499 | pr_warning("%s is not a data structure.\n", varname); |
500 | return -EINVAL; | ||
501 | } | ||
491 | 502 | ||
492 | ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); | 503 | ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); |
493 | if (*ref_ptr) | 504 | if (*ref_ptr) |
@@ -496,34 +507,46 @@ static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | |||
496 | *ref_ptr = ref; | 507 | *ref_ptr = ref; |
497 | } else { | 508 | } else { |
498 | /* Verify it is a data structure */ | 509 | /* Verify it is a data structure */ |
499 | if (dwarf_tag(&type) != DW_TAG_structure_type) | 510 | if (dwarf_tag(&type) != DW_TAG_structure_type) { |
500 | die("%s is not a data structure.", varname); | 511 | pr_warning("%s is not a data structure.\n", varname); |
501 | 512 | return -EINVAL; | |
502 | if (field->ref) | 513 | } |
503 | die("Semantic error: %s must be referred by '.'", | 514 | if (field->ref) { |
504 | field->name); | 515 | pr_err("Semantic error: %s must be referred by '.'\n", |
505 | if (!ref) | 516 | field->name); |
506 | die("Structure on a register is not supported yet."); | 517 | return -EINVAL; |
518 | } | ||
519 | if (!ref) { | ||
520 | pr_warning("Structure on a register is not " | ||
521 | "supported yet.\n"); | ||
522 | return -ENOTSUP; | ||
523 | } | ||
507 | } | 524 | } |
508 | 525 | ||
509 | if (die_find_member(&type, field->name, die_mem) == NULL) | 526 | if (die_find_member(&type, field->name, die_mem) == NULL) { |
510 | die("%s(tyep:%s) has no member %s.", varname, | 527 | pr_warning("%s(tyep:%s) has no member %s.\n", varname, |
511 | dwarf_diename(&type), field->name); | 528 | dwarf_diename(&type), field->name); |
529 | return -EINVAL; | ||
530 | } | ||
512 | 531 | ||
513 | /* Get the offset of the field */ | 532 | /* Get the offset of the field */ |
514 | if (dwarf_attr(die_mem, DW_AT_data_member_location, &attr) == NULL || | 533 | if (dwarf_attr(die_mem, DW_AT_data_member_location, &attr) == NULL || |
515 | dwarf_formudata(&attr, &offs) != 0) | 534 | dwarf_formudata(&attr, &offs) != 0) { |
516 | die("Failed to get the offset of %s.", field->name); | 535 | pr_warning("Failed to get the offset of %s.\n", field->name); |
536 | return -ENOENT; | ||
537 | } | ||
517 | ref->offset += (long)offs; | 538 | ref->offset += (long)offs; |
518 | 539 | ||
519 | /* Converting next field */ | 540 | /* Converting next field */ |
520 | if (field->next) | 541 | if (field->next) |
521 | convert_variable_fields(die_mem, field->name, field->next, | 542 | return convert_variable_fields(die_mem, field->name, |
522 | &ref, die_mem); | 543 | field->next, &ref, die_mem); |
544 | else | ||
545 | return 0; | ||
523 | } | 546 | } |
524 | 547 | ||
525 | /* Show a variables in kprobe event format */ | 548 | /* Show a variables in kprobe event format */ |
526 | static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 549 | static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
527 | { | 550 | { |
528 | Dwarf_Attribute attr; | 551 | Dwarf_Attribute attr; |
529 | Dwarf_Die die_mem; | 552 | Dwarf_Die die_mem; |
@@ -538,28 +561,30 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
538 | if (ret <= 0 || nexpr == 0) | 561 | if (ret <= 0 || nexpr == 0) |
539 | goto error; | 562 | goto error; |
540 | 563 | ||
541 | convert_location(expr, pf); | 564 | ret = convert_location(expr, pf); |
542 | 565 | if (ret == 0 && pf->pvar->field) { | |
543 | if (pf->pvar->field) { | 566 | ret = convert_variable_fields(vr_die, pf->pvar->var, |
544 | convert_variable_fields(vr_die, pf->pvar->var, | 567 | pf->pvar->field, &pf->tvar->ref, |
545 | pf->pvar->field, &pf->tvar->ref, | 568 | &die_mem); |
546 | &die_mem); | ||
547 | vr_die = &die_mem; | 569 | vr_die = &die_mem; |
548 | } | 570 | } |
549 | if (pf->pvar->type) | 571 | if (ret == 0) { |
550 | pf->tvar->type = xstrdup(pf->pvar->type); | 572 | if (pf->pvar->type) |
551 | else | 573 | pf->tvar->type = xstrdup(pf->pvar->type); |
552 | convert_variable_type(vr_die, pf->tvar); | 574 | else |
575 | ret = convert_variable_type(vr_die, pf->tvar); | ||
576 | } | ||
553 | /* *expr will be cached in libdw. Don't free it. */ | 577 | /* *expr will be cached in libdw. Don't free it. */ |
554 | return ; | 578 | return ret; |
555 | error: | 579 | error: |
556 | /* TODO: Support const_value */ | 580 | /* TODO: Support const_value */ |
557 | die("Failed to find the location of %s at this address.\n" | 581 | pr_err("Failed to find the location of %s at this address.\n" |
558 | " Perhaps, it has been optimized out.", pf->pvar->var); | 582 | " Perhaps, it has been optimized out.\n", pf->pvar->var); |
583 | return -ENOENT; | ||
559 | } | 584 | } |
560 | 585 | ||
561 | /* Find a variable in a subprogram die */ | 586 | /* Find a variable in a subprogram die */ |
562 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 587 | static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
563 | { | 588 | { |
564 | Dwarf_Die vr_die; | 589 | Dwarf_Die vr_die; |
565 | char buf[32], *ptr; | 590 | char buf[32], *ptr; |
@@ -578,19 +603,22 @@ static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
578 | if (!is_c_varname(pf->pvar->var)) { | 603 | if (!is_c_varname(pf->pvar->var)) { |
579 | /* Copy raw parameters */ | 604 | /* Copy raw parameters */ |
580 | pf->tvar->value = xstrdup(pf->pvar->var); | 605 | pf->tvar->value = xstrdup(pf->pvar->var); |
581 | } else { | 606 | return 0; |
582 | pr_debug("Searching '%s' variable in context.\n", | ||
583 | pf->pvar->var); | ||
584 | /* Search child die for local variables and parameters. */ | ||
585 | if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) | ||
586 | die("Failed to find '%s' in this function.", | ||
587 | pf->pvar->var); | ||
588 | convert_variable(&vr_die, pf); | ||
589 | } | 607 | } |
608 | |||
609 | pr_debug("Searching '%s' variable in context.\n", | ||
610 | pf->pvar->var); | ||
611 | /* Search child die for local variables and parameters. */ | ||
612 | if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { | ||
613 | pr_warning("Failed to find '%s' in this function.\n", | ||
614 | pf->pvar->var); | ||
615 | return -ENOENT; | ||
616 | } | ||
617 | return convert_variable(&vr_die, pf); | ||
590 | } | 618 | } |
591 | 619 | ||
592 | /* Show a probe point to output buffer */ | 620 | /* Show a probe point to output buffer */ |
593 | static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | 621 | static int convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) |
594 | { | 622 | { |
595 | struct kprobe_trace_event *tev; | 623 | struct kprobe_trace_event *tev; |
596 | Dwarf_Addr eaddr; | 624 | Dwarf_Addr eaddr; |
@@ -600,22 +628,31 @@ static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
600 | Dwarf_Attribute fb_attr; | 628 | Dwarf_Attribute fb_attr; |
601 | size_t nops; | 629 | size_t nops; |
602 | 630 | ||
603 | if (pf->ntevs == MAX_PROBES) | 631 | if (pf->ntevs == MAX_PROBES) { |
604 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | 632 | pr_warning("Too many( > %d) probe point found.\n", MAX_PROBES); |
633 | return -ERANGE; | ||
634 | } | ||
605 | tev = &pf->tevs[pf->ntevs++]; | 635 | tev = &pf->tevs[pf->ntevs++]; |
606 | 636 | ||
607 | /* If no real subprogram, find a real one */ | 637 | /* If no real subprogram, find a real one */ |
608 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 638 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { |
609 | sp_die = die_find_real_subprogram(&pf->cu_die, | 639 | sp_die = die_find_real_subprogram(&pf->cu_die, |
610 | pf->addr, &die_mem); | 640 | pf->addr, &die_mem); |
611 | if (!sp_die) | 641 | if (!sp_die) { |
612 | die("Probe point is not found in subprograms."); | 642 | pr_warning("Failed to find probe point in any " |
643 | "functions.\n"); | ||
644 | return -ENOENT; | ||
645 | } | ||
613 | } | 646 | } |
614 | 647 | ||
615 | /* Copy the name of probe point */ | 648 | /* Copy the name of probe point */ |
616 | name = dwarf_diename(sp_die); | 649 | name = dwarf_diename(sp_die); |
617 | if (name) { | 650 | if (name) { |
618 | dwarf_entrypc(sp_die, &eaddr); | 651 | if (dwarf_entrypc(sp_die, &eaddr) != 0) { |
652 | pr_warning("Failed to get entry pc of %s\n", | ||
653 | dwarf_diename(sp_die)); | ||
654 | return -ENOENT; | ||
655 | } | ||
619 | tev->point.symbol = xstrdup(name); | 656 | tev->point.symbol = xstrdup(name); |
620 | tev->point.offset = (unsigned long)(pf->addr - eaddr); | 657 | tev->point.offset = (unsigned long)(pf->addr - eaddr); |
621 | } else | 658 | } else |
@@ -633,9 +670,12 @@ static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
633 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && | 670 | } else if (nops == 1 && pf->fb_ops[0].atom == DW_OP_call_frame_cfa && |
634 | pf->cfi != NULL) { | 671 | pf->cfi != NULL) { |
635 | Dwarf_Frame *frame; | 672 | Dwarf_Frame *frame; |
636 | ret = dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame); | 673 | if (dwarf_cfi_addrframe(pf->cfi, pf->addr, &frame) != 0 || |
637 | DIE_IF(ret != 0); | 674 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops) != 0) { |
638 | dwarf_frame_cfa(frame, &pf->fb_ops, &nops); | 675 | pr_warning("Failed to get CFA on 0x%jx\n", |
676 | (uintmax_t)pf->addr); | ||
677 | return -ENOENT; | ||
678 | } | ||
639 | } | 679 | } |
640 | 680 | ||
641 | /* Find each argument */ | 681 | /* Find each argument */ |
@@ -644,45 +684,53 @@ static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
644 | for (i = 0; i < pf->pev->nargs; i++) { | 684 | for (i = 0; i < pf->pev->nargs; i++) { |
645 | pf->pvar = &pf->pev->args[i]; | 685 | pf->pvar = &pf->pev->args[i]; |
646 | pf->tvar = &tev->args[i]; | 686 | pf->tvar = &tev->args[i]; |
647 | find_variable(sp_die, pf); | 687 | ret = find_variable(sp_die, pf); |
688 | if (ret != 0) | ||
689 | return ret; | ||
648 | } | 690 | } |
649 | 691 | ||
650 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 692 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
651 | pf->fb_ops = NULL; | 693 | pf->fb_ops = NULL; |
694 | return 0; | ||
652 | } | 695 | } |
653 | 696 | ||
654 | /* Find probe point from its line number */ | 697 | /* Find probe point from its line number */ |
655 | static void find_probe_point_by_line(struct probe_finder *pf) | 698 | static int find_probe_point_by_line(struct probe_finder *pf) |
656 | { | 699 | { |
657 | Dwarf_Lines *lines; | 700 | Dwarf_Lines *lines; |
658 | Dwarf_Line *line; | 701 | Dwarf_Line *line; |
659 | size_t nlines, i; | 702 | size_t nlines, i; |
660 | Dwarf_Addr addr; | 703 | Dwarf_Addr addr; |
661 | int lineno; | 704 | int lineno; |
662 | int ret; | 705 | int ret = 0; |
663 | 706 | ||
664 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); | 707 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
665 | DIE_IF(ret != 0); | 708 | pr_warning("No source lines found in this CU.\n"); |
709 | return -ENOENT; | ||
710 | } | ||
666 | 711 | ||
667 | for (i = 0; i < nlines; i++) { | 712 | for (i = 0; i < nlines && ret == 0; i++) { |
668 | line = dwarf_onesrcline(lines, i); | 713 | line = dwarf_onesrcline(lines, i); |
669 | dwarf_lineno(line, &lineno); | 714 | if (dwarf_lineno(line, &lineno) != 0 || |
670 | if (lineno != pf->lno) | 715 | lineno != pf->lno) |
671 | continue; | 716 | continue; |
672 | 717 | ||
673 | /* TODO: Get fileno from line, but how? */ | 718 | /* TODO: Get fileno from line, but how? */ |
674 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 719 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
675 | continue; | 720 | continue; |
676 | 721 | ||
677 | ret = dwarf_lineaddr(line, &addr); | 722 | if (dwarf_lineaddr(line, &addr) != 0) { |
678 | DIE_IF(ret != 0); | 723 | pr_warning("Failed to get the address of the line.\n"); |
724 | return -ENOENT; | ||
725 | } | ||
679 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", | 726 | pr_debug("Probe line found: line[%d]:%d addr:0x%jx\n", |
680 | (int)i, lineno, (uintmax_t)addr); | 727 | (int)i, lineno, (uintmax_t)addr); |
681 | pf->addr = addr; | 728 | pf->addr = addr; |
682 | 729 | ||
683 | convert_probe_point(NULL, pf); | 730 | ret = convert_probe_point(NULL, pf); |
684 | /* Continuing, because target line might be inlined. */ | 731 | /* Continuing, because target line might be inlined. */ |
685 | } | 732 | } |
733 | return ret; | ||
686 | } | 734 | } |
687 | 735 | ||
688 | /* Find lines which match lazy pattern */ | 736 | /* Find lines which match lazy pattern */ |
@@ -690,15 +738,27 @@ static int find_lazy_match_lines(struct list_head *head, | |||
690 | const char *fname, const char *pat) | 738 | const char *fname, const char *pat) |
691 | { | 739 | { |
692 | char *fbuf, *p1, *p2; | 740 | char *fbuf, *p1, *p2; |
693 | int fd, line, nlines = 0; | 741 | int fd, ret, line, nlines = 0; |
694 | struct stat st; | 742 | struct stat st; |
695 | 743 | ||
696 | fd = open(fname, O_RDONLY); | 744 | fd = open(fname, O_RDONLY); |
697 | if (fd < 0) | 745 | if (fd < 0) { |
698 | die("failed to open %s", fname); | 746 | pr_warning("Failed to open %s: %s\n", fname, strerror(-fd)); |
699 | DIE_IF(fstat(fd, &st) < 0); | 747 | return fd; |
748 | } | ||
749 | |||
750 | ret = fstat(fd, &st); | ||
751 | if (ret < 0) { | ||
752 | pr_warning("Failed to get the size of %s: %s\n", | ||
753 | fname, strerror(errno)); | ||
754 | return ret; | ||
755 | } | ||
700 | fbuf = xmalloc(st.st_size + 2); | 756 | fbuf = xmalloc(st.st_size + 2); |
701 | DIE_IF(read(fd, fbuf, st.st_size) < 0); | 757 | ret = read(fd, fbuf, st.st_size); |
758 | if (ret < 0) { | ||
759 | pr_warning("Failed to read %s: %s\n", fname, strerror(errno)); | ||
760 | return ret; | ||
761 | } | ||
702 | close(fd); | 762 | close(fd); |
703 | fbuf[st.st_size] = '\n'; /* Dummy line */ | 763 | fbuf[st.st_size] = '\n'; /* Dummy line */ |
704 | fbuf[st.st_size + 1] = '\0'; | 764 | fbuf[st.st_size + 1] = '\0'; |
@@ -718,7 +778,7 @@ static int find_lazy_match_lines(struct list_head *head, | |||
718 | } | 778 | } |
719 | 779 | ||
720 | /* Find probe points from lazy pattern */ | 780 | /* Find probe points from lazy pattern */ |
721 | static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | 781 | static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) |
722 | { | 782 | { |
723 | Dwarf_Lines *lines; | 783 | Dwarf_Lines *lines; |
724 | Dwarf_Line *line; | 784 | Dwarf_Line *line; |
@@ -726,31 +786,40 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
726 | Dwarf_Addr addr; | 786 | Dwarf_Addr addr; |
727 | Dwarf_Die die_mem; | 787 | Dwarf_Die die_mem; |
728 | int lineno; | 788 | int lineno; |
729 | int ret; | 789 | int ret = 0; |
730 | 790 | ||
731 | if (list_empty(&pf->lcache)) { | 791 | if (list_empty(&pf->lcache)) { |
732 | /* Matching lazy line pattern */ | 792 | /* Matching lazy line pattern */ |
733 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 793 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
734 | pf->pev->point.lazy_line); | 794 | pf->pev->point.lazy_line); |
735 | if (ret <= 0) | 795 | if (ret == 0) { |
736 | die("No matched lines found in %s.", pf->fname); | 796 | pr_debug("No matched lines found in %s.\n", pf->fname); |
797 | return 0; | ||
798 | } else if (ret < 0) | ||
799 | return ret; | ||
737 | } | 800 | } |
738 | 801 | ||
739 | ret = dwarf_getsrclines(&pf->cu_die, &lines, &nlines); | 802 | if (dwarf_getsrclines(&pf->cu_die, &lines, &nlines) != 0) { |
740 | DIE_IF(ret != 0); | 803 | pr_warning("No source lines found in this CU.\n"); |
741 | for (i = 0; i < nlines; i++) { | 804 | return -ENOENT; |
805 | } | ||
806 | |||
807 | for (i = 0; i < nlines && ret >= 0; i++) { | ||
742 | line = dwarf_onesrcline(lines, i); | 808 | line = dwarf_onesrcline(lines, i); |
743 | 809 | ||
744 | dwarf_lineno(line, &lineno); | 810 | if (dwarf_lineno(line, &lineno) != 0 || |
745 | if (!line_list__has_line(&pf->lcache, lineno)) | 811 | !line_list__has_line(&pf->lcache, lineno)) |
746 | continue; | 812 | continue; |
747 | 813 | ||
748 | /* TODO: Get fileno from line, but how? */ | 814 | /* TODO: Get fileno from line, but how? */ |
749 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) | 815 | if (strtailcmp(dwarf_linesrc(line, NULL, NULL), pf->fname) != 0) |
750 | continue; | 816 | continue; |
751 | 817 | ||
752 | ret = dwarf_lineaddr(line, &addr); | 818 | if (dwarf_lineaddr(line, &addr) != 0) { |
753 | DIE_IF(ret != 0); | 819 | pr_debug("Failed to get the address of line %d.\n", |
820 | lineno); | ||
821 | continue; | ||
822 | } | ||
754 | if (sp_die) { | 823 | if (sp_die) { |
755 | /* Address filtering 1: does sp_die include addr? */ | 824 | /* Address filtering 1: does sp_die include addr? */ |
756 | if (!dwarf_haspc(sp_die, addr)) | 825 | if (!dwarf_haspc(sp_die, addr)) |
@@ -764,27 +833,42 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
764 | (int)i, lineno, (unsigned long long)addr); | 833 | (int)i, lineno, (unsigned long long)addr); |
765 | pf->addr = addr; | 834 | pf->addr = addr; |
766 | 835 | ||
767 | convert_probe_point(sp_die, pf); | 836 | ret = convert_probe_point(sp_die, pf); |
768 | /* Continuing, because target line might be inlined. */ | 837 | /* Continuing, because target line might be inlined. */ |
769 | } | 838 | } |
770 | /* TODO: deallocate lines, but how? */ | 839 | /* TODO: deallocate lines, but how? */ |
840 | return ret; | ||
771 | } | 841 | } |
772 | 842 | ||
843 | /* Callback parameter with return value */ | ||
844 | struct dwarf_callback_param { | ||
845 | void *data; | ||
846 | int retval; | ||
847 | }; | ||
848 | |||
773 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 849 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
774 | { | 850 | { |
775 | struct probe_finder *pf = (struct probe_finder *)data; | 851 | struct dwarf_callback_param *param = data; |
852 | struct probe_finder *pf = param->data; | ||
776 | struct perf_probe_point *pp = &pf->pev->point; | 853 | struct perf_probe_point *pp = &pf->pev->point; |
854 | Dwarf_Addr addr; | ||
777 | 855 | ||
778 | if (pp->lazy_line) | 856 | if (pp->lazy_line) |
779 | find_probe_point_lazy(in_die, pf); | 857 | param->retval = find_probe_point_lazy(in_die, pf); |
780 | else { | 858 | else { |
781 | /* Get probe address */ | 859 | /* Get probe address */ |
782 | pf->addr = die_get_entrypc(in_die); | 860 | if (dwarf_entrypc(in_die, &addr) != 0) { |
861 | pr_warning("Failed to get entry pc of %s.\n", | ||
862 | dwarf_diename(in_die)); | ||
863 | param->retval = -ENOENT; | ||
864 | return DWARF_CB_ABORT; | ||
865 | } | ||
866 | pf->addr = addr; | ||
783 | pf->addr += pp->offset; | 867 | pf->addr += pp->offset; |
784 | pr_debug("found inline addr: 0x%jx\n", | 868 | pr_debug("found inline addr: 0x%jx\n", |
785 | (uintmax_t)pf->addr); | 869 | (uintmax_t)pf->addr); |
786 | 870 | ||
787 | convert_probe_point(in_die, pf); | 871 | param->retval = convert_probe_point(in_die, pf); |
788 | } | 872 | } |
789 | 873 | ||
790 | return DWARF_CB_OK; | 874 | return DWARF_CB_OK; |
@@ -793,39 +877,53 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | |||
793 | /* Search function from function name */ | 877 | /* Search function from function name */ |
794 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 878 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
795 | { | 879 | { |
796 | struct probe_finder *pf = (struct probe_finder *)data; | 880 | struct dwarf_callback_param *param = data; |
881 | struct probe_finder *pf = param->data; | ||
797 | struct perf_probe_point *pp = &pf->pev->point; | 882 | struct perf_probe_point *pp = &pf->pev->point; |
798 | 883 | ||
799 | /* Check tag and diename */ | 884 | /* Check tag and diename */ |
800 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 885 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
801 | die_compare_name(sp_die, pp->function) != 0) | 886 | die_compare_name(sp_die, pp->function) != 0) |
802 | return 0; | 887 | return DWARF_CB_OK; |
803 | 888 | ||
804 | pf->fname = dwarf_decl_file(sp_die); | 889 | pf->fname = dwarf_decl_file(sp_die); |
805 | if (pp->line) { /* Function relative line */ | 890 | if (pp->line) { /* Function relative line */ |
806 | dwarf_decl_line(sp_die, &pf->lno); | 891 | dwarf_decl_line(sp_die, &pf->lno); |
807 | pf->lno += pp->line; | 892 | pf->lno += pp->line; |
808 | find_probe_point_by_line(pf); | 893 | param->retval = find_probe_point_by_line(pf); |
809 | } else if (!dwarf_func_inline(sp_die)) { | 894 | } else if (!dwarf_func_inline(sp_die)) { |
810 | /* Real function */ | 895 | /* Real function */ |
811 | if (pp->lazy_line) | 896 | if (pp->lazy_line) |
812 | find_probe_point_lazy(sp_die, pf); | 897 | param->retval = find_probe_point_lazy(sp_die, pf); |
813 | else { | 898 | else { |
814 | pf->addr = die_get_entrypc(sp_die); | 899 | if (dwarf_entrypc(sp_die, &pf->addr) != 0) { |
900 | pr_warning("Failed to get entry pc of %s.\n", | ||
901 | dwarf_diename(sp_die)); | ||
902 | param->retval = -ENOENT; | ||
903 | return DWARF_CB_ABORT; | ||
904 | } | ||
815 | pf->addr += pp->offset; | 905 | pf->addr += pp->offset; |
816 | /* TODO: Check the address in this function */ | 906 | /* TODO: Check the address in this function */ |
817 | convert_probe_point(sp_die, pf); | 907 | param->retval = convert_probe_point(sp_die, pf); |
818 | } | 908 | } |
819 | } else | 909 | } else { |
910 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
911 | .retval = 0}; | ||
820 | /* Inlined function: search instances */ | 912 | /* Inlined function: search instances */ |
821 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, pf); | 913 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, |
914 | &_param); | ||
915 | param->retval = _param.retval; | ||
916 | } | ||
822 | 917 | ||
823 | return 1; /* Exit; no same symbol in this CU. */ | 918 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
824 | } | 919 | } |
825 | 920 | ||
826 | static void find_probe_point_by_func(struct probe_finder *pf) | 921 | static int find_probe_point_by_func(struct probe_finder *pf) |
827 | { | 922 | { |
828 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); | 923 | struct dwarf_callback_param _param = {.data = (void *)pf, |
924 | .retval = 0}; | ||
925 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0); | ||
926 | return _param.retval; | ||
829 | } | 927 | } |
830 | 928 | ||
831 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ | 929 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ |
@@ -838,14 +936,18 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
838 | size_t cuhl; | 936 | size_t cuhl; |
839 | Dwarf_Die *diep; | 937 | Dwarf_Die *diep; |
840 | Dwarf *dbg; | 938 | Dwarf *dbg; |
939 | int ret = 0; | ||
841 | 940 | ||
842 | pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); | 941 | pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); |
843 | *tevs = pf.tevs; | 942 | *tevs = pf.tevs; |
844 | pf.ntevs = 0; | 943 | pf.ntevs = 0; |
845 | 944 | ||
846 | dbg = dwarf_begin(fd, DWARF_C_READ); | 945 | dbg = dwarf_begin(fd, DWARF_C_READ); |
847 | if (!dbg) | 946 | if (!dbg) { |
848 | return -ENOENT; | 947 | pr_warning("No dwarf info found in the vmlinux - " |
948 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
949 | return -EBADF; | ||
950 | } | ||
849 | 951 | ||
850 | /* Get the call frame information from this dwarf */ | 952 | /* Get the call frame information from this dwarf */ |
851 | pf.cfi = dwarf_getcfi(dbg); | 953 | pf.cfi = dwarf_getcfi(dbg); |
@@ -853,7 +955,8 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
853 | off = 0; | 955 | off = 0; |
854 | line_list__init(&pf.lcache); | 956 | line_list__init(&pf.lcache); |
855 | /* Loop on CUs (Compilation Unit) */ | 957 | /* Loop on CUs (Compilation Unit) */ |
856 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL)) { | 958 | while (!dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) && |
959 | ret >= 0) { | ||
857 | /* Get the DIE(Debugging Information Entry) of this CU */ | 960 | /* Get the DIE(Debugging Information Entry) of this CU */ |
858 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); | 961 | diep = dwarf_offdie(dbg, off + cuhl, &pf.cu_die); |
859 | if (!diep) | 962 | if (!diep) |
@@ -867,12 +970,12 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
867 | 970 | ||
868 | if (!pp->file || pf.fname) { | 971 | if (!pp->file || pf.fname) { |
869 | if (pp->function) | 972 | if (pp->function) |
870 | find_probe_point_by_func(&pf); | 973 | ret = find_probe_point_by_func(&pf); |
871 | else if (pp->lazy_line) | 974 | else if (pp->lazy_line) |
872 | find_probe_point_lazy(NULL, &pf); | 975 | ret = find_probe_point_lazy(NULL, &pf); |
873 | else { | 976 | else { |
874 | pf.lno = pp->line; | 977 | pf.lno = pp->line; |
875 | find_probe_point_by_line(&pf); | 978 | ret = find_probe_point_by_line(&pf); |
876 | } | 979 | } |
877 | } | 980 | } |
878 | off = noff; | 981 | off = noff; |
@@ -880,7 +983,7 @@ int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | |||
880 | line_list__free(&pf.lcache); | 983 | line_list__free(&pf.lcache); |
881 | dwarf_end(dbg); | 984 | dwarf_end(dbg); |
882 | 985 | ||
883 | return pf.ntevs; | 986 | return (ret < 0) ? ret : pf.ntevs; |
884 | } | 987 | } |
885 | 988 | ||
886 | /* Reverse search */ | 989 | /* Reverse search */ |
@@ -893,10 +996,11 @@ int find_perf_probe_point(int fd, unsigned long addr, | |||
893 | Dwarf_Addr laddr, eaddr; | 996 | Dwarf_Addr laddr, eaddr; |
894 | const char *tmp; | 997 | const char *tmp; |
895 | int lineno, ret = 0; | 998 | int lineno, ret = 0; |
999 | bool found = false; | ||
896 | 1000 | ||
897 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1001 | dbg = dwarf_begin(fd, DWARF_C_READ); |
898 | if (!dbg) | 1002 | if (!dbg) |
899 | return -ENOENT; | 1003 | return -EBADF; |
900 | 1004 | ||
901 | /* Find cu die */ | 1005 | /* Find cu die */ |
902 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { | 1006 | if (!dwarf_addrdie(dbg, (Dwarf_Addr)addr, &cudie)) { |
@@ -907,82 +1011,87 @@ int find_perf_probe_point(int fd, unsigned long addr, | |||
907 | /* Find a corresponding line */ | 1011 | /* Find a corresponding line */ |
908 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); | 1012 | line = dwarf_getsrc_die(&cudie, (Dwarf_Addr)addr); |
909 | if (line) { | 1013 | if (line) { |
910 | dwarf_lineaddr(line, &laddr); | 1014 | if (dwarf_lineaddr(line, &laddr) == 0 && |
911 | if ((Dwarf_Addr)addr == laddr) { | 1015 | (Dwarf_Addr)addr == laddr && |
912 | dwarf_lineno(line, &lineno); | 1016 | dwarf_lineno(line, &lineno) == 0) { |
913 | ppt->line = lineno; | ||
914 | |||
915 | tmp = dwarf_linesrc(line, NULL, NULL); | 1017 | tmp = dwarf_linesrc(line, NULL, NULL); |
916 | DIE_IF(!tmp); | 1018 | if (tmp) { |
917 | ppt->file = xstrdup(tmp); | 1019 | ppt->line = lineno; |
918 | ret = 1; | 1020 | ppt->file = xstrdup(tmp); |
1021 | found = true; | ||
1022 | } | ||
919 | } | 1023 | } |
920 | } | 1024 | } |
921 | 1025 | ||
922 | /* Find a corresponding function */ | 1026 | /* Find a corresponding function */ |
923 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { | 1027 | if (die_find_real_subprogram(&cudie, (Dwarf_Addr)addr, &spdie)) { |
924 | tmp = dwarf_diename(&spdie); | 1028 | tmp = dwarf_diename(&spdie); |
925 | if (!tmp) | 1029 | if (!tmp || dwarf_entrypc(&spdie, &eaddr) != 0) |
926 | goto end; | 1030 | goto end; |
927 | 1031 | ||
928 | dwarf_entrypc(&spdie, &eaddr); | 1032 | if (ppt->line) { |
929 | if (!lineno) { | 1033 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, |
930 | /* We don't have a line number, let's use offset */ | 1034 | &indie)) { |
931 | ppt->function = xstrdup(tmp); | 1035 | /* addr in an inline function */ |
932 | ppt->offset = addr - (unsigned long)eaddr; | 1036 | tmp = dwarf_diename(&indie); |
933 | ret = 1; | 1037 | if (!tmp) |
934 | goto end; | 1038 | goto end; |
935 | } | 1039 | ret = dwarf_decl_line(&indie, &lineno); |
936 | if (die_find_inlinefunc(&spdie, (Dwarf_Addr)addr, &indie)) { | 1040 | } else { |
937 | /* addr in an inline function */ | 1041 | if (eaddr == addr) { /* Function entry */ |
938 | tmp = dwarf_diename(&indie); | 1042 | lineno = ppt->line; |
939 | if (!tmp) | 1043 | ret = 0; |
940 | goto end; | 1044 | } else |
941 | dwarf_decl_line(&indie, &lineno); | 1045 | ret = dwarf_decl_line(&spdie, &lineno); |
942 | } else { | 1046 | } |
943 | if (eaddr == addr) /* No offset: function entry */ | 1047 | if (ret == 0) { |
944 | lineno = ppt->line; | 1048 | /* Make a relative line number */ |
945 | else | 1049 | ppt->line -= lineno; |
946 | dwarf_decl_line(&spdie, &lineno); | 1050 | goto found; |
1051 | } | ||
947 | } | 1052 | } |
1053 | /* We don't have a line number, let's use offset */ | ||
1054 | ppt->offset = addr - (unsigned long)eaddr; | ||
1055 | found: | ||
948 | ppt->function = xstrdup(tmp); | 1056 | ppt->function = xstrdup(tmp); |
949 | ppt->line -= lineno; /* Make a relative line number */ | 1057 | found = true; |
950 | } | 1058 | } |
951 | 1059 | ||
952 | end: | 1060 | end: |
953 | dwarf_end(dbg); | 1061 | dwarf_end(dbg); |
1062 | if (ret >= 0) | ||
1063 | ret = found ? 1 : 0; | ||
954 | return ret; | 1064 | return ret; |
955 | } | 1065 | } |
956 | 1066 | ||
957 | 1067 | ||
958 | /* Find line range from its line number */ | 1068 | /* Find line range from its line number */ |
959 | static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | 1069 | static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) |
960 | { | 1070 | { |
961 | Dwarf_Lines *lines; | 1071 | Dwarf_Lines *lines; |
962 | Dwarf_Line *line; | 1072 | Dwarf_Line *line; |
963 | size_t nlines, i; | 1073 | size_t nlines, i; |
964 | Dwarf_Addr addr; | 1074 | Dwarf_Addr addr; |
965 | int lineno; | 1075 | int lineno; |
966 | int ret; | ||
967 | const char *src; | 1076 | const char *src; |
968 | Dwarf_Die die_mem; | 1077 | Dwarf_Die die_mem; |
969 | 1078 | ||
970 | line_list__init(&lf->lr->line_list); | 1079 | line_list__init(&lf->lr->line_list); |
971 | ret = dwarf_getsrclines(&lf->cu_die, &lines, &nlines); | 1080 | if (dwarf_getsrclines(&lf->cu_die, &lines, &nlines) != 0) { |
972 | DIE_IF(ret != 0); | 1081 | pr_warning("No source lines found in this CU.\n"); |
1082 | return -ENOENT; | ||
1083 | } | ||
973 | 1084 | ||
974 | for (i = 0; i < nlines; i++) { | 1085 | for (i = 0; i < nlines; i++) { |
975 | line = dwarf_onesrcline(lines, i); | 1086 | line = dwarf_onesrcline(lines, i); |
976 | ret = dwarf_lineno(line, &lineno); | 1087 | if (dwarf_lineno(line, &lineno) != 0 || |
977 | DIE_IF(ret != 0); | 1088 | (lf->lno_s > lineno || lf->lno_e < lineno)) |
978 | if (lf->lno_s > lineno || lf->lno_e < lineno) | ||
979 | continue; | 1089 | continue; |
980 | 1090 | ||
981 | if (sp_die) { | 1091 | if (sp_die) { |
982 | /* Address filtering 1: does sp_die include addr? */ | 1092 | /* Address filtering 1: does sp_die include addr? */ |
983 | ret = dwarf_lineaddr(line, &addr); | 1093 | if (dwarf_lineaddr(line, &addr) != 0 || |
984 | DIE_IF(ret != 0); | 1094 | !dwarf_haspc(sp_die, addr)) |
985 | if (!dwarf_haspc(sp_die, addr)) | ||
986 | continue; | 1095 | continue; |
987 | 1096 | ||
988 | /* Address filtering 2: No child include addr? */ | 1097 | /* Address filtering 2: No child include addr? */ |
@@ -1007,18 +1116,22 @@ static void find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
1007 | free(lf->lr->path); | 1116 | free(lf->lr->path); |
1008 | lf->lr->path = NULL; | 1117 | lf->lr->path = NULL; |
1009 | } | 1118 | } |
1119 | return lf->found; | ||
1010 | } | 1120 | } |
1011 | 1121 | ||
1012 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1122 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
1013 | { | 1123 | { |
1014 | find_line_range_by_line(in_die, (struct line_finder *)data); | 1124 | struct dwarf_callback_param *param = data; |
1125 | |||
1126 | param->retval = find_line_range_by_line(in_die, param->data); | ||
1015 | return DWARF_CB_ABORT; /* No need to find other instances */ | 1127 | return DWARF_CB_ABORT; /* No need to find other instances */ |
1016 | } | 1128 | } |
1017 | 1129 | ||
1018 | /* Search function from function name */ | 1130 | /* Search function from function name */ |
1019 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | 1131 | static int line_range_search_cb(Dwarf_Die *sp_die, void *data) |
1020 | { | 1132 | { |
1021 | struct line_finder *lf = (struct line_finder *)data; | 1133 | struct dwarf_callback_param *param = data; |
1134 | struct line_finder *lf = param->data; | ||
1022 | struct line_range *lr = lf->lr; | 1135 | struct line_range *lr = lf->lr; |
1023 | 1136 | ||
1024 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && | 1137 | if (dwarf_tag(sp_die) == DW_TAG_subprogram && |
@@ -1033,38 +1146,47 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
1033 | lf->lno_e = lr->offset + lr->end; | 1146 | lf->lno_e = lr->offset + lr->end; |
1034 | lr->start = lf->lno_s; | 1147 | lr->start = lf->lno_s; |
1035 | lr->end = lf->lno_e; | 1148 | lr->end = lf->lno_e; |
1036 | if (dwarf_func_inline(sp_die)) | 1149 | if (dwarf_func_inline(sp_die)) { |
1150 | struct dwarf_callback_param _param; | ||
1151 | _param.data = (void *)lf; | ||
1152 | _param.retval = 0; | ||
1037 | dwarf_func_inline_instances(sp_die, | 1153 | dwarf_func_inline_instances(sp_die, |
1038 | line_range_inline_cb, lf); | 1154 | line_range_inline_cb, |
1039 | else | 1155 | &_param); |
1040 | find_line_range_by_line(sp_die, lf); | 1156 | param->retval = _param.retval; |
1041 | return 1; | 1157 | } else |
1158 | param->retval = find_line_range_by_line(sp_die, lf); | ||
1159 | return DWARF_CB_ABORT; | ||
1042 | } | 1160 | } |
1043 | return 0; | 1161 | return DWARF_CB_OK; |
1044 | } | 1162 | } |
1045 | 1163 | ||
1046 | static void find_line_range_by_func(struct line_finder *lf) | 1164 | static int find_line_range_by_func(struct line_finder *lf) |
1047 | { | 1165 | { |
1048 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, lf, 0); | 1166 | struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0}; |
1167 | dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0); | ||
1168 | return param.retval; | ||
1049 | } | 1169 | } |
1050 | 1170 | ||
1051 | int find_line_range(int fd, struct line_range *lr) | 1171 | int find_line_range(int fd, struct line_range *lr) |
1052 | { | 1172 | { |
1053 | struct line_finder lf = {.lr = lr, .found = 0}; | 1173 | struct line_finder lf = {.lr = lr, .found = 0}; |
1054 | int ret; | 1174 | int ret = 0; |
1055 | Dwarf_Off off = 0, noff; | 1175 | Dwarf_Off off = 0, noff; |
1056 | size_t cuhl; | 1176 | size_t cuhl; |
1057 | Dwarf_Die *diep; | 1177 | Dwarf_Die *diep; |
1058 | Dwarf *dbg; | 1178 | Dwarf *dbg; |
1059 | 1179 | ||
1060 | dbg = dwarf_begin(fd, DWARF_C_READ); | 1180 | dbg = dwarf_begin(fd, DWARF_C_READ); |
1061 | if (!dbg) | 1181 | if (!dbg) { |
1062 | return -ENOENT; | 1182 | pr_warning("No dwarf info found in the vmlinux - " |
1183 | "please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
1184 | return -EBADF; | ||
1185 | } | ||
1063 | 1186 | ||
1064 | /* Loop on CUs (Compilation Unit) */ | 1187 | /* Loop on CUs (Compilation Unit) */ |
1065 | while (!lf.found) { | 1188 | while (!lf.found && ret >= 0) { |
1066 | ret = dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL); | 1189 | if (dwarf_nextcu(dbg, off, &noff, &cuhl, NULL, NULL, NULL) != 0) |
1067 | if (ret != 0) | ||
1068 | break; | 1190 | break; |
1069 | 1191 | ||
1070 | /* Get the DIE(Debugging Information Entry) of this CU */ | 1192 | /* Get the DIE(Debugging Information Entry) of this CU */ |
@@ -1080,20 +1202,21 @@ int find_line_range(int fd, struct line_range *lr) | |||
1080 | 1202 | ||
1081 | if (!lr->file || lf.fname) { | 1203 | if (!lr->file || lf.fname) { |
1082 | if (lr->function) | 1204 | if (lr->function) |
1083 | find_line_range_by_func(&lf); | 1205 | ret = find_line_range_by_func(&lf); |
1084 | else { | 1206 | else { |
1085 | lf.lno_s = lr->start; | 1207 | lf.lno_s = lr->start; |
1086 | if (!lr->end) | 1208 | if (!lr->end) |
1087 | lf.lno_e = INT_MAX; | 1209 | lf.lno_e = INT_MAX; |
1088 | else | 1210 | else |
1089 | lf.lno_e = lr->end; | 1211 | lf.lno_e = lr->end; |
1090 | find_line_range_by_line(NULL, &lf); | 1212 | ret = find_line_range_by_line(NULL, &lf); |
1091 | } | 1213 | } |
1092 | } | 1214 | } |
1093 | off = noff; | 1215 | off = noff; |
1094 | } | 1216 | } |
1095 | pr_debug("path: %lx\n", (unsigned long)lr->path); | 1217 | pr_debug("path: %lx\n", (unsigned long)lr->path); |
1096 | dwarf_end(dbg); | 1218 | dwarf_end(dbg); |
1097 | return lf.found; | 1219 | |
1220 | return (ret < 0) ? ret : lf.found; | ||
1098 | } | 1221 | } |
1099 | 1222 | ||