aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2010-07-06 03:00:32 -0400
committerIngo Molnar <mingo@elte.hu>2010-07-06 03:00:32 -0400
commit8bd0e1be25c43a9fbd33a8de06449088879d527a (patch)
tree8f24493dfd45df467faa69e2ecef67b8321932ef /tools/perf
parent39ef13a4ac28aa64cfe1bc36e6e00f1096707a28 (diff)
parentb7dcb857cc3eb89136111fefe89780129c1af1d7 (diff)
Merge branch 'perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux-2.6 into perf/core
Diffstat (limited to 'tools/perf')
-rw-r--r--tools/perf/Documentation/perf-probe.txt4
-rw-r--r--tools/perf/Makefile48
-rw-r--r--tools/perf/util/probe-event.c71
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c192
5 files changed, 230 insertions, 86 deletions
diff --git a/tools/perf/Documentation/perf-probe.txt b/tools/perf/Documentation/perf-probe.txt
index ea531d9d975c..27d52dae5a43 100644
--- a/tools/perf/Documentation/perf-probe.txt
+++ b/tools/perf/Documentation/perf-probe.txt
@@ -94,8 +94,8 @@ Each probe argument follows below syntax.
94 94
95 [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE] 95 [NAME=]LOCALVAR|$retval|%REG|@SYMBOL[:TYPE]
96 96
97'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.) 97'NAME' specifies the name of this argument (optional). You can use the name of local variable, local data structure member (e.g. var->field, var.field2), local array with fixed index (e.g. array[1], var->array[0], var->pointer[2]), or kprobe-tracer argument format (e.g. $retval, %ax, etc). Note that the name of this argument will be set as the last member name if you specify a local data structure member (e.g. field2 for 'var->field1.field2'.)
98'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. 98'TYPE' casts the type of this argument (optional). If omitted, perf probe automatically set the type based on debuginfo. You can specify 'string' type only for the local variable or structure member which is an array of or a pointer to 'char' or 'unsigned char' type.
99 99
100LINE SYNTAX 100LINE SYNTAX
101----------- 101-----------
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index 17a3692397c5..26f626d45a9e 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -605,33 +605,35 @@ endif
605 605
606ifdef NO_DEMANGLE 606ifdef NO_DEMANGLE
607 BASIC_CFLAGS += -DNO_DEMANGLE 607 BASIC_CFLAGS += -DNO_DEMANGLE
608else ifdef HAVE_CPLUS_DEMANGLE
609 EXTLIBS += -liberty
610 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
611else 608else
612 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd 609 ifdef HAVE_CPLUS_DEMANGLE
613 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD)) 610 EXTLIBS += -liberty
614 ifeq ($(has_bfd),y) 611 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
615 EXTLIBS += -lbfd 612 else
616 else 613 FLAGS_BFD=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -lbfd
617 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty 614 has_bfd := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD))
618 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY)) 615 ifeq ($(has_bfd),y)
619 ifeq ($(has_bfd_iberty),y) 616 EXTLIBS += -lbfd
620 EXTLIBS += -lbfd -liberty
621 else 617 else
622 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz 618 FLAGS_BFD_IBERTY=$(FLAGS_BFD) -liberty
623 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z)) 619 has_bfd_iberty := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY))
624 ifeq ($(has_bfd_iberty_z),y) 620 ifeq ($(has_bfd_iberty),y)
625 EXTLIBS += -lbfd -liberty -lz 621 EXTLIBS += -lbfd -liberty
626 else 622 else
627 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty 623 FLAGS_BFD_IBERTY_Z=$(FLAGS_BFD_IBERTY) -lz
628 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE)) 624 has_bfd_iberty_z := $(call try-cc,$(SOURCE_BFD),$(FLAGS_BFD_IBERTY_Z))
629 ifeq ($(has_cplus_demangle),y) 625 ifeq ($(has_bfd_iberty_z),y)
630 EXTLIBS += -liberty 626 EXTLIBS += -lbfd -liberty -lz
631 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
632 else 627 else
633 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling) 628 FLAGS_CPLUS_DEMANGLE=$(ALL_CFLAGS) $(ALL_LDFLAGS) $(EXTLIBS) -liberty
634 BASIC_CFLAGS += -DNO_DEMANGLE 629 has_cplus_demangle := $(call try-cc,$(SOURCE_CPLUS_DEMANGLE),$(FLAGS_CPLUS_DEMANGLE))
630 ifeq ($(has_cplus_demangle),y)
631 EXTLIBS += -liberty
632 BASIC_CFLAGS += -DHAVE_CPLUS_DEMANGLE
633 else
634 msg := $(warning No bfd.h/libbfd found, install binutils-dev[el]/zlib-static to gain symbol demangling)
635 BASIC_CFLAGS += -DNO_DEMANGLE
636 endif
635 endif 637 endif
636 endif 638 endif
637 endif 639 endif
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 914c67095d96..09cf5465e10a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -557,7 +557,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
557/* Parse perf-probe event argument */ 557/* Parse perf-probe event argument */
558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg) 558static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
559{ 559{
560 char *tmp; 560 char *tmp, *goodname;
561 struct perf_probe_arg_field **fieldp; 561 struct perf_probe_arg_field **fieldp;
562 562
563 pr_debug("parsing arg: %s into ", str); 563 pr_debug("parsing arg: %s into ", str);
@@ -580,7 +580,7 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
580 pr_debug("type:%s ", arg->type); 580 pr_debug("type:%s ", arg->type);
581 } 581 }
582 582
583 tmp = strpbrk(str, "-."); 583 tmp = strpbrk(str, "-.[");
584 if (!is_c_varname(str) || !tmp) { 584 if (!is_c_varname(str) || !tmp) {
585 /* A variable, register, symbol or special value */ 585 /* A variable, register, symbol or special value */
586 arg->var = strdup(str); 586 arg->var = strdup(str);
@@ -590,10 +590,11 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
590 return 0; 590 return 0;
591 } 591 }
592 592
593 /* Structure fields */ 593 /* Structure fields or array element */
594 arg->var = strndup(str, tmp - str); 594 arg->var = strndup(str, tmp - str);
595 if (arg->var == NULL) 595 if (arg->var == NULL)
596 return -ENOMEM; 596 return -ENOMEM;
597 goodname = arg->var;
597 pr_debug("%s, ", arg->var); 598 pr_debug("%s, ", arg->var);
598 fieldp = &arg->field; 599 fieldp = &arg->field;
599 600
@@ -601,22 +602,38 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
601 *fieldp = zalloc(sizeof(struct perf_probe_arg_field)); 602 *fieldp = zalloc(sizeof(struct perf_probe_arg_field));
602 if (*fieldp == NULL) 603 if (*fieldp == NULL)
603 return -ENOMEM; 604 return -ENOMEM;
604 if (*tmp == '.') { 605 if (*tmp == '[') { /* Array */
605 str = tmp + 1; 606 str = tmp;
606 (*fieldp)->ref = false; 607 (*fieldp)->index = strtol(str + 1, &tmp, 0);
607 } else if (tmp[1] == '>') {
608 str = tmp + 2;
609 (*fieldp)->ref = true; 608 (*fieldp)->ref = true;
610 } else { 609 if (*tmp != ']' || tmp == str + 1) {
611 semantic_error("Argument parse error: %s\n", str); 610 semantic_error("Array index must be a"
612 return -EINVAL; 611 " number.\n");
612 return -EINVAL;
613 }
614 tmp++;
615 if (*tmp == '\0')
616 tmp = NULL;
617 } else { /* Structure */
618 if (*tmp == '.') {
619 str = tmp + 1;
620 (*fieldp)->ref = false;
621 } else if (tmp[1] == '>') {
622 str = tmp + 2;
623 (*fieldp)->ref = true;
624 } else {
625 semantic_error("Argument parse error: %s\n",
626 str);
627 return -EINVAL;
628 }
629 tmp = strpbrk(str, "-.[");
613 } 630 }
614
615 tmp = strpbrk(str, "-.");
616 if (tmp) { 631 if (tmp) {
617 (*fieldp)->name = strndup(str, tmp - str); 632 (*fieldp)->name = strndup(str, tmp - str);
618 if ((*fieldp)->name == NULL) 633 if ((*fieldp)->name == NULL)
619 return -ENOMEM; 634 return -ENOMEM;
635 if (*str != '[')
636 goodname = (*fieldp)->name;
620 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref); 637 pr_debug("%s(%d), ", (*fieldp)->name, (*fieldp)->ref);
621 fieldp = &(*fieldp)->next; 638 fieldp = &(*fieldp)->next;
622 } 639 }
@@ -624,11 +641,13 @@ static int parse_perf_probe_arg(char *str, struct perf_probe_arg *arg)
624 (*fieldp)->name = strdup(str); 641 (*fieldp)->name = strdup(str);
625 if ((*fieldp)->name == NULL) 642 if ((*fieldp)->name == NULL)
626 return -ENOMEM; 643 return -ENOMEM;
644 if (*str != '[')
645 goodname = (*fieldp)->name;
627 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref); 646 pr_debug("%s(%d)\n", (*fieldp)->name, (*fieldp)->ref);
628 647
629 /* If no name is specified, set the last field name */ 648 /* If no name is specified, set the last field name (not array index)*/
630 if (!arg->name) { 649 if (!arg->name) {
631 arg->name = strdup((*fieldp)->name); 650 arg->name = strdup(goodname);
632 if (arg->name == NULL) 651 if (arg->name == NULL)
633 return -ENOMEM; 652 return -ENOMEM;
634 } 653 }
@@ -776,8 +795,11 @@ int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len)
776 len -= ret; 795 len -= ret;
777 796
778 while (field) { 797 while (field) {
779 ret = e_snprintf(tmp, len, "%s%s", field->ref ? "->" : ".", 798 if (field->name[0] == '[')
780 field->name); 799 ret = e_snprintf(tmp, len, "%s", field->name);
800 else
801 ret = e_snprintf(tmp, len, "%s%s",
802 field->ref ? "->" : ".", field->name);
781 if (ret <= 0) 803 if (ret <= 0)
782 goto error; 804 goto error;
783 tmp += ret; 805 tmp += ret;
@@ -904,6 +926,7 @@ out:
904static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, 926static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
905 char *buf, size_t buflen) 927 char *buf, size_t buflen)
906{ 928{
929 struct kprobe_trace_arg_ref *ref = arg->ref;
907 int ret, depth = 0; 930 int ret, depth = 0;
908 char *tmp = buf; 931 char *tmp = buf;
909 932
@@ -917,16 +940,24 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
917 buf += ret; 940 buf += ret;
918 buflen -= ret; 941 buflen -= ret;
919 942
943 /* Special case: @XXX */
944 if (arg->value[0] == '@' && arg->ref)
945 ref = ref->next;
946
920 /* Dereferencing arguments */ 947 /* Dereferencing arguments */
921 if (arg->ref) { 948 if (ref) {
922 depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf, 949 depth = __synthesize_kprobe_trace_arg_ref(ref, &buf,
923 &buflen, 1); 950 &buflen, 1);
924 if (depth < 0) 951 if (depth < 0)
925 return depth; 952 return depth;
926 } 953 }
927 954
928 /* Print argument value */ 955 /* Print argument value */
929 ret = e_snprintf(buf, buflen, "%s", arg->value); 956 if (arg->value[0] == '@' && arg->ref)
957 ret = e_snprintf(buf, buflen, "%s%+ld", arg->value,
958 arg->ref->offset);
959 else
960 ret = e_snprintf(buf, buflen, "%s", arg->value);
930 if (ret < 0) 961 if (ret < 0)
931 return ret; 962 return ret;
932 buf += ret; 963 buf += ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index e9db1a214ca4..bc06d3e8bafa 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -50,6 +50,7 @@ struct perf_probe_point {
50struct perf_probe_arg_field { 50struct perf_probe_arg_field {
51 struct perf_probe_arg_field *next; /* Next field */ 51 struct perf_probe_arg_field *next; /* Next field */
52 char *name; /* Name of the field */ 52 char *name; /* Name of the field */
53 long index; /* Array index number */
53 bool ref; /* Referencing flag */ 54 bool ref; /* Referencing flag */
54}; 55};
55 56
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index baf665383498..3e64e1fa1051 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -406,14 +406,50 @@ static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name,
406 * Probe finder related functions 406 * Probe finder related functions
407 */ 407 */
408 408
409static struct kprobe_trace_arg_ref *alloc_trace_arg_ref(long offs)
410{
411 struct kprobe_trace_arg_ref *ref;
412 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
413 if (ref != NULL)
414 ref->offset = offs;
415 return ref;
416}
417
409/* Show a location */ 418/* Show a location */
410static int convert_location(Dwarf_Op *op, struct probe_finder *pf) 419static int convert_variable_location(Dwarf_Die *vr_die, struct probe_finder *pf)
411{ 420{
421 Dwarf_Attribute attr;
422 Dwarf_Op *op;
423 size_t nops;
412 unsigned int regn; 424 unsigned int regn;
413 Dwarf_Word offs = 0; 425 Dwarf_Word offs = 0;
414 bool ref = false; 426 bool ref = false;
415 const char *regs; 427 const char *regs;
416 struct kprobe_trace_arg *tvar = pf->tvar; 428 struct kprobe_trace_arg *tvar = pf->tvar;
429 int ret;
430
431 /* TODO: handle more than 1 exprs */
432 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL ||
433 dwarf_getlocation_addr(&attr, pf->addr, &op, &nops, 1) <= 0 ||
434 nops == 0) {
435 /* TODO: Support const_value */
436 pr_err("Failed to find the location of %s at this address.\n"
437 " Perhaps, it has been optimized out.\n", pf->pvar->var);
438 return -ENOENT;
439 }
440
441 if (op->atom == DW_OP_addr) {
442 /* Static variables on memory (not stack), make @varname */
443 ret = strlen(dwarf_diename(vr_die));
444 tvar->value = zalloc(ret + 2);
445 if (tvar->value == NULL)
446 return -ENOMEM;
447 snprintf(tvar->value, ret + 2, "@%s", dwarf_diename(vr_die));
448 tvar->ref = alloc_trace_arg_ref((long)offs);
449 if (tvar->ref == NULL)
450 return -ENOMEM;
451 return 0;
452 }
417 453
418 /* If this is based on frame buffer, set the offset */ 454 /* If this is based on frame buffer, set the offset */
419 if (op->atom == DW_OP_fbreg) { 455 if (op->atom == DW_OP_fbreg) {
@@ -455,27 +491,72 @@ static int convert_location(Dwarf_Op *op, struct probe_finder *pf)
455 return -ENOMEM; 491 return -ENOMEM;
456 492
457 if (ref) { 493 if (ref) {
458 tvar->ref = zalloc(sizeof(struct kprobe_trace_arg_ref)); 494 tvar->ref = alloc_trace_arg_ref((long)offs);
459 if (tvar->ref == NULL) 495 if (tvar->ref == NULL)
460 return -ENOMEM; 496 return -ENOMEM;
461 tvar->ref->offset = (long)offs;
462 } 497 }
463 return 0; 498 return 0;
464} 499}
465 500
466static int convert_variable_type(Dwarf_Die *vr_die, 501static int convert_variable_type(Dwarf_Die *vr_die,
467 struct kprobe_trace_arg *targ) 502 struct kprobe_trace_arg *tvar,
503 const char *cast)
468{ 504{
505 struct kprobe_trace_arg_ref **ref_ptr = &tvar->ref;
469 Dwarf_Die type; 506 Dwarf_Die type;
470 char buf[16]; 507 char buf[16];
471 int ret; 508 int ret;
472 509
510 /* TODO: check all types */
511 if (cast && strcmp(cast, "string") != 0) {
512 /* Non string type is OK */
513 tvar->type = strdup(cast);
514 return (tvar->type == NULL) ? -ENOMEM : 0;
515 }
516
473 if (die_get_real_type(vr_die, &type) == NULL) { 517 if (die_get_real_type(vr_die, &type) == NULL) {
474 pr_warning("Failed to get a type information of %s.\n", 518 pr_warning("Failed to get a type information of %s.\n",
475 dwarf_diename(vr_die)); 519 dwarf_diename(vr_die));
476 return -ENOENT; 520 return -ENOENT;
477 } 521 }
478 522
523 pr_debug("%s type is %s.\n",
524 dwarf_diename(vr_die), dwarf_diename(&type));
525
526 if (cast && strcmp(cast, "string") == 0) { /* String type */
527 ret = dwarf_tag(&type);
528 if (ret != DW_TAG_pointer_type &&
529 ret != DW_TAG_array_type) {
530 pr_warning("Failed to cast into string: "
531 "%s(%s) is not a pointer nor array.",
532 dwarf_diename(vr_die), dwarf_diename(&type));
533 return -EINVAL;
534 }
535 if (ret == DW_TAG_pointer_type) {
536 if (die_get_real_type(&type, &type) == NULL) {
537 pr_warning("Failed to get a type information.");
538 return -ENOENT;
539 }
540 while (*ref_ptr)
541 ref_ptr = &(*ref_ptr)->next;
542 /* Add new reference with offset +0 */
543 *ref_ptr = zalloc(sizeof(struct kprobe_trace_arg_ref));
544 if (*ref_ptr == NULL) {
545 pr_warning("Out of memory error\n");
546 return -ENOMEM;
547 }
548 }
549 if (die_compare_name(&type, "char") != 0 &&
550 die_compare_name(&type, "unsigned char") != 0) {
551 pr_warning("Failed to cast into string: "
552 "%s is not (unsigned) char *.",
553 dwarf_diename(vr_die));
554 return -EINVAL;
555 }
556 tvar->type = strdup(cast);
557 return (tvar->type == NULL) ? -ENOMEM : 0;
558 }
559
479 ret = die_get_byte_size(&type) * 8; 560 ret = die_get_byte_size(&type) * 8;
480 if (ret) { 561 if (ret) {
481 /* Check the bitwidth */ 562 /* Check the bitwidth */
@@ -495,8 +576,8 @@ static int convert_variable_type(Dwarf_Die *vr_die,
495 strerror(-ret)); 576 strerror(-ret));
496 return ret; 577 return ret;
497 } 578 }
498 targ->type = strdup(buf); 579 tvar->type = strdup(buf);
499 if (targ->type == NULL) 580 if (tvar->type == NULL)
500 return -ENOMEM; 581 return -ENOMEM;
501 } 582 }
502 return 0; 583 return 0;
@@ -510,16 +591,44 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
510 struct kprobe_trace_arg_ref *ref = *ref_ptr; 591 struct kprobe_trace_arg_ref *ref = *ref_ptr;
511 Dwarf_Die type; 592 Dwarf_Die type;
512 Dwarf_Word offs; 593 Dwarf_Word offs;
513 int ret; 594 int ret, tag;
514 595
515 pr_debug("converting %s in %s\n", field->name, varname); 596 pr_debug("converting %s in %s\n", field->name, varname);
516 if (die_get_real_type(vr_die, &type) == NULL) { 597 if (die_get_real_type(vr_die, &type) == NULL) {
517 pr_warning("Failed to get the type of %s.\n", varname); 598 pr_warning("Failed to get the type of %s.\n", varname);
518 return -ENOENT; 599 return -ENOENT;
519 } 600 }
520 601 pr_debug2("Var real type: (%x)\n", (unsigned)dwarf_dieoffset(&type));
521 /* Check the pointer and dereference */ 602 tag = dwarf_tag(&type);
522 if (dwarf_tag(&type) == DW_TAG_pointer_type) { 603
604 if (field->name[0] == '[' &&
605 (tag == DW_TAG_array_type || tag == DW_TAG_pointer_type)) {
606 if (field->next)
607 /* Save original type for next field */
608 memcpy(die_mem, &type, sizeof(*die_mem));
609 /* Get the type of this array */
610 if (die_get_real_type(&type, &type) == NULL) {
611 pr_warning("Failed to get the type of %s.\n", varname);
612 return -ENOENT;
613 }
614 pr_debug2("Array real type: (%x)\n",
615 (unsigned)dwarf_dieoffset(&type));
616 if (tag == DW_TAG_pointer_type) {
617 ref = zalloc(sizeof(struct kprobe_trace_arg_ref));
618 if (ref == NULL)
619 return -ENOMEM;
620 if (*ref_ptr)
621 (*ref_ptr)->next = ref;
622 else
623 *ref_ptr = ref;
624 }
625 ref->offset += die_get_byte_size(&type) * field->index;
626 if (!field->next)
627 /* Save vr_die for converting types */
628 memcpy(die_mem, vr_die, sizeof(*die_mem));
629 goto next;
630 } else if (tag == DW_TAG_pointer_type) {
631 /* Check the pointer and dereference */
523 if (!field->ref) { 632 if (!field->ref) {
524 pr_err("Semantic error: %s must be referred by '->'\n", 633 pr_err("Semantic error: %s must be referred by '->'\n",
525 field->name); 634 field->name);
@@ -545,10 +654,15 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
545 *ref_ptr = ref; 654 *ref_ptr = ref;
546 } else { 655 } else {
547 /* Verify it is a data structure */ 656 /* Verify it is a data structure */
548 if (dwarf_tag(&type) != DW_TAG_structure_type) { 657 if (tag != DW_TAG_structure_type) {
549 pr_warning("%s is not a data structure.\n", varname); 658 pr_warning("%s is not a data structure.\n", varname);
550 return -EINVAL; 659 return -EINVAL;
551 } 660 }
661 if (field->name[0] == '[') {
662 pr_err("Semantic error: %s is not a pointor nor array.",
663 varname);
664 return -EINVAL;
665 }
552 if (field->ref) { 666 if (field->ref) {
553 pr_err("Semantic error: %s must be referred by '.'\n", 667 pr_err("Semantic error: %s must be referred by '.'\n",
554 field->name); 668 field->name);
@@ -575,6 +689,7 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
575 } 689 }
576 ref->offset += (long)offs; 690 ref->offset += (long)offs;
577 691
692next:
578 /* Converting next field */ 693 /* Converting next field */
579 if (field->next) 694 if (field->next)
580 return convert_variable_fields(die_mem, field->name, 695 return convert_variable_fields(die_mem, field->name,
@@ -586,51 +701,32 @@ static int convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
586/* Show a variables in kprobe event format */ 701/* Show a variables in kprobe event format */
587static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 702static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
588{ 703{
589 Dwarf_Attribute attr;
590 Dwarf_Die die_mem; 704 Dwarf_Die die_mem;
591 Dwarf_Op *expr;
592 size_t nexpr;
593 int ret; 705 int ret;
594 706
595 if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) 707 pr_debug("Converting variable %s into trace event.\n",
596 goto error; 708 dwarf_diename(vr_die));
597 /* TODO: handle more than 1 exprs */
598 ret = dwarf_getlocation_addr(&attr, pf->addr, &expr, &nexpr, 1);
599 if (ret <= 0 || nexpr == 0)
600 goto error;
601 709
602 ret = convert_location(expr, pf); 710 ret = convert_variable_location(vr_die, pf);
603 if (ret == 0 && pf->pvar->field) { 711 if (ret == 0 && pf->pvar->field) {
604 ret = convert_variable_fields(vr_die, pf->pvar->var, 712 ret = convert_variable_fields(vr_die, pf->pvar->var,
605 pf->pvar->field, &pf->tvar->ref, 713 pf->pvar->field, &pf->tvar->ref,
606 &die_mem); 714 &die_mem);
607 vr_die = &die_mem; 715 vr_die = &die_mem;
608 } 716 }
609 if (ret == 0) { 717 if (ret == 0)
610 if (pf->pvar->type) { 718 ret = convert_variable_type(vr_die, pf->tvar, pf->pvar->type);
611 pf->tvar->type = strdup(pf->pvar->type);
612 if (pf->tvar->type == NULL)
613 ret = -ENOMEM;
614 } else
615 ret = convert_variable_type(vr_die, pf->tvar);
616 }
617 /* *expr will be cached in libdw. Don't free it. */ 719 /* *expr will be cached in libdw. Don't free it. */
618 return ret; 720 return ret;
619error:
620 /* TODO: Support const_value */
621 pr_err("Failed to find the location of %s at this address.\n"
622 " Perhaps, it has been optimized out.\n", pf->pvar->var);
623 return -ENOENT;
624} 721}
625 722
626/* Find a variable in a subprogram die */ 723/* Find a variable in a subprogram die */
627static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) 724static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
628{ 725{
629 Dwarf_Die vr_die; 726 Dwarf_Die vr_die, *scopes;
630 char buf[32], *ptr; 727 char buf[32], *ptr;
631 int ret; 728 int ret, nscopes;
632 729
633 /* TODO: Support arrays */
634 if (pf->pvar->name) 730 if (pf->pvar->name)
635 pf->tvar->name = strdup(pf->pvar->name); 731 pf->tvar->name = strdup(pf->pvar->name);
636 else { 732 else {
@@ -657,12 +753,26 @@ static int find_variable(Dwarf_Die *sp_die, struct probe_finder *pf)
657 pr_debug("Searching '%s' variable in context.\n", 753 pr_debug("Searching '%s' variable in context.\n",
658 pf->pvar->var); 754 pf->pvar->var);
659 /* Search child die for local variables and parameters. */ 755 /* Search child die for local variables and parameters. */
660 if (!die_find_variable(sp_die, pf->pvar->var, &vr_die)) { 756 if (die_find_variable(sp_die, pf->pvar->var, &vr_die))
757 ret = convert_variable(&vr_die, pf);
758 else {
759 /* Search upper class */
760 nscopes = dwarf_getscopes_die(sp_die, &scopes);
761 if (nscopes > 0) {
762 ret = dwarf_getscopevar(scopes, nscopes, pf->pvar->var,
763 0, NULL, 0, 0, &vr_die);
764 if (ret >= 0)
765 ret = convert_variable(&vr_die, pf);
766 else
767 ret = -ENOENT;
768 free(scopes);
769 } else
770 ret = -ENOENT;
771 }
772 if (ret < 0)
661 pr_warning("Failed to find '%s' in this function.\n", 773 pr_warning("Failed to find '%s' in this function.\n",
662 pf->pvar->var); 774 pf->pvar->var);
663 return -ENOENT; 775 return ret;
664 }
665 return convert_variable(&vr_die, pf);
666} 776}
667 777
668/* Show a probe point to output buffer */ 778/* Show a probe point to output buffer */