diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-05-11 15:48:49 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-05-11 16:19:20 -0400 |
commit | 6de783b6f50f7f1db18a3fda0aa34b2e84b5771d (patch) | |
tree | b5606aafa9e9703d433d8dff6ef931027832eb90 /tools/perf/util/annotate.c | |
parent | e8ea1561952b04276cf4c02500e363de76c142aa (diff) |
perf annotate: Resolve symbols using objdump comment
This:
mov 0x95bbb6(%rip),%ecx # ffffffff81ae8d04 <d_hash_shift>
Becomes:
mov d_hash_shift,%ecx
Ditto for many more instructions that take two operands.
Requested-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-i5opbyai2x6mn9e5yjmhx9k6@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 112 |
1 files changed, 112 insertions, 0 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 9a020d1e0180..82c7f630f8a8 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -122,6 +122,89 @@ bool ins__is_jump(const struct ins *ins) | |||
122 | return ins->ops == &jump_ops; | 122 | return ins->ops == &jump_ops; |
123 | } | 123 | } |
124 | 124 | ||
125 | static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) | ||
126 | { | ||
127 | char *endptr, *name, *t; | ||
128 | |||
129 | if (strstr(raw, "(%rip)") == NULL) | ||
130 | return 0; | ||
131 | |||
132 | *addrp = strtoull(comment, &endptr, 16); | ||
133 | name = strchr(endptr, '<'); | ||
134 | if (name == NULL) | ||
135 | return -1; | ||
136 | |||
137 | name++; | ||
138 | |||
139 | t = strchr(name, '>'); | ||
140 | if (t == NULL) | ||
141 | return 0; | ||
142 | |||
143 | *t = '\0'; | ||
144 | *namep = strdup(name); | ||
145 | *t = '>'; | ||
146 | |||
147 | return 0; | ||
148 | } | ||
149 | |||
150 | static int mov__parse(struct ins_operands *ops) | ||
151 | { | ||
152 | char *s = strchr(ops->raw, ','), *target, *comment, prev; | ||
153 | |||
154 | if (s == NULL) | ||
155 | return -1; | ||
156 | |||
157 | *s = '\0'; | ||
158 | ops->source.raw = strdup(ops->raw); | ||
159 | *s = ','; | ||
160 | |||
161 | if (ops->source.raw == NULL) | ||
162 | return -1; | ||
163 | |||
164 | target = ++s; | ||
165 | |||
166 | while (s[0] != '\0' && !isspace(s[0])) | ||
167 | ++s; | ||
168 | prev = *s; | ||
169 | *s = '\0'; | ||
170 | |||
171 | ops->target.raw = strdup(target); | ||
172 | *s = prev; | ||
173 | |||
174 | if (ops->target.raw == NULL) | ||
175 | goto out_free_source; | ||
176 | |||
177 | comment = strchr(s, '#'); | ||
178 | if (comment == NULL) | ||
179 | return 0; | ||
180 | |||
181 | while (comment[0] != '\0' && isspace(comment[0])) | ||
182 | ++comment; | ||
183 | |||
184 | comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); | ||
185 | comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | ||
186 | |||
187 | return 0; | ||
188 | |||
189 | out_free_source: | ||
190 | free(ops->source.raw); | ||
191 | ops->source.raw = NULL; | ||
192 | return -1; | ||
193 | } | ||
194 | |||
195 | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, | ||
196 | struct ins_operands *ops) | ||
197 | { | ||
198 | return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, | ||
199 | ops->source.name ?: ops->source.raw, | ||
200 | ops->target.name ?: ops->target.raw); | ||
201 | } | ||
202 | |||
203 | static struct ins_ops mov_ops = { | ||
204 | .parse = mov__parse, | ||
205 | .scnprintf = mov__scnprintf, | ||
206 | }; | ||
207 | |||
125 | static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, | 208 | static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, |
126 | struct ins_operands *ops __used) | 209 | struct ins_operands *ops __used) |
127 | { | 210 | { |
@@ -136,8 +219,20 @@ static struct ins_ops nop_ops = { | |||
136 | * Must be sorted by name! | 219 | * Must be sorted by name! |
137 | */ | 220 | */ |
138 | static struct ins instructions[] = { | 221 | static struct ins instructions[] = { |
222 | { .name = "add", .ops = &mov_ops, }, | ||
223 | { .name = "addl", .ops = &mov_ops, }, | ||
224 | { .name = "addq", .ops = &mov_ops, }, | ||
225 | { .name = "addw", .ops = &mov_ops, }, | ||
226 | { .name = "and", .ops = &mov_ops, }, | ||
139 | { .name = "call", .ops = &call_ops, }, | 227 | { .name = "call", .ops = &call_ops, }, |
140 | { .name = "callq", .ops = &call_ops, }, | 228 | { .name = "callq", .ops = &call_ops, }, |
229 | { .name = "cmp", .ops = &mov_ops, }, | ||
230 | { .name = "cmpb", .ops = &mov_ops, }, | ||
231 | { .name = "cmpl", .ops = &mov_ops, }, | ||
232 | { .name = "cmpq", .ops = &mov_ops, }, | ||
233 | { .name = "cmpw", .ops = &mov_ops, }, | ||
234 | { .name = "cmpxch", .ops = &mov_ops, }, | ||
235 | { .name = "imul", .ops = &mov_ops, }, | ||
141 | { .name = "ja", .ops = &jump_ops, }, | 236 | { .name = "ja", .ops = &jump_ops, }, |
142 | { .name = "jae", .ops = &jump_ops, }, | 237 | { .name = "jae", .ops = &jump_ops, }, |
143 | { .name = "jb", .ops = &jump_ops, }, | 238 | { .name = "jb", .ops = &jump_ops, }, |
@@ -173,9 +268,23 @@ static struct ins instructions[] = { | |||
173 | { .name = "jrcxz", .ops = &jump_ops, }, | 268 | { .name = "jrcxz", .ops = &jump_ops, }, |
174 | { .name = "js", .ops = &jump_ops, }, | 269 | { .name = "js", .ops = &jump_ops, }, |
175 | { .name = "jz", .ops = &jump_ops, }, | 270 | { .name = "jz", .ops = &jump_ops, }, |
271 | { .name = "lea", .ops = &mov_ops, }, | ||
272 | { .name = "mov", .ops = &mov_ops, }, | ||
273 | { .name = "movb", .ops = &mov_ops, }, | ||
274 | { .name = "movdqa",.ops = &mov_ops, }, | ||
275 | { .name = "movl", .ops = &mov_ops, }, | ||
276 | { .name = "movq", .ops = &mov_ops, }, | ||
277 | { .name = "movslq", .ops = &mov_ops, }, | ||
278 | { .name = "movzbl", .ops = &mov_ops, }, | ||
279 | { .name = "movzwl", .ops = &mov_ops, }, | ||
176 | { .name = "nop", .ops = &nop_ops, }, | 280 | { .name = "nop", .ops = &nop_ops, }, |
177 | { .name = "nopl", .ops = &nop_ops, }, | 281 | { .name = "nopl", .ops = &nop_ops, }, |
178 | { .name = "nopw", .ops = &nop_ops, }, | 282 | { .name = "nopw", .ops = &nop_ops, }, |
283 | { .name = "or", .ops = &mov_ops, }, | ||
284 | { .name = "orl", .ops = &mov_ops, }, | ||
285 | { .name = "test", .ops = &mov_ops, }, | ||
286 | { .name = "testb", .ops = &mov_ops, }, | ||
287 | { .name = "testl", .ops = &mov_ops, }, | ||
179 | }; | 288 | }; |
180 | 289 | ||
181 | static int ins__cmp(const void *name, const void *insp) | 290 | static int ins__cmp(const void *name, const void *insp) |
@@ -323,6 +432,9 @@ void disasm_line__free(struct disasm_line *dl) | |||
323 | { | 432 | { |
324 | free(dl->line); | 433 | free(dl->line); |
325 | free(dl->name); | 434 | free(dl->name); |
435 | free(dl->ops.source.raw); | ||
436 | free(dl->ops.source.name); | ||
437 | free(dl->ops.target.raw); | ||
326 | free(dl->ops.target.name); | 438 | free(dl->ops.target.name); |
327 | free(dl); | 439 | free(dl); |
328 | } | 440 | } |