diff options
author | Paul Clarke <pc@us.ibm.com> | 2017-04-25 14:15:49 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2017-05-02 17:23:11 -0400 |
commit | d80406453ad4a69932dc17a617d5b7bc7ae80b8f (patch) | |
tree | 43551c93dab399be05e0979ef1e610a3bfc3228a /tools | |
parent | b843f62ad942f3879c2d7acd27b44f931c609685 (diff) |
perf symbols: Allow user probes on versioned symbols
Symbol versioning, as in glibc, results in symbols being defined as:
<real symbol>@[@]<version>
(Note that "@@" identifies a default symbol, if the symbol name is
repeated.)
perf is currently unable to deal with this, and is unable to create user
probes at such symbols:
--
$ nm /lib/powerpc64le-linux-gnu/libpthread.so.0 | grep pthread_create
0000000000008d30 t __pthread_create_2_1
0000000000008d30 T pthread_create@@GLIBC_2.17
$ /usr/bin/sudo perf probe -v -x /lib/powerpc64le-linux-gnu/libpthread.so.0 pthread_create
probe-definition(0): pthread_create
symbol:pthread_create file:(null) line:0 offset:0 return:0 lazy:(null)
0 arguments
Open Debuginfo file: /usr/lib/debug/lib/powerpc64le-linux-gnu/libpthread-2.19.so
Try to find probe point from debuginfo.
Probe point 'pthread_create' not found.
Error: Failed to add events. Reason: No such file or directory (Code: -2)
--
One is not able to specify the fully versioned symbol, either, due to
syntactic conflicts with other uses of "@" by perf:
--
$ /usr/bin/sudo perf probe -v -x /lib/powerpc64le-linux-gnu/libpthread.so.0 pthread_create@@GLIBC_2.17
probe-definition(0): pthread_create@@GLIBC_2.17
Semantic error :SRC@SRC is not allowed.
0 arguments
Error: Command Parse Error. Reason: Invalid argument (Code: -22)
--
This patch ignores versioning for default symbols, thus allowing probes to be
created for these symbols:
--
$ /usr/bin/sudo ./perf probe -x /lib/powerpc64le-linux-gnu/libpthread.so.0 pthread_create
Added new event:
probe_libpthread:pthread_create (on pthread_create in /lib/powerpc64le-linux-gnu/libpthread-2.19.so)
You can now use it in all perf tools, such as:
perf record -e probe_libpthread:pthread_create -aR sleep 1
$ /usr/bin/sudo ./perf record -e probe_libpthread:pthread_create -aR ./test 2
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 0.052 MB perf.data (2 samples) ]
$ /usr/bin/sudo ./perf script
test 2915 [000] 19124.260729: probe_libpthread:pthread_create: (3fff99248d38)
test 2916 [000] 19124.260962: probe_libpthread:pthread_create: (3fff99248d38)
$ /usr/bin/sudo ./perf probe --del=probe_libpthread:pthread_create
Removed event: probe_libpthread:pthread_create
--
Committer note:
Change the variable storing the result of strlen() to 'int', to fix the build
on debian:experimental-x-mipsel, fedora:24-x-ARC-uClibc, ubuntu:16.04-x-arm,
etc:
util/symbol.c: In function 'symbol__match_symbol_name':
util/symbol.c:422:11: error: comparison between signed and unsigned integer expressions [-Werror=sign-compare]
if (len < versioning - name)
^
Signed-off-by: Paul A. Clarke <pc@us.ibm.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
Cc: David Ahern <dsahern@gmail.com>
Link: http://lkml.kernel.org/r/c2b18d9c-17f8-9285-4868-f58b6359ccac@us.ibm.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/arch/powerpc/util/sym-handling.c | 12 | ||||
-rw-r--r-- | tools/perf/util/map.c | 5 | ||||
-rw-r--r-- | tools/perf/util/map.h | 5 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 61 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 11 |
5 files changed, 74 insertions, 20 deletions
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index 39dbe512b9fc..bf9a2594572c 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c | |||
@@ -52,6 +52,18 @@ int arch__compare_symbol_names(const char *namea, const char *nameb) | |||
52 | 52 | ||
53 | return strcmp(namea, nameb); | 53 | return strcmp(namea, nameb); |
54 | } | 54 | } |
55 | |||
56 | int arch__compare_symbol_names_n(const char *namea, const char *nameb, | ||
57 | unsigned int n) | ||
58 | { | ||
59 | /* Skip over initial dot */ | ||
60 | if (*namea == '.') | ||
61 | namea++; | ||
62 | if (*nameb == '.') | ||
63 | nameb++; | ||
64 | |||
65 | return strncmp(namea, nameb, n); | ||
66 | } | ||
55 | #endif | 67 | #endif |
56 | 68 | ||
57 | #if defined(_CALL_ELF) && _CALL_ELF == 2 | 69 | #if defined(_CALL_ELF) && _CALL_ELF == 2 |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index ebfa5d92358a..2179b2deb730 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -325,11 +325,6 @@ int map__load(struct map *map) | |||
325 | return 0; | 325 | return 0; |
326 | } | 326 | } |
327 | 327 | ||
328 | int __weak arch__compare_symbol_names(const char *namea, const char *nameb) | ||
329 | { | ||
330 | return strcmp(namea, nameb); | ||
331 | } | ||
332 | |||
333 | struct symbol *map__find_symbol(struct map *map, u64 addr) | 328 | struct symbol *map__find_symbol(struct map *map, u64 addr) |
334 | { | 329 | { |
335 | if (map__load(map) < 0) | 330 | if (map__load(map) < 0) |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index c8a5a644c0a9..f9e8ac8a52cd 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -130,13 +130,14 @@ struct thread; | |||
130 | */ | 130 | */ |
131 | #define __map__for_each_symbol_by_name(map, sym_name, pos) \ | 131 | #define __map__for_each_symbol_by_name(map, sym_name, pos) \ |
132 | for (pos = map__find_symbol_by_name(map, sym_name); \ | 132 | for (pos = map__find_symbol_by_name(map, sym_name); \ |
133 | pos && arch__compare_symbol_names(pos->name, sym_name) == 0; \ | 133 | pos && \ |
134 | !symbol__match_symbol_name(pos->name, sym_name, \ | ||
135 | SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); \ | ||
134 | pos = symbol__next_by_name(pos)) | 136 | pos = symbol__next_by_name(pos)) |
135 | 137 | ||
136 | #define map__for_each_symbol_by_name(map, sym_name, pos) \ | 138 | #define map__for_each_symbol_by_name(map, sym_name, pos) \ |
137 | __map__for_each_symbol_by_name(map, sym_name, (pos)) | 139 | __map__for_each_symbol_by_name(map, sym_name, (pos)) |
138 | 140 | ||
139 | int arch__compare_symbol_names(const char *namea, const char *nameb); | ||
140 | void map__init(struct map *map, enum map_type type, | 141 | void map__init(struct map *map, enum map_type type, |
141 | u64 start, u64 end, u64 pgoff, struct dso *dso); | 142 | u64 start, u64 end, u64 pgoff, struct dso *dso); |
142 | struct map *map__new(struct machine *machine, u64 start, u64 len, | 143 | struct map *map__new(struct machine *machine, u64 start, u64 len, |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b349e8eda0e2..8f2b068ff756 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -90,6 +90,17 @@ static int prefix_underscores_count(const char *str) | |||
90 | return tail - str; | 90 | return tail - str; |
91 | } | 91 | } |
92 | 92 | ||
93 | int __weak arch__compare_symbol_names(const char *namea, const char *nameb) | ||
94 | { | ||
95 | return strcmp(namea, nameb); | ||
96 | } | ||
97 | |||
98 | int __weak arch__compare_symbol_names_n(const char *namea, const char *nameb, | ||
99 | unsigned int n) | ||
100 | { | ||
101 | return strncmp(namea, nameb, n); | ||
102 | } | ||
103 | |||
93 | int __weak arch__choose_best_symbol(struct symbol *syma, | 104 | int __weak arch__choose_best_symbol(struct symbol *syma, |
94 | struct symbol *symb __maybe_unused) | 105 | struct symbol *symb __maybe_unused) |
95 | { | 106 | { |
@@ -399,8 +410,26 @@ static void symbols__sort_by_name(struct rb_root *symbols, | |||
399 | } | 410 | } |
400 | } | 411 | } |
401 | 412 | ||
413 | int symbol__match_symbol_name(const char *name, const char *str, | ||
414 | enum symbol_tag_include includes) | ||
415 | { | ||
416 | const char *versioning; | ||
417 | |||
418 | if (includes == SYMBOL_TAG_INCLUDE__DEFAULT_ONLY && | ||
419 | (versioning = strstr(name, "@@"))) { | ||
420 | int len = strlen(str); | ||
421 | |||
422 | if (len < versioning - name) | ||
423 | len = versioning - name; | ||
424 | |||
425 | return arch__compare_symbol_names_n(name, str, len); | ||
426 | } else | ||
427 | return arch__compare_symbol_names(name, str); | ||
428 | } | ||
429 | |||
402 | static struct symbol *symbols__find_by_name(struct rb_root *symbols, | 430 | static struct symbol *symbols__find_by_name(struct rb_root *symbols, |
403 | const char *name) | 431 | const char *name, |
432 | enum symbol_tag_include includes) | ||
404 | { | 433 | { |
405 | struct rb_node *n; | 434 | struct rb_node *n; |
406 | struct symbol_name_rb_node *s = NULL; | 435 | struct symbol_name_rb_node *s = NULL; |
@@ -414,11 +443,11 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols, | |||
414 | int cmp; | 443 | int cmp; |
415 | 444 | ||
416 | s = rb_entry(n, struct symbol_name_rb_node, rb_node); | 445 | s = rb_entry(n, struct symbol_name_rb_node, rb_node); |
417 | cmp = arch__compare_symbol_names(name, s->sym.name); | 446 | cmp = symbol__match_symbol_name(s->sym.name, name, includes); |
418 | 447 | ||
419 | if (cmp < 0) | 448 | if (cmp > 0) |
420 | n = n->rb_left; | 449 | n = n->rb_left; |
421 | else if (cmp > 0) | 450 | else if (cmp < 0) |
422 | n = n->rb_right; | 451 | n = n->rb_right; |
423 | else | 452 | else |
424 | break; | 453 | break; |
@@ -427,16 +456,17 @@ static struct symbol *symbols__find_by_name(struct rb_root *symbols, | |||
427 | if (n == NULL) | 456 | if (n == NULL) |
428 | return NULL; | 457 | return NULL; |
429 | 458 | ||
430 | /* return first symbol that has same name (if any) */ | 459 | if (includes != SYMBOL_TAG_INCLUDE__DEFAULT_ONLY) |
431 | for (n = rb_prev(n); n; n = rb_prev(n)) { | 460 | /* return first symbol that has same name (if any) */ |
432 | struct symbol_name_rb_node *tmp; | 461 | for (n = rb_prev(n); n; n = rb_prev(n)) { |
462 | struct symbol_name_rb_node *tmp; | ||
433 | 463 | ||
434 | tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); | 464 | tmp = rb_entry(n, struct symbol_name_rb_node, rb_node); |
435 | if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) | 465 | if (arch__compare_symbol_names(tmp->sym.name, s->sym.name)) |
436 | break; | 466 | break; |
437 | 467 | ||
438 | s = tmp; | 468 | s = tmp; |
439 | } | 469 | } |
440 | 470 | ||
441 | return &s->sym; | 471 | return &s->sym; |
442 | } | 472 | } |
@@ -503,7 +533,12 @@ struct symbol *symbol__next_by_name(struct symbol *sym) | |||
503 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 533 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
504 | const char *name) | 534 | const char *name) |
505 | { | 535 | { |
506 | return symbols__find_by_name(&dso->symbol_names[type], name); | 536 | struct symbol *s = symbols__find_by_name(&dso->symbol_names[type], name, |
537 | SYMBOL_TAG_INCLUDE__NONE); | ||
538 | if (!s) | ||
539 | s = symbols__find_by_name(&dso->symbol_names[type], name, | ||
540 | SYMBOL_TAG_INCLUDE__DEFAULT_ONLY); | ||
541 | return s; | ||
507 | } | 542 | } |
508 | 543 | ||
509 | void dso__sort_by_name(struct dso *dso, enum map_type type) | 544 | void dso__sort_by_name(struct dso *dso, enum map_type type) |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 7acd70fce68e..41ebba9a2eb2 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -348,8 +348,19 @@ void arch__sym_update(struct symbol *s, GElf_Sym *sym); | |||
348 | #define SYMBOL_A 0 | 348 | #define SYMBOL_A 0 |
349 | #define SYMBOL_B 1 | 349 | #define SYMBOL_B 1 |
350 | 350 | ||
351 | int arch__compare_symbol_names(const char *namea, const char *nameb); | ||
352 | int arch__compare_symbol_names_n(const char *namea, const char *nameb, | ||
353 | unsigned int n); | ||
351 | int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb); | 354 | int arch__choose_best_symbol(struct symbol *syma, struct symbol *symb); |
352 | 355 | ||
356 | enum symbol_tag_include { | ||
357 | SYMBOL_TAG_INCLUDE__NONE = 0, | ||
358 | SYMBOL_TAG_INCLUDE__DEFAULT_ONLY | ||
359 | }; | ||
360 | |||
361 | int symbol__match_symbol_name(const char *namea, const char *nameb, | ||
362 | enum symbol_tag_include includes); | ||
363 | |||
353 | /* structure containing an SDT note's info */ | 364 | /* structure containing an SDT note's info */ |
354 | struct sdt_note { | 365 | struct sdt_note { |
355 | char *name; /* name of the note*/ | 366 | char *name; /* name of the note*/ |