diff options
Diffstat (limited to 'tools/perf/util/probe-finder.c')
| -rw-r--r-- | tools/perf/util/probe-finder.c | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index e02b60770485..db52ec2e84de 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -206,6 +206,28 @@ static Dwarf_Addr die_get_entrypc(Dwarf_Die *dw_die) | |||
| 206 | return epc; | 206 | return epc; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | /* Get type die, but skip qualifiers and typedef */ | ||
| 210 | static Dwarf_Die *die_get_real_type(Dwarf_Die *vr_die, Dwarf_Die *die_mem) | ||
| 211 | { | ||
| 212 | Dwarf_Attribute attr; | ||
| 213 | int tag; | ||
| 214 | |||
| 215 | do { | ||
| 216 | if (dwarf_attr(vr_die, DW_AT_type, &attr) == NULL || | ||
| 217 | dwarf_formref_die(&attr, die_mem) == NULL) | ||
| 218 | return NULL; | ||
| 219 | |||
| 220 | tag = dwarf_tag(die_mem); | ||
| 221 | vr_die = die_mem; | ||
| 222 | } while (tag == DW_TAG_const_type || | ||
| 223 | tag == DW_TAG_restrict_type || | ||
| 224 | tag == DW_TAG_volatile_type || | ||
| 225 | tag == DW_TAG_shared_type || | ||
| 226 | tag == DW_TAG_typedef); | ||
| 227 | |||
| 228 | return die_mem; | ||
| 229 | } | ||
| 230 | |||
| 209 | /* Return values for die_find callbacks */ | 231 | /* Return values for die_find callbacks */ |
| 210 | enum { | 232 | enum { |
| 211 | DIE_FIND_CB_FOUND = 0, /* End of Search */ | 233 | DIE_FIND_CB_FOUND = 0, /* End of Search */ |
| @@ -314,6 +336,25 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, | |||
| 314 | die_mem); | 336 | die_mem); |
| 315 | } | 337 | } |
| 316 | 338 | ||
| 339 | static int __die_find_member_cb(Dwarf_Die *die_mem, void *data) | ||
| 340 | { | ||
| 341 | const char *name = data; | ||
| 342 | |||
| 343 | if ((dwarf_tag(die_mem) == DW_TAG_member) && | ||
| 344 | (die_compare_name(die_mem, name) == 0)) | ||
| 345 | return DIE_FIND_CB_FOUND; | ||
| 346 | |||
| 347 | return DIE_FIND_CB_SIBLING; | ||
| 348 | } | ||
| 349 | |||
| 350 | /* Find a member called 'name' */ | ||
| 351 | static Dwarf_Die *die_find_member(Dwarf_Die *st_die, const char *name, | ||
| 352 | Dwarf_Die *die_mem) | ||
| 353 | { | ||
| 354 | return die_find_child(st_die, __die_find_member_cb, (void *)name, | ||
| 355 | die_mem); | ||
| 356 | } | ||
| 357 | |||
| 317 | /* | 358 | /* |
| 318 | * Probe finder related functions | 359 | * Probe finder related functions |
| 319 | */ | 360 | */ |
| @@ -363,6 +404,62 @@ static void convert_location(Dwarf_Op *op, struct probe_finder *pf) | |||
| 363 | } | 404 | } |
| 364 | } | 405 | } |
| 365 | 406 | ||
| 407 | static void convert_variable_fields(Dwarf_Die *vr_die, const char *varname, | ||
| 408 | struct perf_probe_arg_field *field, | ||
| 409 | struct kprobe_trace_arg_ref **ref_ptr) | ||
| 410 | { | ||
| 411 | struct kprobe_trace_arg_ref *ref = *ref_ptr; | ||
| 412 | Dwarf_Attribute attr; | ||
| 413 | Dwarf_Die member; | ||
| 414 | Dwarf_Die type; | ||
| 415 | Dwarf_Word offs; | ||
| 416 | |||
| 417 | pr_debug("converting %s in %s\n", field->name, varname); | ||
| 418 | if (die_get_real_type(vr_die, &type) == NULL) | ||
| 419 | die("Failed to get a type information of %s.", varname); | ||
| 420 | |||
| 421 | /* Check the pointer and dereference */ | ||
| 422 | if (dwarf_tag(&type) == DW_TAG_pointer_type) { | ||
| 423 | if (!field->ref) | ||
| 424 | die("Semantic error: %s must be referred by '->'", | ||
| 425 | field->name); | ||
| 426 | /* Get the type pointed by this pointer */ | ||
| 427 | if (die_get_real_type(&type, &type) == NULL) | ||
| 428 | die("Failed to get a type information of %s.", varname); | ||
| 429 | |||
| 430 | ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); | ||
| 431 | if (*ref_ptr) | ||
| 432 | (*ref_ptr)->next = ref; | ||
| 433 | else | ||
| 434 | *ref_ptr = ref; | ||
| 435 | } else { | ||
| 436 | if (field->ref) | ||
| 437 | die("Semantic error: %s must be referred by '.'", | ||
| 438 | field->name); | ||
| 439 | if (!ref) | ||
| 440 | die("Structure on a register is not supported yet."); | ||
| 441 | } | ||
| 442 | |||
| 443 | /* Verify it is a data structure */ | ||
| 444 | if (dwarf_tag(&type) != DW_TAG_structure_type) | ||
| 445 | die("%s is not a data structure.", varname); | ||
| 446 | |||
| 447 | if (die_find_member(&type, field->name, &member) == NULL) | ||
| 448 | die("%s(tyep:%s) has no member %s.", varname, | ||
| 449 | dwarf_diename(&type), field->name); | ||
| 450 | |||
| 451 | /* Get the offset of the field */ | ||
| 452 | if (dwarf_attr(&member, DW_AT_data_member_location, &attr) == NULL || | ||
| 453 | dwarf_formudata(&attr, &offs) != 0) | ||
| 454 | die("Failed to get the offset of %s.", field->name); | ||
| 455 | ref->offset += (long)offs; | ||
| 456 | |||
| 457 | /* Converting next field */ | ||
| 458 | if (field->next) | ||
| 459 | convert_variable_fields(&member, field->name, field->next, | ||
| 460 | &ref); | ||
| 461 | } | ||
| 462 | |||
| 366 | /* Show a variables in kprobe event format */ | 463 | /* Show a variables in kprobe event format */ |
| 367 | static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 464 | static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
| 368 | { | 465 | { |
| @@ -379,6 +476,10 @@ static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
| 379 | goto error; | 476 | goto error; |
| 380 | 477 | ||
| 381 | convert_location(expr, pf); | 478 | convert_location(expr, pf); |
| 479 | |||
| 480 | if (pf->pvar->field) | ||
| 481 | convert_variable_fields(vr_die, pf->pvar->name, | ||
| 482 | pf->pvar->field, &pf->tvar->ref); | ||
| 382 | /* *expr will be cached in libdw. Don't free it. */ | 483 | /* *expr will be cached in libdw. Don't free it. */ |
| 383 | return ; | 484 | return ; |
| 384 | error: | 485 | error: |
| @@ -391,13 +492,15 @@ error: | |||
| 391 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 492 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
| 392 | { | 493 | { |
| 393 | Dwarf_Die vr_die; | 494 | Dwarf_Die vr_die; |
| 495 | char buf[128]; | ||
| 394 | 496 | ||
| 395 | /* TODO: Support struct members and arrays */ | 497 | /* TODO: Support struct members and arrays */ |
| 396 | if (!is_c_varname(pf->pvar->name)) { | 498 | if (!is_c_varname(pf->pvar->name)) { |
| 397 | /* Copy raw parameters */ | 499 | /* Copy raw parameters */ |
| 398 | pf->tvar->value = xstrdup(pf->pvar->name); | 500 | pf->tvar->value = xstrdup(pf->pvar->name); |
| 399 | } else { | 501 | } else { |
| 400 | pf->tvar->name = xstrdup(pf->pvar->name); | 502 | synthesize_perf_probe_arg(pf->pvar, buf, 128); |
| 503 | pf->tvar->name = xstrdup(buf); | ||
| 401 | pr_debug("Searching '%s' variable in context.\n", | 504 | pr_debug("Searching '%s' variable in context.\n", |
| 402 | pf->pvar->name); | 505 | pf->pvar->name); |
| 403 | /* Search child die for local variables and parameters. */ | 506 | /* Search child die for local variables and parameters. */ |
