aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf
diff options
context:
space:
mode:
authorArnaldo Carvalho de Melo <acme@infradead.org>2010-02-25 10:57:40 -0500
committerIngo Molnar <mingo@elte.hu>2010-02-25 11:39:14 -0500
commit628ada0cb03666dd463f7c25947eaccdf440c309 (patch)
tree2338cf888ccecb1bb9df32031cef43f527b05ca0 /tools/perf
parent3846df2e0a99a2bf10023de0e9c1496592012d4c (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')
-rw-r--r--tools/perf/builtin-annotate.c57
-rw-r--r--tools/perf/util/symbol.c2
-rw-r--r--tools/perf/util/symbol.h2
3 files changed, 32 insertions, 29 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
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;
@@ -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
113static int perf_session__add_hist_entry(struct perf_session *self, 102static 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
125static int process_sample_event(event_t *event, struct perf_session *session) 126static 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;
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 7aab4e5f3669..323c0aea0a91 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -144,7 +144,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name)
144 return self; 144 return self;
145} 145}
146 146
147static void symbol__delete(struct symbol *self) 147void symbol__delete(struct symbol *self)
148{ 148{
149 free(((void *)self) - symbol_conf.priv_size); 149 free(((void *)self) - symbol_conf.priv_size);
150} 150}
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index 1b4192ee5300..280dadd32a08 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -51,6 +51,8 @@ struct symbol {
51 char name[0]; 51 char name[0];
52}; 52};
53 53
54void symbol__delete(struct symbol *self);
55
54struct strlist; 56struct strlist;
55 57
56struct symbol_conf { 58struct symbol_conf {