aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-04-12 13:17:15 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2010-04-14 16:27:56 -0400
commit4984912eb23113a4007940cd09c8351c0623ea5f (patch)
tree81e725def8479b4f4c7d7114f30df690784864c1
parent93ccae7a2227466a0d071fe52c51319f2f34c365 (diff)
perf probe: Query basic types from debuginfo
Query the basic type information (byte-size and signed-flag) from debuginfo and pass that to kprobe-tracer. This is especially useful for tracing the members of data structure, because each member has different byte-size on the memory. 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: <20100412171715.3790.23730.stgit@localhost6.localdomain6> Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/util/probe-event.c9
-rw-r--r--tools/perf/util/probe-event.h1
-rw-r--r--tools/perf/util/probe-finder.c78
3 files changed, 80 insertions, 8 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 19de8b77973d..05ca4a959e60 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -740,6 +740,13 @@ static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg,
740 buf += ret; 740 buf += ret;
741 buflen -= ret; 741 buflen -= ret;
742 } 742 }
743 /* Print argument type */
744 if (arg->type) {
745 ret = e_snprintf(buf, buflen, ":%s", arg->type);
746 if (ret <= 0)
747 return ret;
748 buf += ret;
749 }
743 750
744 return buf - tmp; 751 return buf - tmp;
745} 752}
@@ -848,6 +855,8 @@ void clear_kprobe_trace_event(struct kprobe_trace_event *tev)
848 free(tev->args[i].name); 855 free(tev->args[i].name);
849 if (tev->args[i].value) 856 if (tev->args[i].value)
850 free(tev->args[i].value); 857 free(tev->args[i].value);
858 if (tev->args[i].type)
859 free(tev->args[i].type);
851 ref = tev->args[i].ref; 860 ref = tev->args[i].ref;
852 while (ref) { 861 while (ref) {
853 next = ref->next; 862 next = ref->next;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 10411f596321..a393a3f87cd0 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -23,6 +23,7 @@ struct kprobe_trace_arg_ref {
23struct kprobe_trace_arg { 23struct kprobe_trace_arg {
24 char *name; /* Argument name */ 24 char *name; /* Argument name */
25 char *value; /* Base value */ 25 char *value; /* Base value */
26 char *type; /* Type name */
26 struct kprobe_trace_arg_ref *ref; /* Referencing offset */ 27 struct kprobe_trace_arg_ref *ref; /* Referencing offset */
27}; 28};
28 29
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 105e95c95eeb..ebeb413ac473 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) */
88static const char *get_arch_regstr(unsigned int n) 91static const char *get_arch_regstr(unsigned int n)
89{ 92{
@@ -230,6 +233,31 @@ static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem)
230 return die_mem; 233 return die_mem;
231} 234}
232 235
236static bool die_is_signed_type(Dwarf_Die *tp_die)
237{
238 Dwarf_Attribute attr;
239 Dwarf_Word ret;
240
241 if (dwarf_attr(tp_die, DW_AT_encoding, &attr) == NULL ||
242 dwarf_formudata(&attr, &ret) != 0)
243 return false;
244
245 return (ret == DW_ATE_signed_char || ret == DW_ATE_signed ||
246 ret == DW_ATE_signed_fixed);
247}
248
249static int die_get_byte_size(Dwarf_Die *tp_die)
250{
251 Dwarf_Attribute attr;
252 Dwarf_Word ret;
253
254 if (dwarf_attr(tp_die, DW_AT_byte_size, &attr) == NULL ||
255 dwarf_formudata(&attr, &ret) != 0)
256 return 0;
257
258 return (int)ret;
259}
260
233/* Return values for die_find callbacks */ 261/* Return values for die_find callbacks */
234enum { 262enum {
235 DIE_FIND_CB_FOUND = 0, /* End of Search */ 263 DIE_FIND_CB_FOUND = 0, /* End of Search */
@@ -406,13 +434,42 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf)
406 } 434 }
407} 435}
408 436
437static void convert_variable_type(Dwarf_Die *vr_die,
438 struct kprobe_trace_arg *targ)
439{
440 Dwarf_Die type;
441 char buf[16];
442 int ret;
443
444 if (die_get_real_type(vr_die, &type) == NULL)
445 die("Failed to get a type information of %s.",
446 dwarf_diename(vr_die));
447
448 ret = die_get_byte_size(&type) * 8;
449 if (ret) {
450 /* Check the bitwidth */
451 if (ret > MAX_BASIC_TYPE_BITS) {
452 pr_warning(" Warning: %s exceeds max-bitwidth."
453 " Cut down to %d bits.\n",
454 dwarf_diename(&type), MAX_BASIC_TYPE_BITS);
455 ret = MAX_BASIC_TYPE_BITS;
456 }
457
458 ret = snprintf(buf, 16, "%c%d",
459 die_is_signed_type(&type) ? 's' : 'u', ret);
460 if (ret < 0 || ret >= 16)
461 die("Failed to convert variable type.");
462 targ->type = xstrdup(buf);
463 }
464}
465
409static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, 466static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
410 struct perf_probe_arg_field *field, 467 struct perf_probe_arg_field *field,
411 struct kprobe_trace_arg_ref **ref_ptr) 468 struct kprobe_trace_arg_ref **ref_ptr,
469 Dwarf_Die *die_mem)
412{ 470{
413 struct kprobe_trace_arg_ref *ref = *ref_ptr; 471 struct kprobe_trace_arg_ref *ref = *ref_ptr;
414 Dwarf_Attribute attr; 472 Dwarf_Attribute attr;
415 Dwarf_Die member;
416 Dwarf_Die type; 473 Dwarf_Die type;
417 Dwarf_Word offs; 474 Dwarf_Word offs;
418 475
@@ -450,26 +507,27 @@ static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname,
450 die("Structure on a register is not supported yet."); 507 die("Structure on a register is not supported yet.");
451 } 508 }
452 509
453 if (die_find_member(&type, field->name, &member) == NULL) 510 if (die_find_member(&type, field->name, die_mem) == NULL)
454 die("%s(tyep:%s) has no member %s.", varname, 511 die("%s(tyep:%s) has no member %s.", varname,
455 dwarf_diename(&type), field->name); 512 dwarf_diename(&type), field->name);
456 513
457 /* Get the offset of the field */ 514 /* Get the offset of the field */
458 if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL || 515 if (dwarf_attr(die_mem, DW_AT_data_member_location, &attr) == NULL ||
459 dwarf_formudata(&attr, &offs) != 0) 516 dwarf_formudata(&attr, &offs) != 0)
460 die("Failed to get the offset of %s.", field->name); 517 die("Failed to get the offset of %s.", field->name);
461 ref->offset += (long)offs; 518 ref->offset += (long)offs;
462 519
463 /* Converting next field */ 520 /* Converting next field */
464 if (field->next) 521 if (field->next)
465 convert_variable_fields(&member, field->name, field->next, 522 convert_variable_fields(die_mem, field->name, field->next,
466 &ref); 523 &ref, die_mem);
467} 524}
468 525
469/* Show a variables in kprobe event format */ 526/* Show a variables in kprobe event format */
470static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) 527static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
471{ 528{
472 Dwarf_Attribute attr; 529 Dwarf_Attribute attr;
530 Dwarf_Die die_mem;
473 Dwarf_Op *expr; 531 Dwarf_Op *expr;
474 size_t nexpr; 532 size_t nexpr;
475 int ret; 533 int ret;
@@ -483,9 +541,13 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf)
483 541
484 convert_location(expr, pf); 542 convert_location(expr, pf);
485 543
486 if (pf->pvar->field) 544 if (pf->pvar->field) {
487 convert_variable_fields(vr_die, pf->pvar->var, 545 convert_variable_fields(vr_die, pf->pvar->var,
488 pf->pvar->field, &pf->tvar->ref); 546 pf->pvar->field, &pf->tvar->ref,
547 &die_mem);
548 vr_die = &die_mem;
549 }
550 convert_variable_type(vr_die, pf->tvar);
489 /* *expr will be cached in libdw. Don't free it. */ 551 /* *expr will be cached in libdw. Don't free it. */
490 return ; 552 return ;
491error: 553error: