diff options
| -rw-r--r-- | tools/perf/util/probe-event.c | 9 | ||||
| -rw-r--r-- | tools/perf/util/probe-event.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 78 |
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 { | |||
| 23 | struct kprobe_trace_arg { | 23 | struct 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) */ |
| 88 | static const char *get_arch_regstr(unsigned int n) | 91 | static 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 | ||
| 236 | static 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 | |||
| 249 | static 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 */ |
| 234 | enum { | 262 | enum { |
| 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 | ||
| 437 | static 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 | |||
| 409 | static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | 466 | static 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 */ |
| 470 | static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 527 | static 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 ; |
| 491 | error: | 553 | error: |
