diff options
Diffstat (limited to 'tools/perf/util/annotate.c')
-rw-r--r-- | tools/perf/util/annotate.c | 599 |
1 files changed, 555 insertions, 44 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 08c6d138a655..8069dfb5ba77 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -18,6 +18,403 @@ | |||
18 | 18 | ||
19 | const char *disassembler_style; | 19 | const char *disassembler_style; |
20 | 20 | ||
21 | static struct ins *ins__find(const char *name); | ||
22 | static int disasm_line__parse(char *line, char **namep, char **rawp); | ||
23 | |||
24 | static void ins__delete(struct ins_operands *ops) | ||
25 | { | ||
26 | free(ops->source.raw); | ||
27 | free(ops->source.name); | ||
28 | free(ops->target.raw); | ||
29 | free(ops->target.name); | ||
30 | } | ||
31 | |||
32 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | ||
33 | struct ins_operands *ops) | ||
34 | { | ||
35 | return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); | ||
36 | } | ||
37 | |||
38 | int ins__scnprintf(struct ins *ins, char *bf, size_t size, | ||
39 | struct ins_operands *ops) | ||
40 | { | ||
41 | if (ins->ops->scnprintf) | ||
42 | return ins->ops->scnprintf(ins, bf, size, ops); | ||
43 | |||
44 | return ins__raw_scnprintf(ins, bf, size, ops); | ||
45 | } | ||
46 | |||
47 | static int call__parse(struct ins_operands *ops) | ||
48 | { | ||
49 | char *endptr, *tok, *name; | ||
50 | |||
51 | ops->target.addr = strtoull(ops->raw, &endptr, 16); | ||
52 | |||
53 | name = strchr(endptr, '<'); | ||
54 | if (name == NULL) | ||
55 | goto indirect_call; | ||
56 | |||
57 | name++; | ||
58 | |||
59 | tok = strchr(name, '>'); | ||
60 | if (tok == NULL) | ||
61 | return -1; | ||
62 | |||
63 | *tok = '\0'; | ||
64 | ops->target.name = strdup(name); | ||
65 | *tok = '>'; | ||
66 | |||
67 | return ops->target.name == NULL ? -1 : 0; | ||
68 | |||
69 | indirect_call: | ||
70 | tok = strchr(endptr, '('); | ||
71 | if (tok != NULL) { | ||
72 | ops->target.addr = 0; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | tok = strchr(endptr, '*'); | ||
77 | if (tok == NULL) | ||
78 | return -1; | ||
79 | |||
80 | ops->target.addr = strtoull(tok + 1, NULL, 16); | ||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int call__scnprintf(struct ins *ins, char *bf, size_t size, | ||
85 | struct ins_operands *ops) | ||
86 | { | ||
87 | if (ops->target.name) | ||
88 | return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); | ||
89 | |||
90 | if (ops->target.addr == 0) | ||
91 | return ins__raw_scnprintf(ins, bf, size, ops); | ||
92 | |||
93 | return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); | ||
94 | } | ||
95 | |||
96 | static struct ins_ops call_ops = { | ||
97 | .parse = call__parse, | ||
98 | .scnprintf = call__scnprintf, | ||
99 | }; | ||
100 | |||
101 | bool ins__is_call(const struct ins *ins) | ||
102 | { | ||
103 | return ins->ops == &call_ops; | ||
104 | } | ||
105 | |||
106 | static int jump__parse(struct ins_operands *ops) | ||
107 | { | ||
108 | const char *s = strchr(ops->raw, '+'); | ||
109 | |||
110 | ops->target.addr = strtoll(ops->raw, NULL, 16); | ||
111 | |||
112 | if (s++ != NULL) | ||
113 | ops->target.offset = strtoll(s, NULL, 16); | ||
114 | else | ||
115 | ops->target.offset = UINT64_MAX; | ||
116 | |||
117 | return 0; | ||
118 | } | ||
119 | |||
120 | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | ||
121 | struct ins_operands *ops) | ||
122 | { | ||
123 | return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); | ||
124 | } | ||
125 | |||
126 | static struct ins_ops jump_ops = { | ||
127 | .parse = jump__parse, | ||
128 | .scnprintf = jump__scnprintf, | ||
129 | }; | ||
130 | |||
131 | bool ins__is_jump(const struct ins *ins) | ||
132 | { | ||
133 | return ins->ops == &jump_ops; | ||
134 | } | ||
135 | |||
136 | static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) | ||
137 | { | ||
138 | char *endptr, *name, *t; | ||
139 | |||
140 | if (strstr(raw, "(%rip)") == NULL) | ||
141 | return 0; | ||
142 | |||
143 | *addrp = strtoull(comment, &endptr, 16); | ||
144 | name = strchr(endptr, '<'); | ||
145 | if (name == NULL) | ||
146 | return -1; | ||
147 | |||
148 | name++; | ||
149 | |||
150 | t = strchr(name, '>'); | ||
151 | if (t == NULL) | ||
152 | return 0; | ||
153 | |||
154 | *t = '\0'; | ||
155 | *namep = strdup(name); | ||
156 | *t = '>'; | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static int lock__parse(struct ins_operands *ops) | ||
162 | { | ||
163 | char *name; | ||
164 | |||
165 | ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); | ||
166 | if (ops->locked.ops == NULL) | ||
167 | return 0; | ||
168 | |||
169 | if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) | ||
170 | goto out_free_ops; | ||
171 | |||
172 | ops->locked.ins = ins__find(name); | ||
173 | if (ops->locked.ins == NULL) | ||
174 | goto out_free_ops; | ||
175 | |||
176 | if (!ops->locked.ins->ops) | ||
177 | return 0; | ||
178 | |||
179 | if (ops->locked.ins->ops->parse) | ||
180 | ops->locked.ins->ops->parse(ops->locked.ops); | ||
181 | |||
182 | return 0; | ||
183 | |||
184 | out_free_ops: | ||
185 | free(ops->locked.ops); | ||
186 | ops->locked.ops = NULL; | ||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | ||
191 | struct ins_operands *ops) | ||
192 | { | ||
193 | int printed; | ||
194 | |||
195 | if (ops->locked.ins == NULL) | ||
196 | return ins__raw_scnprintf(ins, bf, size, ops); | ||
197 | |||
198 | printed = scnprintf(bf, size, "%-6.6s ", ins->name); | ||
199 | return printed + ins__scnprintf(ops->locked.ins, bf + printed, | ||
200 | size - printed, ops->locked.ops); | ||
201 | } | ||
202 | |||
203 | static void lock__delete(struct ins_operands *ops) | ||
204 | { | ||
205 | free(ops->locked.ops); | ||
206 | free(ops->target.raw); | ||
207 | free(ops->target.name); | ||
208 | } | ||
209 | |||
210 | static struct ins_ops lock_ops = { | ||
211 | .free = lock__delete, | ||
212 | .parse = lock__parse, | ||
213 | .scnprintf = lock__scnprintf, | ||
214 | }; | ||
215 | |||
216 | static int mov__parse(struct ins_operands *ops) | ||
217 | { | ||
218 | char *s = strchr(ops->raw, ','), *target, *comment, prev; | ||
219 | |||
220 | if (s == NULL) | ||
221 | return -1; | ||
222 | |||
223 | *s = '\0'; | ||
224 | ops->source.raw = strdup(ops->raw); | ||
225 | *s = ','; | ||
226 | |||
227 | if (ops->source.raw == NULL) | ||
228 | return -1; | ||
229 | |||
230 | target = ++s; | ||
231 | |||
232 | while (s[0] != '\0' && !isspace(s[0])) | ||
233 | ++s; | ||
234 | prev = *s; | ||
235 | *s = '\0'; | ||
236 | |||
237 | ops->target.raw = strdup(target); | ||
238 | *s = prev; | ||
239 | |||
240 | if (ops->target.raw == NULL) | ||
241 | goto out_free_source; | ||
242 | |||
243 | comment = strchr(s, '#'); | ||
244 | if (comment == NULL) | ||
245 | return 0; | ||
246 | |||
247 | while (comment[0] != '\0' && isspace(comment[0])) | ||
248 | ++comment; | ||
249 | |||
250 | comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); | ||
251 | comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | ||
252 | |||
253 | return 0; | ||
254 | |||
255 | out_free_source: | ||
256 | free(ops->source.raw); | ||
257 | ops->source.raw = NULL; | ||
258 | return -1; | ||
259 | } | ||
260 | |||
261 | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, | ||
262 | struct ins_operands *ops) | ||
263 | { | ||
264 | return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, | ||
265 | ops->source.name ?: ops->source.raw, | ||
266 | ops->target.name ?: ops->target.raw); | ||
267 | } | ||
268 | |||
269 | static struct ins_ops mov_ops = { | ||
270 | .parse = mov__parse, | ||
271 | .scnprintf = mov__scnprintf, | ||
272 | }; | ||
273 | |||
274 | static int dec__parse(struct ins_operands *ops) | ||
275 | { | ||
276 | char *target, *comment, *s, prev; | ||
277 | |||
278 | target = s = ops->raw; | ||
279 | |||
280 | while (s[0] != '\0' && !isspace(s[0])) | ||
281 | ++s; | ||
282 | prev = *s; | ||
283 | *s = '\0'; | ||
284 | |||
285 | ops->target.raw = strdup(target); | ||
286 | *s = prev; | ||
287 | |||
288 | if (ops->target.raw == NULL) | ||
289 | return -1; | ||
290 | |||
291 | comment = strchr(s, '#'); | ||
292 | if (comment == NULL) | ||
293 | return 0; | ||
294 | |||
295 | while (comment[0] != '\0' && isspace(comment[0])) | ||
296 | ++comment; | ||
297 | |||
298 | comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | ||
299 | |||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int dec__scnprintf(struct ins *ins, char *bf, size_t size, | ||
304 | struct ins_operands *ops) | ||
305 | { | ||
306 | return scnprintf(bf, size, "%-6.6s %s", ins->name, | ||
307 | ops->target.name ?: ops->target.raw); | ||
308 | } | ||
309 | |||
310 | static struct ins_ops dec_ops = { | ||
311 | .parse = dec__parse, | ||
312 | .scnprintf = dec__scnprintf, | ||
313 | }; | ||
314 | |||
315 | static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size, | ||
316 | struct ins_operands *ops __used) | ||
317 | { | ||
318 | return scnprintf(bf, size, "%-6.6s", "nop"); | ||
319 | } | ||
320 | |||
321 | static struct ins_ops nop_ops = { | ||
322 | .scnprintf = nop__scnprintf, | ||
323 | }; | ||
324 | |||
325 | /* | ||
326 | * Must be sorted by name! | ||
327 | */ | ||
328 | static struct ins instructions[] = { | ||
329 | { .name = "add", .ops = &mov_ops, }, | ||
330 | { .name = "addl", .ops = &mov_ops, }, | ||
331 | { .name = "addq", .ops = &mov_ops, }, | ||
332 | { .name = "addw", .ops = &mov_ops, }, | ||
333 | { .name = "and", .ops = &mov_ops, }, | ||
334 | { .name = "bts", .ops = &mov_ops, }, | ||
335 | { .name = "call", .ops = &call_ops, }, | ||
336 | { .name = "callq", .ops = &call_ops, }, | ||
337 | { .name = "cmp", .ops = &mov_ops, }, | ||
338 | { .name = "cmpb", .ops = &mov_ops, }, | ||
339 | { .name = "cmpl", .ops = &mov_ops, }, | ||
340 | { .name = "cmpq", .ops = &mov_ops, }, | ||
341 | { .name = "cmpw", .ops = &mov_ops, }, | ||
342 | { .name = "cmpxch", .ops = &mov_ops, }, | ||
343 | { .name = "dec", .ops = &dec_ops, }, | ||
344 | { .name = "decl", .ops = &dec_ops, }, | ||
345 | { .name = "imul", .ops = &mov_ops, }, | ||
346 | { .name = "inc", .ops = &dec_ops, }, | ||
347 | { .name = "incl", .ops = &dec_ops, }, | ||
348 | { .name = "ja", .ops = &jump_ops, }, | ||
349 | { .name = "jae", .ops = &jump_ops, }, | ||
350 | { .name = "jb", .ops = &jump_ops, }, | ||
351 | { .name = "jbe", .ops = &jump_ops, }, | ||
352 | { .name = "jc", .ops = &jump_ops, }, | ||
353 | { .name = "jcxz", .ops = &jump_ops, }, | ||
354 | { .name = "je", .ops = &jump_ops, }, | ||
355 | { .name = "jecxz", .ops = &jump_ops, }, | ||
356 | { .name = "jg", .ops = &jump_ops, }, | ||
357 | { .name = "jge", .ops = &jump_ops, }, | ||
358 | { .name = "jl", .ops = &jump_ops, }, | ||
359 | { .name = "jle", .ops = &jump_ops, }, | ||
360 | { .name = "jmp", .ops = &jump_ops, }, | ||
361 | { .name = "jmpq", .ops = &jump_ops, }, | ||
362 | { .name = "jna", .ops = &jump_ops, }, | ||
363 | { .name = "jnae", .ops = &jump_ops, }, | ||
364 | { .name = "jnb", .ops = &jump_ops, }, | ||
365 | { .name = "jnbe", .ops = &jump_ops, }, | ||
366 | { .name = "jnc", .ops = &jump_ops, }, | ||
367 | { .name = "jne", .ops = &jump_ops, }, | ||
368 | { .name = "jng", .ops = &jump_ops, }, | ||
369 | { .name = "jnge", .ops = &jump_ops, }, | ||
370 | { .name = "jnl", .ops = &jump_ops, }, | ||
371 | { .name = "jnle", .ops = &jump_ops, }, | ||
372 | { .name = "jno", .ops = &jump_ops, }, | ||
373 | { .name = "jnp", .ops = &jump_ops, }, | ||
374 | { .name = "jns", .ops = &jump_ops, }, | ||
375 | { .name = "jnz", .ops = &jump_ops, }, | ||
376 | { .name = "jo", .ops = &jump_ops, }, | ||
377 | { .name = "jp", .ops = &jump_ops, }, | ||
378 | { .name = "jpe", .ops = &jump_ops, }, | ||
379 | { .name = "jpo", .ops = &jump_ops, }, | ||
380 | { .name = "jrcxz", .ops = &jump_ops, }, | ||
381 | { .name = "js", .ops = &jump_ops, }, | ||
382 | { .name = "jz", .ops = &jump_ops, }, | ||
383 | { .name = "lea", .ops = &mov_ops, }, | ||
384 | { .name = "lock", .ops = &lock_ops, }, | ||
385 | { .name = "mov", .ops = &mov_ops, }, | ||
386 | { .name = "movb", .ops = &mov_ops, }, | ||
387 | { .name = "movdqa",.ops = &mov_ops, }, | ||
388 | { .name = "movl", .ops = &mov_ops, }, | ||
389 | { .name = "movq", .ops = &mov_ops, }, | ||
390 | { .name = "movslq", .ops = &mov_ops, }, | ||
391 | { .name = "movzbl", .ops = &mov_ops, }, | ||
392 | { .name = "movzwl", .ops = &mov_ops, }, | ||
393 | { .name = "nop", .ops = &nop_ops, }, | ||
394 | { .name = "nopl", .ops = &nop_ops, }, | ||
395 | { .name = "nopw", .ops = &nop_ops, }, | ||
396 | { .name = "or", .ops = &mov_ops, }, | ||
397 | { .name = "orl", .ops = &mov_ops, }, | ||
398 | { .name = "test", .ops = &mov_ops, }, | ||
399 | { .name = "testb", .ops = &mov_ops, }, | ||
400 | { .name = "testl", .ops = &mov_ops, }, | ||
401 | { .name = "xadd", .ops = &mov_ops, }, | ||
402 | }; | ||
403 | |||
404 | static int ins__cmp(const void *name, const void *insp) | ||
405 | { | ||
406 | const struct ins *ins = insp; | ||
407 | |||
408 | return strcmp(name, ins->name); | ||
409 | } | ||
410 | |||
411 | static struct ins *ins__find(const char *name) | ||
412 | { | ||
413 | const int nmemb = ARRAY_SIZE(instructions); | ||
414 | |||
415 | return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp); | ||
416 | } | ||
417 | |||
21 | int symbol__annotate_init(struct map *map __used, struct symbol *sym) | 418 | int symbol__annotate_init(struct map *map __used, struct symbol *sym) |
22 | { | 419 | { |
23 | struct annotation *notes = symbol__annotation(sym); | 420 | struct annotation *notes = symbol__annotation(sym); |
@@ -28,7 +425,7 @@ int symbol__annotate_init(struct map *map __used, struct symbol *sym) | |||
28 | int symbol__alloc_hist(struct symbol *sym) | 425 | int symbol__alloc_hist(struct symbol *sym) |
29 | { | 426 | { |
30 | struct annotation *notes = symbol__annotation(sym); | 427 | struct annotation *notes = symbol__annotation(sym); |
31 | const size_t size = sym->end - sym->start + 1; | 428 | const size_t size = symbol__size(sym); |
32 | size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); | 429 | size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); |
33 | 430 | ||
34 | notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); | 431 | notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); |
@@ -78,31 +475,110 @@ int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | |||
78 | return 0; | 475 | return 0; |
79 | } | 476 | } |
80 | 477 | ||
81 | static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize) | 478 | static void disasm_line__init_ins(struct disasm_line *dl) |
479 | { | ||
480 | dl->ins = ins__find(dl->name); | ||
481 | |||
482 | if (dl->ins == NULL) | ||
483 | return; | ||
484 | |||
485 | if (!dl->ins->ops) | ||
486 | return; | ||
487 | |||
488 | if (dl->ins->ops->parse) | ||
489 | dl->ins->ops->parse(&dl->ops); | ||
490 | } | ||
491 | |||
492 | static int disasm_line__parse(char *line, char **namep, char **rawp) | ||
493 | { | ||
494 | char *name = line, tmp; | ||
495 | |||
496 | while (isspace(name[0])) | ||
497 | ++name; | ||
498 | |||
499 | if (name[0] == '\0') | ||
500 | return -1; | ||
501 | |||
502 | *rawp = name + 1; | ||
503 | |||
504 | while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) | ||
505 | ++*rawp; | ||
506 | |||
507 | tmp = (*rawp)[0]; | ||
508 | (*rawp)[0] = '\0'; | ||
509 | *namep = strdup(name); | ||
510 | |||
511 | if (*namep == NULL) | ||
512 | goto out_free_name; | ||
513 | |||
514 | (*rawp)[0] = tmp; | ||
515 | |||
516 | if ((*rawp)[0] != '\0') { | ||
517 | (*rawp)++; | ||
518 | while (isspace((*rawp)[0])) | ||
519 | ++(*rawp); | ||
520 | } | ||
521 | |||
522 | return 0; | ||
523 | |||
524 | out_free_name: | ||
525 | free(*namep); | ||
526 | *namep = NULL; | ||
527 | return -1; | ||
528 | } | ||
529 | |||
530 | static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) | ||
82 | { | 531 | { |
83 | struct objdump_line *self = malloc(sizeof(*self) + privsize); | 532 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); |
84 | 533 | ||
85 | if (self != NULL) { | 534 | if (dl != NULL) { |
86 | self->offset = offset; | 535 | dl->offset = offset; |
87 | self->line = line; | 536 | dl->line = strdup(line); |
537 | if (dl->line == NULL) | ||
538 | goto out_delete; | ||
539 | |||
540 | if (offset != -1) { | ||
541 | if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) | ||
542 | goto out_free_line; | ||
543 | |||
544 | disasm_line__init_ins(dl); | ||
545 | } | ||
88 | } | 546 | } |
89 | 547 | ||
90 | return self; | 548 | return dl; |
549 | |||
550 | out_free_line: | ||
551 | free(dl->line); | ||
552 | out_delete: | ||
553 | free(dl); | ||
554 | return NULL; | ||
555 | } | ||
556 | |||
557 | void disasm_line__free(struct disasm_line *dl) | ||
558 | { | ||
559 | free(dl->line); | ||
560 | free(dl->name); | ||
561 | if (dl->ins && dl->ins->ops->free) | ||
562 | dl->ins->ops->free(&dl->ops); | ||
563 | else | ||
564 | ins__delete(&dl->ops); | ||
565 | free(dl); | ||
91 | } | 566 | } |
92 | 567 | ||
93 | void objdump_line__free(struct objdump_line *self) | 568 | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) |
94 | { | 569 | { |
95 | free(self->line); | 570 | if (raw || !dl->ins) |
96 | free(self); | 571 | return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); |
572 | |||
573 | return ins__scnprintf(dl->ins, bf, size, &dl->ops); | ||
97 | } | 574 | } |
98 | 575 | ||
99 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | 576 | static void disasm__add(struct list_head *head, struct disasm_line *line) |
100 | { | 577 | { |
101 | list_add_tail(&line->node, head); | 578 | list_add_tail(&line->node, head); |
102 | } | 579 | } |
103 | 580 | ||
104 | struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | 581 | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) |
105 | struct objdump_line *pos) | ||
106 | { | 582 | { |
107 | list_for_each_entry_continue(pos, head, node) | 583 | list_for_each_entry_continue(pos, head, node) |
108 | if (pos->offset >= 0) | 584 | if (pos->offset >= 0) |
@@ -111,15 +587,14 @@ struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | |||
111 | return NULL; | 587 | return NULL; |
112 | } | 588 | } |
113 | 589 | ||
114 | static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, | 590 | static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start, |
115 | int evidx, u64 len, int min_pcnt, | 591 | int evidx, u64 len, int min_pcnt, int printed, |
116 | int printed, int max_lines, | 592 | int max_lines, struct disasm_line *queue) |
117 | struct objdump_line *queue) | ||
118 | { | 593 | { |
119 | static const char *prev_line; | 594 | static const char *prev_line; |
120 | static const char *prev_color; | 595 | static const char *prev_color; |
121 | 596 | ||
122 | if (oline->offset != -1) { | 597 | if (dl->offset != -1) { |
123 | const char *path = NULL; | 598 | const char *path = NULL; |
124 | unsigned int hits = 0; | 599 | unsigned int hits = 0; |
125 | double percent = 0.0; | 600 | double percent = 0.0; |
@@ -127,10 +602,11 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, | |||
127 | struct annotation *notes = symbol__annotation(sym); | 602 | struct annotation *notes = symbol__annotation(sym); |
128 | struct source_line *src_line = notes->src->lines; | 603 | struct source_line *src_line = notes->src->lines; |
129 | struct sym_hist *h = annotation__histogram(notes, evidx); | 604 | struct sym_hist *h = annotation__histogram(notes, evidx); |
130 | s64 offset = oline->offset; | 605 | s64 offset = dl->offset; |
131 | struct objdump_line *next; | 606 | const u64 addr = start + offset; |
607 | struct disasm_line *next; | ||
132 | 608 | ||
133 | next = objdump__get_next_ip_line(¬es->src->source, oline); | 609 | next = disasm__get_next_ip_line(¬es->src->source, dl); |
134 | 610 | ||
135 | while (offset < (s64)len && | 611 | while (offset < (s64)len && |
136 | (next == NULL || offset < next->offset)) { | 612 | (next == NULL || offset < next->offset)) { |
@@ -155,9 +631,9 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, | |||
155 | 631 | ||
156 | if (queue != NULL) { | 632 | if (queue != NULL) { |
157 | list_for_each_entry_from(queue, ¬es->src->source, node) { | 633 | list_for_each_entry_from(queue, ¬es->src->source, node) { |
158 | if (queue == oline) | 634 | if (queue == dl) |
159 | break; | 635 | break; |
160 | objdump_line__print(queue, sym, evidx, len, | 636 | disasm_line__print(queue, sym, start, evidx, len, |
161 | 0, 0, 1, NULL); | 637 | 0, 0, 1, NULL); |
162 | } | 638 | } |
163 | } | 639 | } |
@@ -180,17 +656,18 @@ static int objdump_line__print(struct objdump_line *oline, struct symbol *sym, | |||
180 | 656 | ||
181 | color_fprintf(stdout, color, " %7.2f", percent); | 657 | color_fprintf(stdout, color, " %7.2f", percent); |
182 | printf(" : "); | 658 | printf(" : "); |
183 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line); | 659 | color_fprintf(stdout, PERF_COLOR_MAGENTA, " %" PRIx64 ":", addr); |
660 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); | ||
184 | } else if (max_lines && printed >= max_lines) | 661 | } else if (max_lines && printed >= max_lines) |
185 | return 1; | 662 | return 1; |
186 | else { | 663 | else { |
187 | if (queue) | 664 | if (queue) |
188 | return -1; | 665 | return -1; |
189 | 666 | ||
190 | if (!*oline->line) | 667 | if (!*dl->line) |
191 | printf(" :\n"); | 668 | printf(" :\n"); |
192 | else | 669 | else |
193 | printf(" : %s\n", oline->line); | 670 | printf(" : %s\n", dl->line); |
194 | } | 671 | } |
195 | 672 | ||
196 | return 0; | 673 | return 0; |
@@ -200,8 +677,8 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
200 | FILE *file, size_t privsize) | 677 | FILE *file, size_t privsize) |
201 | { | 678 | { |
202 | struct annotation *notes = symbol__annotation(sym); | 679 | struct annotation *notes = symbol__annotation(sym); |
203 | struct objdump_line *objdump_line; | 680 | struct disasm_line *dl; |
204 | char *line = NULL, *tmp, *tmp2, *c; | 681 | char *line = NULL, *parsed_line, *tmp, *tmp2, *c; |
205 | size_t line_len; | 682 | size_t line_len; |
206 | s64 line_ip, offset = -1; | 683 | s64 line_ip, offset = -1; |
207 | 684 | ||
@@ -219,6 +696,7 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
219 | *c = 0; | 696 | *c = 0; |
220 | 697 | ||
221 | line_ip = -1; | 698 | line_ip = -1; |
699 | parsed_line = line; | ||
222 | 700 | ||
223 | /* | 701 | /* |
224 | * Strip leading spaces: | 702 | * Strip leading spaces: |
@@ -246,14 +724,17 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | |||
246 | offset = line_ip - start; | 724 | offset = line_ip - start; |
247 | if (offset < 0 || (u64)line_ip > end) | 725 | if (offset < 0 || (u64)line_ip > end) |
248 | offset = -1; | 726 | offset = -1; |
727 | else | ||
728 | parsed_line = tmp2 + 1; | ||
249 | } | 729 | } |
250 | 730 | ||
251 | objdump_line = objdump_line__new(offset, line, privsize); | 731 | dl = disasm_line__new(offset, parsed_line, privsize); |
252 | if (objdump_line == NULL) { | 732 | free(line); |
253 | free(line); | 733 | |
734 | if (dl == NULL) | ||
254 | return -1; | 735 | return -1; |
255 | } | 736 | |
256 | objdump__add_line(¬es->src->source, objdump_line); | 737 | disasm__add(¬es->src->source, dl); |
257 | 738 | ||
258 | return 0; | 739 | return 0; |
259 | } | 740 | } |
@@ -476,7 +957,7 @@ static void symbol__annotate_hits(struct symbol *sym, int evidx) | |||
476 | { | 957 | { |
477 | struct annotation *notes = symbol__annotation(sym); | 958 | struct annotation *notes = symbol__annotation(sym); |
478 | struct sym_hist *h = annotation__histogram(notes, evidx); | 959 | struct sym_hist *h = annotation__histogram(notes, evidx); |
479 | u64 len = sym->end - sym->start, offset; | 960 | u64 len = symbol__size(sym), offset; |
480 | 961 | ||
481 | for (offset = 0; offset < len; ++offset) | 962 | for (offset = 0; offset < len; ++offset) |
482 | if (h->addr[offset] != 0) | 963 | if (h->addr[offset] != 0) |
@@ -492,7 +973,8 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
492 | struct dso *dso = map->dso; | 973 | struct dso *dso = map->dso; |
493 | const char *filename = dso->long_name, *d_filename; | 974 | const char *filename = dso->long_name, *d_filename; |
494 | struct annotation *notes = symbol__annotation(sym); | 975 | struct annotation *notes = symbol__annotation(sym); |
495 | struct objdump_line *pos, *queue = NULL; | 976 | struct disasm_line *pos, *queue = NULL; |
977 | u64 start = map__rip_2objdump(map, sym->start); | ||
496 | int printed = 2, queue_len = 0; | 978 | int printed = 2, queue_len = 0; |
497 | int more = 0; | 979 | int more = 0; |
498 | u64 len; | 980 | u64 len; |
@@ -502,7 +984,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
502 | else | 984 | else |
503 | d_filename = basename(filename); | 985 | d_filename = basename(filename); |
504 | 986 | ||
505 | len = sym->end - sym->start; | 987 | len = symbol__size(sym); |
506 | 988 | ||
507 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); | 989 | printf(" Percent | Source code & Disassembly of %s\n", d_filename); |
508 | printf("------------------------------------------------\n"); | 990 | printf("------------------------------------------------\n"); |
@@ -516,8 +998,9 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | |||
516 | queue_len = 0; | 998 | queue_len = 0; |
517 | } | 999 | } |
518 | 1000 | ||
519 | switch (objdump_line__print(pos, sym, evidx, len, min_pcnt, | 1001 | switch (disasm_line__print(pos, sym, start, evidx, len, |
520 | printed, max_lines, queue)) { | 1002 | min_pcnt, printed, max_lines, |
1003 | queue)) { | ||
521 | case 0: | 1004 | case 0: |
522 | ++printed; | 1005 | ++printed; |
523 | if (context) { | 1006 | if (context) { |
@@ -561,7 +1044,7 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) | |||
561 | { | 1044 | { |
562 | struct annotation *notes = symbol__annotation(sym); | 1045 | struct annotation *notes = symbol__annotation(sym); |
563 | struct sym_hist *h = annotation__histogram(notes, evidx); | 1046 | struct sym_hist *h = annotation__histogram(notes, evidx); |
564 | int len = sym->end - sym->start, offset; | 1047 | int len = symbol__size(sym), offset; |
565 | 1048 | ||
566 | h->sum = 0; | 1049 | h->sum = 0; |
567 | for (offset = 0; offset < len; ++offset) { | 1050 | for (offset = 0; offset < len; ++offset) { |
@@ -570,14 +1053,42 @@ void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) | |||
570 | } | 1053 | } |
571 | } | 1054 | } |
572 | 1055 | ||
573 | void objdump_line_list__purge(struct list_head *head) | 1056 | void disasm__purge(struct list_head *head) |
574 | { | 1057 | { |
575 | struct objdump_line *pos, *n; | 1058 | struct disasm_line *pos, *n; |
576 | 1059 | ||
577 | list_for_each_entry_safe(pos, n, head, node) { | 1060 | list_for_each_entry_safe(pos, n, head, node) { |
578 | list_del(&pos->node); | 1061 | list_del(&pos->node); |
579 | objdump_line__free(pos); | 1062 | disasm_line__free(pos); |
1063 | } | ||
1064 | } | ||
1065 | |||
1066 | static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp) | ||
1067 | { | ||
1068 | size_t printed; | ||
1069 | |||
1070 | if (dl->offset == -1) | ||
1071 | return fprintf(fp, "%s\n", dl->line); | ||
1072 | |||
1073 | printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name); | ||
1074 | |||
1075 | if (dl->ops.raw[0] != '\0') { | ||
1076 | printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", | ||
1077 | dl->ops.raw); | ||
580 | } | 1078 | } |
1079 | |||
1080 | return printed + fprintf(fp, "\n"); | ||
1081 | } | ||
1082 | |||
1083 | size_t disasm__fprintf(struct list_head *head, FILE *fp) | ||
1084 | { | ||
1085 | struct disasm_line *pos; | ||
1086 | size_t printed = 0; | ||
1087 | |||
1088 | list_for_each_entry(pos, head, node) | ||
1089 | printed += disasm_line__fprintf(pos, fp); | ||
1090 | |||
1091 | return printed; | ||
581 | } | 1092 | } |
582 | 1093 | ||
583 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | 1094 | int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, |
@@ -592,7 +1103,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
592 | if (symbol__annotate(sym, map, 0) < 0) | 1103 | if (symbol__annotate(sym, map, 0) < 0) |
593 | return -1; | 1104 | return -1; |
594 | 1105 | ||
595 | len = sym->end - sym->start; | 1106 | len = symbol__size(sym); |
596 | 1107 | ||
597 | if (print_lines) { | 1108 | if (print_lines) { |
598 | symbol__get_source_line(sym, map, evidx, &source_line, | 1109 | symbol__get_source_line(sym, map, evidx, &source_line, |
@@ -605,7 +1116,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx, | |||
605 | if (print_lines) | 1116 | if (print_lines) |
606 | symbol__free_source_line(sym, len); | 1117 | symbol__free_source_line(sym, len); |
607 | 1118 | ||
608 | objdump_line_list__purge(&symbol__annotation(sym)->src->source); | 1119 | disasm__purge(&symbol__annotation(sym)->src->source); |
609 | 1120 | ||
610 | return 0; | 1121 | return 0; |
611 | } | 1122 | } |