diff options
| author | Arnaldo Carvalho de Melo <acme@infradead.org> | 2010-02-25 10:57:40 -0500 |
|---|---|---|
| committer | Ingo Molnar <mingo@elte.hu> | 2010-02-25 11:39:14 -0500 |
| commit | 628ada0cb03666dd463f7c25947eaccdf440c309 (patch) | |
| tree | 2338cf888ccecb1bb9df32031cef43f527b05ca0 /tools/perf/builtin-annotate.c | |
| parent | 3846df2e0a99a2bf10023de0e9c1496592012d4c (diff) | |
perf annotate: Defer allocating sym_priv->hist array
Because symbol->end is not fixed up at symbol_filter time, only
after all symbols for a DSO are loaded, and that, for asm
symbols, may be bogus, causing segfaults when hits happen in
these symbols.
Reported-by: David Miller <davem@davemloft.net>
Reported-by: Anton Blanchard <anton@samba.org>
Acked-by: David Miller <davem@davemloft.net>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Frédéric Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Paul Mackerras <paulus@samba.org>
Cc: <stable@kernel.org> # for .33.x. Does not apply cleanly, needs backport.
LKML-Reference: <20100225155740.GB8553@ghostprotocols.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 57 |
1 files changed, 29 insertions, 28 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 28ea4e0c3658..e47dd1587e39 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -53,32 +53,20 @@ struct sym_priv { | |||
| 53 | 53 | ||
| 54 | static const char *sym_hist_filter; | 54 | static const char *sym_hist_filter; |
| 55 | 55 | ||
| 56 | static int symbol_filter(struct map *map __used, struct symbol *sym) | 56 | static int sym__alloc_hist(struct symbol *self) |
| 57 | { | 57 | { |
| 58 | if (sym_hist_filter == NULL || | 58 | struct sym_priv *priv = symbol__priv(self); |
| 59 | strcmp(sym->name, sym_hist_filter) == 0) { | 59 | const int size = (sizeof(*priv->hist) + |
| 60 | struct sym_priv *priv = symbol__priv(sym); | 60 | (self->end - self->start) * sizeof(u64)); |
| 61 | const int size = (sizeof(*priv->hist) + | ||
| 62 | (sym->end - sym->start) * sizeof(u64)); | ||
| 63 | 61 | ||
| 64 | priv->hist = malloc(size); | 62 | priv->hist = zalloc(size); |
| 65 | if (priv->hist) | 63 | return priv->hist == NULL ? -1 : 0; |
| 66 | memset(priv->hist, 0, size); | ||
| 67 | return 0; | ||
| 68 | } | ||
| 69 | /* | ||
| 70 | * FIXME: We should really filter it out, as we don't want to go thru symbols | ||
| 71 | * we're not interested, and if a DSO ends up with no symbols, delete it too, | ||
| 72 | * but right now the kernel loading routines in symbol.c bail out if no symbols | ||
| 73 | * are found, fix it later. | ||
| 74 | */ | ||
| 75 | return 0; | ||
| 76 | } | 64 | } |
| 77 | 65 | ||
| 78 | /* | 66 | /* |
| 79 | * collect histogram counts | 67 | * collect histogram counts |
| 80 | */ | 68 | */ |
| 81 | static void hist_hit(struct hist_entry *he, u64 ip) | 69 | static int annotate__hist_hit(struct hist_entry *he, u64 ip) |
| 82 | { | 70 | { |
| 83 | unsigned int sym_size, offset; | 71 | unsigned int sym_size, offset; |
| 84 | struct symbol *sym = he->sym; | 72 | struct symbol *sym = he->sym; |
| @@ -88,11 +76,11 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
| 88 | he->count++; | 76 | he->count++; |
| 89 | 77 | ||
| 90 | if (!sym || !he->map) | 78 | if (!sym || !he->map) |
| 91 | return; | 79 | return 0; |
| 92 | 80 | ||
| 93 | priv = symbol__priv(sym); | 81 | priv = symbol__priv(sym); |
| 94 | if (!priv->hist) | 82 | if (priv->hist == NULL && sym__alloc_hist(sym) < 0) |
| 95 | return; | 83 | return -ENOMEM; |
| 96 | 84 | ||
| 97 | sym_size = sym->end - sym->start; | 85 | sym_size = sym->end - sym->start; |
| 98 | offset = ip - sym->start; | 86 | offset = ip - sym->start; |
| @@ -100,7 +88,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
| 100 | pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip)); | 88 | pr_debug3("%s: ip=%#Lx\n", __func__, he->map->unmap_ip(he->map, ip)); |
| 101 | 89 | ||
| 102 | if (offset >= sym_size) | 90 | if (offset >= sym_size) |
| 103 | return; | 91 | return 0; |
| 104 | 92 | ||
| 105 | h = priv->hist; | 93 | h = priv->hist; |
| 106 | h->sum++; | 94 | h->sum++; |
| @@ -108,18 +96,31 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
| 108 | 96 | ||
| 109 | pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start, | 97 | pr_debug3("%#Lx %s: count++ [ip: %#Lx, %#Lx] => %Ld\n", he->sym->start, |
| 110 | he->sym->name, ip, ip - he->sym->start, h->ip[offset]); | 98 | he->sym->name, ip, ip - he->sym->start, h->ip[offset]); |
| 99 | return 0; | ||
| 111 | } | 100 | } |
| 112 | 101 | ||
| 113 | static int perf_session__add_hist_entry(struct perf_session *self, | 102 | static int perf_session__add_hist_entry(struct perf_session *self, |
| 114 | struct addr_location *al, u64 count) | 103 | struct addr_location *al, u64 count) |
| 115 | { | 104 | { |
| 116 | bool hit; | 105 | bool hit; |
| 117 | struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, | 106 | struct hist_entry *he; |
| 118 | count, &hit); | 107 | |
| 108 | if (sym_hist_filter != NULL && | ||
| 109 | (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { | ||
| 110 | /* We're only interested in a symbol named sym_hist_filter */ | ||
| 111 | if (al->sym != NULL) { | ||
| 112 | rb_erase(&al->sym->rb_node, | ||
| 113 | &al->map->dso->symbols[al->map->type]); | ||
| 114 | symbol__delete(al->sym); | ||
| 115 | } | ||
| 116 | return 0; | ||
| 117 | } | ||
| 118 | |||
| 119 | he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); | ||
| 119 | if (he == NULL) | 120 | if (he == NULL) |
| 120 | return -ENOMEM; | 121 | return -ENOMEM; |
| 121 | hist_hit(he, al->addr); | 122 | |
| 122 | return 0; | 123 | return annotate__hist_hit(he, al->addr); |
| 123 | } | 124 | } |
| 124 | 125 | ||
| 125 | static int process_sample_event(event_t *event, struct perf_session *session) | 126 | static int process_sample_event(event_t *event, struct perf_session *session) |
| @@ -129,7 +130,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 129 | dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, | 130 | dump_printf("(IP, %d): %d: %#Lx\n", event->header.misc, |
| 130 | event->ip.pid, event->ip.ip); | 131 | event->ip.pid, event->ip.ip); |
| 131 | 132 | ||
| 132 | if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { | 133 | if (event__preprocess_sample(event, session, &al, NULL) < 0) { |
| 133 | pr_warning("problem processing %d event, skipping it.\n", | 134 | pr_warning("problem processing %d event, skipping it.\n", |
| 134 | event->header.type); | 135 | event->header.type); |
| 135 | return -1; | 136 | return -1; |
