aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@infradead.org>2010-02-25 10:57:40 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2010-04-01 19:01:23 -0400
commit84303658a8fd2bed8e27dacc25643a69dc7426fb (patch)
tree9bd0e13a475466253db699cfa7fcfbd433b47b28
parentc2b2df61e78aa5570473e2d46db6d88f5071b520 (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.c63
-rw-r--r--tools/perf/util/symbol.c2
-rw-r--r--tools/perf/util/symbol.h2
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
54static const char *sym_hist_filter; 54static const char *sym_hist_filter;
55 55
56static int symbol_filter(struct map *map __used, struct symbol *sym) 56static 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 */
81static void hist_hit(struct hist_entry *he, u64 ip) 69static 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
119static int perf_session__add_hist_entry(struct perf_session *self, 108static 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
131static int process_sample_event(event_t *event, struct perf_session *session) 132static 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
152static void symbol__delete(struct symbol *self) 152void 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
52void symbol__delete(struct symbol *self);
53
52struct strlist; 54struct strlist;
53 55
54struct symbol_conf { 56struct symbol_conf {