diff options
author | Arnaldo Carvalho de Melo <acme@infradead.org> | 2010-02-25 10:57:40 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-04-01 19:01:23 -0400 |
commit | 84303658a8fd2bed8e27dacc25643a69dc7426fb (patch) | |
tree | 9bd0e13a475466253db699cfa7fcfbd433b47b28 | |
parent | c2b2df61e78aa5570473e2d46db6d88f5071b520 (diff) |
perf annotate: Defer allocating sym_priv->hist array
commit 628ada0cb03666dd463f7c25947eaccdf440c309 upstream
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.
Backported-from: 628ada0
Reported-by: David Miller <davem@davemloft.net>
Reported-by: Anton Blanchard <anton@samba.org>
Acked-by: David Miller <davem@davemloft.net>
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>
LKML-Reference: <20100225155740.GB8553@ghostprotocols.net>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | tools/perf/builtin-annotate.c | 63 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 2 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 2 |
3 files changed, 35 insertions, 32 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 593ff25006de..0b1ba36393dd 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; |
@@ -102,7 +90,7 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
102 | he->map->unmap_ip(he->map, ip)); | 90 | he->map->unmap_ip(he->map, ip)); |
103 | 91 | ||
104 | if (offset >= sym_size) | 92 | if (offset >= sym_size) |
105 | return; | 93 | return 0; |
106 | 94 | ||
107 | h = priv->hist; | 95 | h = priv->hist; |
108 | h->sum++; | 96 | h->sum++; |
@@ -114,18 +102,31 @@ static void hist_hit(struct hist_entry *he, u64 ip) | |||
114 | he->sym->name, | 102 | he->sym->name, |
115 | (void *)(unsigned long)ip, ip - he->sym->start, | 103 | (void *)(unsigned long)ip, ip - he->sym->start, |
116 | h->ip[offset]); | 104 | h->ip[offset]); |
105 | return 0; | ||
117 | } | 106 | } |
118 | 107 | ||
119 | static int perf_session__add_hist_entry(struct perf_session *self, | 108 | static int perf_session__add_hist_entry(struct perf_session *self, |
120 | struct addr_location *al, u64 count) | 109 | struct addr_location *al, u64 count) |
121 | { | 110 | { |
122 | bool hit; | 111 | bool hit; |
123 | struct hist_entry *he = __perf_session__add_hist_entry(self, al, NULL, | 112 | struct hist_entry *he; |
124 | count, &hit); | 113 | |
125 | if (he == NULL) | 114 | if (sym_hist_filter != NULL && |
126 | return -ENOMEM; | 115 | (al->sym == NULL || strcmp(sym_hist_filter, al->sym->name) != 0)) { |
127 | hist_hit(he, al->addr); | 116 | /* We're only interested in a symbol named sym_hist_filter */ |
128 | return 0; | 117 | if (al->sym != NULL) { |
118 | rb_erase(&al->sym->rb_node, | ||
119 | &al->map->dso->symbols[al->map->type]); | ||
120 | symbol__delete(al->sym); | ||
121 | } | ||
122 | return 0; | ||
123 | } | ||
124 | |||
125 | he = __perf_session__add_hist_entry(self, al, NULL, count, &hit); | ||
126 | if (he == NULL) | ||
127 | return -ENOMEM; | ||
128 | |||
129 | return annotate__hist_hit(he, al->addr); | ||
129 | } | 130 | } |
130 | 131 | ||
131 | static int process_sample_event(event_t *event, struct perf_session *session) | 132 | static int process_sample_event(event_t *event, struct perf_session *session) |
@@ -135,7 +136,7 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
135 | dump_printf("(IP, %d): %d: %p\n", event->header.misc, | 136 | dump_printf("(IP, %d): %d: %p\n", event->header.misc, |
136 | event->ip.pid, (void *)(long)event->ip.ip); | 137 | event->ip.pid, (void *)(long)event->ip.ip); |
137 | 138 | ||
138 | if (event__preprocess_sample(event, session, &al, symbol_filter) < 0) { | 139 | if (event__preprocess_sample(event, session, &al, NULL) < 0) { |
139 | fprintf(stderr, "problem processing %d event, skipping it.\n", | 140 | fprintf(stderr, "problem processing %d event, skipping it.\n", |
140 | event->header.type); | 141 | event->header.type); |
141 | return -1; | 142 | return -1; |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 72547b914ad2..fcb8919887ae 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -149,7 +149,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name) | |||
149 | return self; | 149 | return self; |
150 | } | 150 | } |
151 | 151 | ||
152 | static void symbol__delete(struct symbol *self) | 152 | void symbol__delete(struct symbol *self) |
153 | { | 153 | { |
154 | free(((void *)self) - symbol_conf.priv_size); | 154 | free(((void *)self) - symbol_conf.priv_size); |
155 | } | 155 | } |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 8aded2356f79..400227a22d09 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -49,6 +49,8 @@ struct symbol { | |||
49 | char name[0]; | 49 | char name[0]; |
50 | }; | 50 | }; |
51 | 51 | ||
52 | void symbol__delete(struct symbol *self); | ||
53 | |||
52 | struct strlist; | 54 | struct strlist; |
53 | 55 | ||
54 | struct symbol_conf { | 56 | struct symbol_conf { |