blob: aef841706dffd47f6e6a44bdee50e61ec5a7647b [file] [log] [blame]
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001/*
2 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3 *
4 * Parts came from builtin-annotate.c, see those files for further
5 * copyright notes.
6 *
7 * Released under the GPL v2. (and only v2, not any later version)
8 */
9
10#include "util.h"
Namhyung Kim48c65bd2014-02-20 10:32:53 +090011#include "ui/ui.h"
12#include "sort.h"
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -020013#include "build-id.h"
14#include "color.h"
15#include "cache.h"
16#include "symbol.h"
17#include "debug.h"
18#include "annotate.h"
Namhyung Kimdb8fd072013-03-05 14:53:21 +090019#include "evsel.h"
Peter Zijlstra70fbe052016-09-05 16:08:12 -030020#include "block-range.h"
Andi Kleene5924882014-11-12 18:05:26 -080021#include <regex.h>
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -020022#include <pthread.h>
Jiri Olsa4383db82012-10-27 23:18:29 +020023#include <linux/bitops.h>
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -020024
Andi Kleenf69b64f2011-09-15 14:31:41 -070025const char *disassembler_style;
Maciek Borzecki7a4ec932012-09-04 12:32:30 +020026const char *objdump_path;
Andi Kleene5924882014-11-12 18:05:26 -080027static regex_t file_lineno;
Andi Kleenf69b64f2011-09-15 14:31:41 -070028
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -030029static struct ins *ins__find(const char *name);
30static int disasm_line__parse(char *line, char **namep, char **rawp);
31
Arnaldo Carvalho de Meloc46219ac2012-05-12 13:26:20 -030032static void ins__delete(struct ins_operands *ops)
33{
Arnaldo Carvalho de Melo39956142015-03-05 15:27:28 -030034 if (ops == NULL)
35 return;
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -030036 zfree(&ops->source.raw);
37 zfree(&ops->source.name);
38 zfree(&ops->target.raw);
39 zfree(&ops->target.name);
Arnaldo Carvalho de Meloc46219ac2012-05-12 13:26:20 -030040}
41
Arnaldo Carvalho de Melo54170722012-05-07 18:54:16 -030042static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
43 struct ins_operands *ops)
44{
45 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
46}
47
48int ins__scnprintf(struct ins *ins, char *bf, size_t size,
49 struct ins_operands *ops)
50{
51 if (ins->ops->scnprintf)
52 return ins->ops->scnprintf(ins, bf, size, ops);
53
54 return ins__raw_scnprintf(ins, bf, size, ops);
55}
56
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -030057static int call__parse(struct ins_operands *ops, struct map *map __maybe_unused)
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -030058{
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030059 char *endptr, *tok, *name;
60
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -030061 ops->target.addr = strtoull(ops->raw, &endptr, 16);
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030062
63 name = strchr(endptr, '<');
64 if (name == NULL)
65 goto indirect_call;
66
67 name++;
68
Russell Kingcfef25b2015-12-06 23:07:13 +000069#ifdef __arm__
70 if (strchr(name, '+'))
71 return -1;
72#endif
73
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030074 tok = strchr(name, '>');
75 if (tok == NULL)
76 return -1;
77
78 *tok = '\0';
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -030079 ops->target.name = strdup(name);
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030080 *tok = '>';
81
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -030082 return ops->target.name == NULL ? -1 : 0;
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030083
84indirect_call:
Ravi Bangoria88a7fcf2016-08-19 18:29:35 +053085 tok = strchr(endptr, '*');
86 if (tok == NULL) {
Arnaldo Carvalho de Meloe8ea1562012-05-11 12:28:55 -030087 ops->target.addr = 0;
88 return 0;
89 }
90
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -030091 ops->target.addr = strtoull(tok + 1, NULL, 16);
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -030092 return 0;
93}
94
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030095static int call__scnprintf(struct ins *ins, char *bf, size_t size,
Arnaldo Carvalho de Melo54170722012-05-07 18:54:16 -030096 struct ins_operands *ops)
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -030097{
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -030098 if (ops->target.name)
99 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -0300100
Arnaldo Carvalho de Meloe8ea1562012-05-11 12:28:55 -0300101 if (ops->target.addr == 0)
102 return ins__raw_scnprintf(ins, bf, size, ops);
103
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300104 return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -0300105}
106
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300107static struct ins_ops call_ops = {
Arnaldo Carvalho de Melod2232882012-04-20 15:26:47 -0300108 .parse = call__parse,
109 .scnprintf = call__scnprintf,
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300110};
111
112bool ins__is_call(const struct ins *ins)
113{
114 return ins->ops == &call_ops;
115}
116
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300117static int jump__parse(struct ins_operands *ops, struct map *map __maybe_unused)
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300118{
Arnaldo Carvalho de Meloc7e6ead2012-04-20 14:38:46 -0300119 const char *s = strchr(ops->raw, '+');
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300120
Adrian Hunterbbb7f842013-08-07 14:38:54 +0300121 ops->target.addr = strtoull(ops->raw, NULL, 16);
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300122
Arnaldo Carvalho de Melofb29fa582012-04-25 14:16:03 -0300123 if (s++ != NULL)
Adrian Hunterbbb7f842013-08-07 14:38:54 +0300124 ops->target.offset = strtoull(s, NULL, 16);
Arnaldo Carvalho de Melofb29fa582012-04-25 14:16:03 -0300125 else
126 ops->target.offset = UINT64_MAX;
127
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300128 return 0;
129}
130
Arnaldo Carvalho de Meloc7e6ead2012-04-20 14:38:46 -0300131static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
Arnaldo Carvalho de Melo54170722012-05-07 18:54:16 -0300132 struct ins_operands *ops)
Arnaldo Carvalho de Melo28548d72012-04-19 10:16:27 -0300133{
Arnaldo Carvalho de Melo44d1a3e2012-04-25 08:00:23 -0300134 return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
Arnaldo Carvalho de Melo28548d72012-04-19 10:16:27 -0300135}
136
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300137static struct ins_ops jump_ops = {
Arnaldo Carvalho de Meloc7e6ead2012-04-20 14:38:46 -0300138 .parse = jump__parse,
139 .scnprintf = jump__scnprintf,
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300140};
141
142bool ins__is_jump(const struct ins *ins)
143{
144 return ins->ops == &jump_ops;
145}
146
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300147static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
148{
149 char *endptr, *name, *t;
150
151 if (strstr(raw, "(%rip)") == NULL)
152 return 0;
153
154 *addrp = strtoull(comment, &endptr, 16);
155 name = strchr(endptr, '<');
156 if (name == NULL)
157 return -1;
158
159 name++;
160
161 t = strchr(name, '>');
162 if (t == NULL)
163 return 0;
164
165 *t = '\0';
166 *namep = strdup(name);
167 *t = '>';
168
169 return 0;
170}
171
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300172static int lock__parse(struct ins_operands *ops, struct map *map)
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300173{
174 char *name;
175
176 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
177 if (ops->locked.ops == NULL)
178 return 0;
179
180 if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0)
181 goto out_free_ops;
182
Namhyung Kim2ba34aa2012-11-10 02:27:13 +0900183 ops->locked.ins = ins__find(name);
Rabin Vincent0fb9f2a2015-01-18 20:00:21 +0100184 free(name);
185
Namhyung Kim2ba34aa2012-11-10 02:27:13 +0900186 if (ops->locked.ins == NULL)
187 goto out_free_ops;
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300188
Namhyung Kim2ba34aa2012-11-10 02:27:13 +0900189 if (!ops->locked.ins->ops)
190 return 0;
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300191
Rabin Vincentbe819082015-01-18 20:00:20 +0100192 if (ops->locked.ins->ops->parse &&
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300193 ops->locked.ins->ops->parse(ops->locked.ops, map) < 0)
Rabin Vincentbe819082015-01-18 20:00:20 +0100194 goto out_free_ops;
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300195
196 return 0;
197
198out_free_ops:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300199 zfree(&ops->locked.ops);
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300200 return 0;
201}
202
203static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
204 struct ins_operands *ops)
205{
206 int printed;
207
208 if (ops->locked.ins == NULL)
209 return ins__raw_scnprintf(ins, bf, size, ops);
210
211 printed = scnprintf(bf, size, "%-6.6s ", ins->name);
212 return printed + ins__scnprintf(ops->locked.ins, bf + printed,
213 size - printed, ops->locked.ops);
214}
215
Arnaldo Carvalho de Meloc46219ac2012-05-12 13:26:20 -0300216static void lock__delete(struct ins_operands *ops)
217{
Rabin Vincent0fb9f2a2015-01-18 20:00:21 +0100218 struct ins *ins = ops->locked.ins;
219
220 if (ins && ins->ops->free)
221 ins->ops->free(ops->locked.ops);
222 else
223 ins__delete(ops->locked.ops);
224
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -0300225 zfree(&ops->locked.ops);
226 zfree(&ops->target.raw);
227 zfree(&ops->target.name);
Arnaldo Carvalho de Meloc46219ac2012-05-12 13:26:20 -0300228}
229
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300230static struct ins_ops lock_ops = {
Arnaldo Carvalho de Meloc46219ac2012-05-12 13:26:20 -0300231 .free = lock__delete,
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300232 .parse = lock__parse,
233 .scnprintf = lock__scnprintf,
234};
235
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300236static int mov__parse(struct ins_operands *ops, struct map *map __maybe_unused)
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300237{
238 char *s = strchr(ops->raw, ','), *target, *comment, prev;
239
240 if (s == NULL)
241 return -1;
242
243 *s = '\0';
244 ops->source.raw = strdup(ops->raw);
245 *s = ',';
Arnaldo Carvalho de Melo48000a12014-12-17 17:24:45 -0300246
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300247 if (ops->source.raw == NULL)
248 return -1;
249
250 target = ++s;
Russell Kingcfef25b2015-12-06 23:07:13 +0000251#ifdef __arm__
252 comment = strchr(s, ';');
253#else
Alex Converse1e2bb042014-08-14 14:03:00 -0700254 comment = strchr(s, '#');
Russell Kingcfef25b2015-12-06 23:07:13 +0000255#endif
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300256
Alex Converse1e2bb042014-08-14 14:03:00 -0700257 if (comment != NULL)
258 s = comment - 1;
259 else
260 s = strchr(s, '\0') - 1;
261
262 while (s > target && isspace(s[0]))
263 --s;
264 s++;
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300265 prev = *s;
266 *s = '\0';
267
268 ops->target.raw = strdup(target);
269 *s = prev;
270
271 if (ops->target.raw == NULL)
272 goto out_free_source;
273
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300274 if (comment == NULL)
275 return 0;
276
277 while (comment[0] != '\0' && isspace(comment[0]))
278 ++comment;
279
280 comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name);
281 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
282
283 return 0;
284
285out_free_source:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300286 zfree(&ops->source.raw);
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300287 return -1;
288}
289
290static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
291 struct ins_operands *ops)
292{
293 return scnprintf(bf, size, "%-6.6s %s,%s", ins->name,
294 ops->source.name ?: ops->source.raw,
295 ops->target.name ?: ops->target.raw);
296}
297
298static struct ins_ops mov_ops = {
299 .parse = mov__parse,
300 .scnprintf = mov__scnprintf,
301};
302
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300303static int dec__parse(struct ins_operands *ops, struct map *map __maybe_unused)
Arnaldo Carvalho de Meloa43712c2012-05-11 17:21:09 -0300304{
305 char *target, *comment, *s, prev;
306
307 target = s = ops->raw;
308
309 while (s[0] != '\0' && !isspace(s[0]))
310 ++s;
311 prev = *s;
312 *s = '\0';
313
314 ops->target.raw = strdup(target);
315 *s = prev;
316
317 if (ops->target.raw == NULL)
318 return -1;
319
320 comment = strchr(s, '#');
321 if (comment == NULL)
322 return 0;
323
324 while (comment[0] != '\0' && isspace(comment[0]))
325 ++comment;
326
327 comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name);
328
329 return 0;
330}
331
332static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
333 struct ins_operands *ops)
334{
335 return scnprintf(bf, size, "%-6.6s %s", ins->name,
336 ops->target.name ?: ops->target.raw);
337}
338
339static struct ins_ops dec_ops = {
340 .parse = dec__parse,
341 .scnprintf = dec__scnprintf,
342};
343
Irina Tirdea1d037ca2012-09-11 01:15:03 +0300344static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
345 struct ins_operands *ops __maybe_unused)
Arnaldo Carvalho de Melob9818e92012-05-07 18:57:02 -0300346{
347 return scnprintf(bf, size, "%-6.6s", "nop");
348}
349
350static struct ins_ops nop_ops = {
351 .scnprintf = nop__scnprintf,
352};
353
Naveen N. Rao6ef94922016-06-24 17:23:58 +0530354static struct ins_ops ret_ops = {
355 .scnprintf = ins__raw_scnprintf,
356};
357
358bool ins__is_ret(const struct ins *ins)
359{
360 return ins->ops == &ret_ops;
361}
362
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300363static struct ins instructions[] = {
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300364 { .name = "add", .ops = &mov_ops, },
365 { .name = "addl", .ops = &mov_ops, },
366 { .name = "addq", .ops = &mov_ops, },
367 { .name = "addw", .ops = &mov_ops, },
368 { .name = "and", .ops = &mov_ops, },
Russell Kingcfef25b2015-12-06 23:07:13 +0000369#ifdef __arm__
370 { .name = "b", .ops = &jump_ops, }, // might also be a call
371 { .name = "bcc", .ops = &jump_ops, },
372 { .name = "bcs", .ops = &jump_ops, },
373 { .name = "beq", .ops = &jump_ops, },
374 { .name = "bge", .ops = &jump_ops, },
375 { .name = "bgt", .ops = &jump_ops, },
376 { .name = "bhi", .ops = &jump_ops, },
377 { .name = "bl", .ops = &call_ops, },
Russell Kingcfef25b2015-12-06 23:07:13 +0000378 { .name = "bls", .ops = &jump_ops, },
Chris Ryder58c04002016-05-19 17:59:45 +0100379 { .name = "blt", .ops = &jump_ops, },
Russell Kingcfef25b2015-12-06 23:07:13 +0000380 { .name = "blx", .ops = &call_ops, },
381 { .name = "bne", .ops = &jump_ops, },
382#endif
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300383 { .name = "bts", .ops = &mov_ops, },
Arnaldo Carvalho de Melod86b0592012-04-18 16:07:38 -0300384 { .name = "call", .ops = &call_ops, },
385 { .name = "callq", .ops = &call_ops, },
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300386 { .name = "cmp", .ops = &mov_ops, },
387 { .name = "cmpb", .ops = &mov_ops, },
388 { .name = "cmpl", .ops = &mov_ops, },
389 { .name = "cmpq", .ops = &mov_ops, },
390 { .name = "cmpw", .ops = &mov_ops, },
391 { .name = "cmpxch", .ops = &mov_ops, },
Arnaldo Carvalho de Meloa43712c2012-05-11 17:21:09 -0300392 { .name = "dec", .ops = &dec_ops, },
393 { .name = "decl", .ops = &dec_ops, },
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300394 { .name = "imul", .ops = &mov_ops, },
Arnaldo Carvalho de Meloa43712c2012-05-11 17:21:09 -0300395 { .name = "inc", .ops = &dec_ops, },
396 { .name = "incl", .ops = &dec_ops, },
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300397 { .name = "ja", .ops = &jump_ops, },
Arnaldo Carvalho de Melo3f862fd2012-04-19 17:10:12 -0300398 { .name = "jae", .ops = &jump_ops, },
399 { .name = "jb", .ops = &jump_ops, },
400 { .name = "jbe", .ops = &jump_ops, },
401 { .name = "jc", .ops = &jump_ops, },
402 { .name = "jcxz", .ops = &jump_ops, },
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300403 { .name = "je", .ops = &jump_ops, },
Arnaldo Carvalho de Melo3f862fd2012-04-19 17:10:12 -0300404 { .name = "jecxz", .ops = &jump_ops, },
405 { .name = "jg", .ops = &jump_ops, },
406 { .name = "jge", .ops = &jump_ops, },
407 { .name = "jl", .ops = &jump_ops, },
408 { .name = "jle", .ops = &jump_ops, },
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300409 { .name = "jmp", .ops = &jump_ops, },
410 { .name = "jmpq", .ops = &jump_ops, },
Arnaldo Carvalho de Melo3f862fd2012-04-19 17:10:12 -0300411 { .name = "jna", .ops = &jump_ops, },
412 { .name = "jnae", .ops = &jump_ops, },
413 { .name = "jnb", .ops = &jump_ops, },
414 { .name = "jnbe", .ops = &jump_ops, },
415 { .name = "jnc", .ops = &jump_ops, },
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300416 { .name = "jne", .ops = &jump_ops, },
Arnaldo Carvalho de Melo3f862fd2012-04-19 17:10:12 -0300417 { .name = "jng", .ops = &jump_ops, },
418 { .name = "jnge", .ops = &jump_ops, },
419 { .name = "jnl", .ops = &jump_ops, },
420 { .name = "jnle", .ops = &jump_ops, },
421 { .name = "jno", .ops = &jump_ops, },
422 { .name = "jnp", .ops = &jump_ops, },
423 { .name = "jns", .ops = &jump_ops, },
424 { .name = "jnz", .ops = &jump_ops, },
425 { .name = "jo", .ops = &jump_ops, },
426 { .name = "jp", .ops = &jump_ops, },
427 { .name = "jpe", .ops = &jump_ops, },
428 { .name = "jpo", .ops = &jump_ops, },
429 { .name = "jrcxz", .ops = &jump_ops, },
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300430 { .name = "js", .ops = &jump_ops, },
Arnaldo Carvalho de Melo3f862fd2012-04-19 17:10:12 -0300431 { .name = "jz", .ops = &jump_ops, },
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300432 { .name = "lea", .ops = &mov_ops, },
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300433 { .name = "lock", .ops = &lock_ops, },
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300434 { .name = "mov", .ops = &mov_ops, },
435 { .name = "movb", .ops = &mov_ops, },
436 { .name = "movdqa",.ops = &mov_ops, },
437 { .name = "movl", .ops = &mov_ops, },
438 { .name = "movq", .ops = &mov_ops, },
439 { .name = "movslq", .ops = &mov_ops, },
440 { .name = "movzbl", .ops = &mov_ops, },
441 { .name = "movzwl", .ops = &mov_ops, },
Arnaldo Carvalho de Melob9818e92012-05-07 18:57:02 -0300442 { .name = "nop", .ops = &nop_ops, },
443 { .name = "nopl", .ops = &nop_ops, },
444 { .name = "nopw", .ops = &nop_ops, },
Arnaldo Carvalho de Melo6de783b2012-05-11 16:48:49 -0300445 { .name = "or", .ops = &mov_ops, },
446 { .name = "orl", .ops = &mov_ops, },
447 { .name = "test", .ops = &mov_ops, },
448 { .name = "testb", .ops = &mov_ops, },
449 { .name = "testl", .ops = &mov_ops, },
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300450 { .name = "xadd", .ops = &mov_ops, },
Andi Kleenffadcf02012-10-30 17:34:08 -0700451 { .name = "xbeginl", .ops = &jump_ops, },
452 { .name = "xbeginq", .ops = &jump_ops, },
Naveen N. Rao6ef94922016-06-24 17:23:58 +0530453 { .name = "retq", .ops = &ret_ops, },
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300454};
455
Chris Ryder7e4c1492016-05-19 17:59:46 +0100456static int ins__key_cmp(const void *name, const void *insp)
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300457{
458 const struct ins *ins = insp;
459
460 return strcmp(name, ins->name);
461}
462
Chris Ryder7e4c1492016-05-19 17:59:46 +0100463static int ins__cmp(const void *a, const void *b)
464{
465 const struct ins *ia = a;
466 const struct ins *ib = b;
467
468 return strcmp(ia->name, ib->name);
469}
470
471static void ins__sort(void)
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300472{
473 const int nmemb = ARRAY_SIZE(instructions);
474
Chris Ryder7e4c1492016-05-19 17:59:46 +0100475 qsort(instructions, nmemb, sizeof(struct ins), ins__cmp);
476}
477
478static struct ins *ins__find(const char *name)
479{
480 const int nmemb = ARRAY_SIZE(instructions);
481 static bool sorted;
482
483 if (!sorted) {
484 ins__sort();
485 sorted = true;
486 }
487
488 return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__key_cmp);
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300489}
490
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200491int symbol__alloc_hist(struct symbol *sym)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200492{
493 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo1b2e2df2012-04-19 10:57:06 -0300494 const size_t size = symbol__size(sym);
Cody Schafer86963292012-07-19 20:05:25 -0700495 size_t sizeof_sym_hist;
496
497 /* Check for overflow when calculating sizeof_sym_hist */
498 if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64))
499 return -1;
500
501 sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
502
503 /* Check for overflow in zalloc argument */
504 if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src))
505 / symbol_conf.nr_events)
506 return -1;
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200507
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200508 notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200509 if (notes->src == NULL)
510 return -1;
511 notes->src->sizeof_sym_hist = sizeof_sym_hist;
Arnaldo Carvalho de Melod04b35f2011-11-11 22:17:32 -0200512 notes->src->nr_histograms = symbol_conf.nr_events;
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200513 INIT_LIST_HEAD(&notes->src->source);
514 return 0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200515}
516
Andi Kleend4957632015-07-18 08:24:48 -0700517/* The cycles histogram is lazily allocated. */
518static int symbol__alloc_hist_cycles(struct symbol *sym)
519{
520 struct annotation *notes = symbol__annotation(sym);
521 const size_t size = symbol__size(sym);
522
523 notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
524 if (notes->src->cycles_hist == NULL)
525 return -1;
526 return 0;
527}
528
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -0200529void symbol__annotate_zero_histograms(struct symbol *sym)
530{
531 struct annotation *notes = symbol__annotation(sym);
532
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200533 pthread_mutex_lock(&notes->lock);
Andi Kleend4957632015-07-18 08:24:48 -0700534 if (notes->src != NULL) {
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200535 memset(notes->src->histograms, 0,
536 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
Andi Kleend4957632015-07-18 08:24:48 -0700537 if (notes->src->cycles_hist)
538 memset(notes->src->cycles_hist, 0,
539 symbol__size(sym) * sizeof(struct cyc_hist));
540 }
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200541 pthread_mutex_unlock(&notes->lock);
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -0200542}
543
Andi Kleend4957632015-07-18 08:24:48 -0700544static int __symbol__account_cycles(struct annotation *notes,
545 u64 start,
546 unsigned offset, unsigned cycles,
547 unsigned have_start)
548{
549 struct cyc_hist *ch;
550
551 ch = notes->src->cycles_hist;
552 /*
553 * For now we can only account one basic block per
554 * final jump. But multiple could be overlapping.
555 * Always account the longest one. So when
556 * a shorter one has been already seen throw it away.
557 *
558 * We separately always account the full cycles.
559 */
560 ch[offset].num_aggr++;
561 ch[offset].cycles_aggr += cycles;
562
563 if (!have_start && ch[offset].have_start)
564 return 0;
565 if (ch[offset].num) {
566 if (have_start && (!ch[offset].have_start ||
567 ch[offset].start > start)) {
568 ch[offset].have_start = 0;
569 ch[offset].cycles = 0;
570 ch[offset].num = 0;
571 if (ch[offset].reset < 0xffff)
572 ch[offset].reset++;
573 } else if (have_start &&
574 ch[offset].start < start)
575 return 0;
576 }
577 ch[offset].have_start = have_start;
578 ch[offset].start = start;
579 ch[offset].cycles += cycles;
580 ch[offset].num++;
581 return 0;
582}
583
Arnaldo Carvalho de Melob66d8c02013-12-18 15:37:41 -0300584static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
585 struct annotation *notes, int evidx, u64 addr)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200586{
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -0200587 unsigned offset;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200588 struct sym_hist *h;
589
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200590 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
591
Arnaldo Carvalho de Meloe3d006c2015-10-21 15:45:13 -0300592 if (addr < sym->start || addr >= sym->end) {
593 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
594 __func__, __LINE__, sym->name, sym->start, addr, sym->end);
Arnaldo Carvalho de Melo31d68e72012-03-27 12:55:57 -0300595 return -ERANGE;
Arnaldo Carvalho de Meloe3d006c2015-10-21 15:45:13 -0300596 }
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200597
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -0200598 offset = addr - sym->start;
599 h = annotation__histogram(notes, evidx);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200600 h->sum++;
601 h->addr[offset]++;
602
603 pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
Arnaldo Carvalho de Melo2f525d02011-02-04 13:43:24 -0200604 ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
605 addr, addr - sym->start, evidx, h->addr[offset]);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200606 return 0;
607}
608
Andi Kleend4957632015-07-18 08:24:48 -0700609static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles)
Andi Kleen83be34a2015-05-27 10:51:46 -0700610{
611 struct annotation *notes = symbol__annotation(sym);
612
613 if (notes->src == NULL) {
614 if (symbol__alloc_hist(sym) < 0)
615 return NULL;
616 }
Andi Kleend4957632015-07-18 08:24:48 -0700617 if (!notes->src->cycles_hist && cycles) {
618 if (symbol__alloc_hist_cycles(sym) < 0)
619 return NULL;
620 }
Andi Kleen83be34a2015-05-27 10:51:46 -0700621 return notes;
622}
623
Arnaldo Carvalho de Melo44e83032013-12-18 17:12:24 -0300624static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
625 int evidx, u64 addr)
Arnaldo Carvalho de Melob66d8c02013-12-18 15:37:41 -0300626{
627 struct annotation *notes;
628
Namhyung Kim48c65bd2014-02-20 10:32:53 +0900629 if (sym == NULL)
Arnaldo Carvalho de Melob66d8c02013-12-18 15:37:41 -0300630 return 0;
Andi Kleend4957632015-07-18 08:24:48 -0700631 notes = symbol__get_annotation(sym, false);
Andi Kleen83be34a2015-05-27 10:51:46 -0700632 if (notes == NULL)
633 return -ENOMEM;
Arnaldo Carvalho de Melob66d8c02013-12-18 15:37:41 -0300634 return __symbol__inc_addr_samples(sym, map, notes, evidx, addr);
635}
636
Andi Kleend4957632015-07-18 08:24:48 -0700637static int symbol__account_cycles(u64 addr, u64 start,
638 struct symbol *sym, unsigned cycles)
639{
640 struct annotation *notes;
641 unsigned offset;
642
643 if (sym == NULL)
644 return 0;
645 notes = symbol__get_annotation(sym, true);
646 if (notes == NULL)
647 return -ENOMEM;
648 if (addr < sym->start || addr >= sym->end)
649 return -ERANGE;
650
651 if (start) {
652 if (start < sym->start || start >= sym->end)
653 return -ERANGE;
654 if (start >= addr)
655 start = 0;
656 }
657 offset = addr - sym->start;
658 return __symbol__account_cycles(notes,
659 start ? start - sym->start : 0,
660 offset, cycles,
661 !!start);
662}
663
664int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
665 struct addr_map_symbol *start,
666 unsigned cycles)
667{
Adrian Hunter3d7245b2015-08-14 10:11:34 +0300668 u64 saddr = 0;
Andi Kleend4957632015-07-18 08:24:48 -0700669 int err;
670
671 if (!cycles)
672 return 0;
673
674 /*
675 * Only set start when IPC can be computed. We can only
676 * compute it when the basic block is completely in a single
677 * function.
678 * Special case the case when the jump is elsewhere, but
679 * it starts on the function start.
680 */
681 if (start &&
682 (start->sym == ams->sym ||
683 (ams->sym &&
684 start->addr == ams->sym->start + ams->map->start)))
685 saddr = start->al_addr;
686 if (saddr == 0)
Adrian Hunter3d7245b2015-08-14 10:11:34 +0300687 pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n",
Andi Kleend4957632015-07-18 08:24:48 -0700688 ams->addr,
689 start ? start->addr : 0,
690 ams->sym ? ams->sym->start + ams->map->start : 0,
691 saddr);
692 err = symbol__account_cycles(ams->al_addr, saddr, ams->sym, cycles);
693 if (err)
694 pr_debug2("account_cycles failed %d\n", err);
695 return err;
696}
697
Arnaldo Carvalho de Melo0f4e7a22013-12-18 16:48:29 -0300698int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, int evidx)
699{
700 return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr);
701}
702
Arnaldo Carvalho de Melof626adf2013-12-18 17:10:15 -0300703int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
704{
705 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);
706}
707
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300708static void disasm_line__init_ins(struct disasm_line *dl, struct map *map)
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300709{
710 dl->ins = ins__find(dl->name);
711
712 if (dl->ins == NULL)
713 return;
714
715 if (!dl->ins->ops)
716 return;
717
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300718 if (dl->ins->ops->parse && dl->ins->ops->parse(&dl->ops, map) < 0)
Rabin Vincentbe819082015-01-18 20:00:20 +0100719 dl->ins = NULL;
Arnaldo Carvalho de Melo4f9d0322012-04-18 13:58:34 -0300720}
721
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300722static int disasm_line__parse(char *line, char **namep, char **rawp)
723{
724 char *name = line, tmp;
725
726 while (isspace(name[0]))
727 ++name;
728
729 if (name[0] == '\0')
730 return -1;
731
732 *rawp = name + 1;
733
734 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
735 ++*rawp;
736
737 tmp = (*rawp)[0];
738 (*rawp)[0] = '\0';
739 *namep = strdup(name);
740
741 if (*namep == NULL)
742 goto out_free_name;
743
744 (*rawp)[0] = tmp;
745
746 if ((*rawp)[0] != '\0') {
747 (*rawp)++;
748 while (isspace((*rawp)[0]))
749 ++(*rawp);
750 }
751
752 return 0;
753
754out_free_name:
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -0300755 zfree(namep);
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300756 return -1;
757}
758
Andi Kleene5924882014-11-12 18:05:26 -0800759static struct disasm_line *disasm_line__new(s64 offset, char *line,
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300760 size_t privsize, int line_nr,
761 struct map *map)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200762{
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -0300763 struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200764
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300765 if (dl != NULL) {
766 dl->offset = offset;
767 dl->line = strdup(line);
Andi Kleene5924882014-11-12 18:05:26 -0800768 dl->line_nr = line_nr;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300769 if (dl->line == NULL)
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300770 goto out_delete;
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -0300771
772 if (offset != -1) {
Arnaldo Carvalho de Melo7a997fe2012-05-12 13:15:34 -0300773 if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0)
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -0300774 goto out_free_line;
775
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -0300776 disasm_line__init_ins(dl, map);
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -0300777 }
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200778 }
779
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300780 return dl;
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -0300781
782out_free_line:
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -0300783 zfree(&dl->line);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300784out_delete:
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300785 free(dl);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300786 return NULL;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200787}
788
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300789void disasm_line__free(struct disasm_line *dl)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200790{
Arnaldo Carvalho de Melo74cf2492013-12-27 16:55:14 -0300791 zfree(&dl->line);
792 zfree(&dl->name);
Arnaldo Carvalho de Meloc46219ac2012-05-12 13:26:20 -0300793 if (dl->ins && dl->ins->ops->free)
794 dl->ins->ops->free(&dl->ops);
795 else
796 ins__delete(&dl->ops);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300797 free(dl);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200798}
799
Arnaldo Carvalho de Melo54170722012-05-07 18:54:16 -0300800int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
801{
802 if (raw || !dl->ins)
803 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
804
805 return ins__scnprintf(dl->ins, bf, size, &dl->ops);
806}
807
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300808static void disasm__add(struct list_head *head, struct disasm_line *line)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200809{
810 list_add_tail(&line->node, head);
811}
812
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300813struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200814{
815 list_for_each_entry_continue(pos, head, node)
816 if (pos->offset >= 0)
817 return pos;
818
819 return NULL;
820}
821
Namhyung Kime64aa752013-03-05 14:53:30 +0900822double disasm__calc_percent(struct annotation *notes, int evidx, s64 offset,
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300823 s64 end, const char **path, u64 *nr_samples)
Namhyung Kime5ccf9f2013-03-05 14:53:23 +0900824{
825 struct source_line *src_line = notes->src->lines;
Namhyung Kime5ccf9f2013-03-05 14:53:23 +0900826 double percent = 0.0;
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300827 *nr_samples = 0;
Namhyung Kime5ccf9f2013-03-05 14:53:23 +0900828
Namhyung Kimbd64fcb2013-03-05 14:53:24 +0900829 if (src_line) {
Namhyung Kim1491c222013-03-05 14:53:28 +0900830 size_t sizeof_src_line = sizeof(*src_line) +
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -0300831 sizeof(src_line->samples) * (src_line->nr_pcnt - 1);
Namhyung Kime5ccf9f2013-03-05 14:53:23 +0900832
Namhyung Kim1491c222013-03-05 14:53:28 +0900833 while (offset < end) {
834 src_line = (void *)notes->src->lines +
835 (sizeof_src_line * offset);
836
837 if (*path == NULL)
838 *path = src_line->path;
839
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -0300840 percent += src_line->samples[evidx].percent;
841 *nr_samples += src_line->samples[evidx].nr;
Namhyung Kim1491c222013-03-05 14:53:28 +0900842 offset++;
Namhyung Kimbd64fcb2013-03-05 14:53:24 +0900843 }
844 } else {
Namhyung Kim1491c222013-03-05 14:53:28 +0900845 struct sym_hist *h = annotation__histogram(notes, evidx);
846 unsigned int hits = 0;
847
Namhyung Kimbd64fcb2013-03-05 14:53:24 +0900848 while (offset < end)
849 hits += h->addr[offset++];
850
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300851 if (h->sum) {
852 *nr_samples = hits;
Namhyung Kimbd64fcb2013-03-05 14:53:24 +0900853 percent = 100.0 * hits / h->sum;
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300854 }
Namhyung Kime5ccf9f2013-03-05 14:53:23 +0900855 }
856
Namhyung Kime5ccf9f2013-03-05 14:53:23 +0900857 return percent;
858}
859
Peter Zijlstra70fbe052016-09-05 16:08:12 -0300860static const char *annotate__address_color(struct block_range *br)
861{
862 double cov = block_range__coverage(br);
863
864 if (cov >= 0) {
865 /* mark red for >75% coverage */
866 if (cov > 0.75)
867 return PERF_COLOR_RED;
868
869 /* mark dull for <1% coverage */
870 if (cov < 0.01)
871 return PERF_COLOR_NORMAL;
872 }
873
874 return PERF_COLOR_MAGENTA;
875}
876
877static const char *annotate__asm_color(struct block_range *br)
878{
879 double cov = block_range__coverage(br);
880
881 if (cov >= 0) {
882 /* mark dull for <1% coverage */
883 if (cov < 0.01)
884 return PERF_COLOR_NORMAL;
885 }
886
887 return PERF_COLOR_BLUE;
888}
889
890static void annotate__branch_printf(struct block_range *br, u64 addr)
891{
892 bool emit_comment = true;
893
894 if (!br)
895 return;
896
897#if 1
898 if (br->is_target && br->start == addr) {
899 struct block_range *branch = br;
900 double p;
901
902 /*
903 * Find matching branch to our target.
904 */
905 while (!branch->is_branch)
906 branch = block_range__next(branch);
907
908 p = 100 *(double)br->entry / branch->coverage;
909
910 if (p > 0.1) {
911 if (emit_comment) {
912 emit_comment = false;
913 printf("\t#");
914 }
915
916 /*
917 * The percentage of coverage joined at this target in relation
918 * to the next branch.
919 */
920 printf(" +%.2f%%", p);
921 }
922 }
923#endif
924 if (br->is_branch && br->end == addr) {
925 double p = 100*(double)br->taken / br->coverage;
926
927 if (p > 0.1) {
928 if (emit_comment) {
929 emit_comment = false;
930 printf("\t#");
931 }
932
933 /*
934 * The percentage of coverage leaving at this branch, and
935 * its prediction ratio.
936 */
937 printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred / br->taken);
938 }
939 }
940}
941
942
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300943static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
Namhyung Kimdb8fd072013-03-05 14:53:21 +0900944 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300945 int max_lines, struct disasm_line *queue)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200946{
947 static const char *prev_line;
948 static const char *prev_color;
949
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300950 if (dl->offset != -1) {
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200951 const char *path = NULL;
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300952 u64 nr_samples;
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900953 double percent, max_percent = 0.0;
954 double *ppercents = &percent;
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300955 u64 *psamples = &nr_samples;
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900956 int i, nr_percent = 1;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200957 const char *color;
958 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300959 s64 offset = dl->offset;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -0300960 const u64 addr = start + offset;
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300961 struct disasm_line *next;
Peter Zijlstra70fbe052016-09-05 16:08:12 -0300962 struct block_range *br;
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -0200963
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300964 next = disasm__get_next_ip_line(&notes->src->source, dl);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -0200965
Namhyung Kim759ff492013-03-05 14:53:26 +0900966 if (perf_evsel__is_group_event(evsel)) {
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900967 nr_percent = evsel->nr_members;
968 ppercents = calloc(nr_percent, sizeof(double));
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300969 psamples = calloc(nr_percent, sizeof(u64));
970 if (ppercents == NULL || psamples == NULL) {
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900971 return -1;
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300972 }
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900973 }
974
975 for (i = 0; i < nr_percent; i++) {
976 percent = disasm__calc_percent(notes,
Namhyung Kim1491c222013-03-05 14:53:28 +0900977 notes->src->lines ? i : evsel->idx + i,
978 offset,
979 next ? next->offset : (s64) len,
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300980 &path, &nr_samples);
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900981
982 ppercents[i] = percent;
Martin Liška0c4a5bc2015-06-19 16:10:43 -0300983 psamples[i] = nr_samples;
Namhyung Kimb1dd4432013-03-05 14:53:25 +0900984 if (percent > max_percent)
985 max_percent = percent;
986 }
987
988 if (max_percent < min_pcnt)
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -0200989 return -1;
990
Arnaldo Carvalho de Meloe3087b82011-02-08 15:01:39 -0200991 if (max_lines && printed >= max_lines)
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -0200992 return 1;
Arnaldo Carvalho de Melod040bd32011-02-05 15:37:31 -0200993
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -0200994 if (queue != NULL) {
995 list_for_each_entry_from(queue, &notes->src->source, node) {
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -0300996 if (queue == dl)
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -0200997 break;
Namhyung Kimdb8fd072013-03-05 14:53:21 +0900998 disasm_line__print(queue, sym, start, evsel, len,
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -0200999 0, 0, 1, NULL);
1000 }
1001 }
1002
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001003 color = get_percent_color(max_percent);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001004
1005 /*
1006 * Also color the filename and line if needed, with
1007 * the same color than the percentage. Don't print it
1008 * twice for close colored addr with the same filename:line
1009 */
1010 if (path) {
1011 if (!prev_line || strcmp(prev_line, path)
1012 || color != prev_color) {
1013 color_fprintf(stdout, color, " %s", path);
1014 prev_line = path;
1015 prev_color = color;
1016 }
1017 }
1018
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001019 for (i = 0; i < nr_percent; i++) {
1020 percent = ppercents[i];
Martin Liška0c4a5bc2015-06-19 16:10:43 -03001021 nr_samples = psamples[i];
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001022 color = get_percent_color(percent);
Martin Liška0c4a5bc2015-06-19 16:10:43 -03001023
1024 if (symbol_conf.show_total_period)
1025 color_fprintf(stdout, color, " %7" PRIu64,
1026 nr_samples);
1027 else
1028 color_fprintf(stdout, color, " %7.2f", percent);
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001029 }
1030
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001031 printf(" : ");
Peter Zijlstra70fbe052016-09-05 16:08:12 -03001032
1033 br = block_range__find(addr);
1034 color_fprintf(stdout, annotate__address_color(br), " %" PRIx64 ":", addr);
1035 color_fprintf(stdout, annotate__asm_color(br), "%s", dl->line);
1036 annotate__branch_printf(br, addr);
1037 printf("\n");
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001038
1039 if (ppercents != &percent)
1040 free(ppercents);
1041
Martin Liška0c4a5bc2015-06-19 16:10:43 -03001042 if (psamples != &nr_samples)
1043 free(psamples);
1044
Arnaldo Carvalho de Meloe3087b82011-02-08 15:01:39 -02001045 } else if (max_lines && printed >= max_lines)
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001046 return 1;
1047 else {
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001048 int width = 8;
1049
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -02001050 if (queue)
1051 return -1;
1052
Namhyung Kim759ff492013-03-05 14:53:26 +09001053 if (perf_evsel__is_group_event(evsel))
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001054 width *= evsel->nr_members;
1055
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001056 if (!*dl->line)
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001057 printf(" %*s:\n", width, " ");
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001058 else
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001059 printf(" %*s: %s\n", width, " ", dl->line);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001060 }
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001061
1062 return 0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001063}
1064
Namhyung Kim3aec1502013-03-05 14:53:22 +09001065/*
1066 * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
1067 * which looks like following
1068 *
1069 * 0000000000415500 <_init>:
1070 * 415500: sub $0x8,%rsp
1071 * 415504: mov 0x2f5ad5(%rip),%rax # 70afe0 <_DYNAMIC+0x2f8>
1072 * 41550b: test %rax,%rax
1073 * 41550e: je 415515 <_init+0x15>
1074 * 415510: callq 416e70 <__gmon_start__@plt>
1075 * 415515: add $0x8,%rsp
1076 * 415519: retq
1077 *
1078 * it will be parsed and saved into struct disasm_line as
1079 * <offset> <name> <ops.raw>
1080 *
1081 * The offset will be a relative offset from the start of the symbol and -1
1082 * means that it's not a disassembly line so should be treated differently.
1083 * The ops.raw part will be parsed further according to type of the instruction.
1084 */
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001085static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
Andi Kleene5924882014-11-12 18:05:26 -08001086 FILE *file, size_t privsize,
1087 int *line_nr)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001088{
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001089 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001090 struct disasm_line *dl;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001091 char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001092 size_t line_len;
1093 s64 line_ip, offset = -1;
Andi Kleene5924882014-11-12 18:05:26 -08001094 regmatch_t match[2];
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001095
1096 if (getline(&line, &line_len, file) < 0)
1097 return -1;
1098
1099 if (!line)
1100 return -1;
1101
1102 while (line_len != 0 && isspace(line[line_len - 1]))
1103 line[--line_len] = '\0';
1104
1105 c = strchr(line, '\n');
1106 if (c)
1107 *c = 0;
1108
1109 line_ip = -1;
Namhyung Kima31b7cc2012-04-11 17:04:59 -03001110 parsed_line = line;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001111
Andi Kleene5924882014-11-12 18:05:26 -08001112 /* /filename:linenr ? Save line number and ignore. */
1113 if (regexec(&file_lineno, line, 2, match, 0) == 0) {
1114 *line_nr = atoi(line + match[1].rm_so);
1115 return 0;
1116 }
1117
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001118 /*
1119 * Strip leading spaces:
1120 */
1121 tmp = line;
1122 while (*tmp) {
1123 if (*tmp != ' ')
1124 break;
1125 tmp++;
1126 }
1127
1128 if (*tmp) {
1129 /*
1130 * Parse hexa addresses followed by ':'
1131 */
1132 line_ip = strtoull(tmp, &tmp2, 16);
1133 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1134 line_ip = -1;
1135 }
1136
1137 if (line_ip != -1) {
1138 u64 start = map__rip_2objdump(map, sym->start),
1139 end = map__rip_2objdump(map, sym->end);
1140
1141 offset = line_ip - start;
Arnaldo Carvalho de Melo2c241bd2014-10-14 17:19:44 -03001142 if ((u64)line_ip < start || (u64)line_ip >= end)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001143 offset = -1;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001144 else
1145 parsed_line = tmp2 + 1;
Namhyung Kima31b7cc2012-04-11 17:04:59 -03001146 }
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001147
Arnaldo Carvalho de Melobff5c302016-09-19 17:18:16 -03001148 dl = disasm_line__new(offset, parsed_line, privsize, *line_nr, map);
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001149 free(line);
Andi Kleene5924882014-11-12 18:05:26 -08001150 (*line_nr)++;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001151
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001152 if (dl == NULL)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001153 return -1;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001154
Adrian Hunterbbb7f842013-08-07 14:38:54 +03001155 if (dl->ops.target.offset == UINT64_MAX)
1156 dl->ops.target.offset = dl->ops.target.addr -
1157 map__rip_2objdump(map, sym->start);
1158
Adrian Hunter6e427ab2013-10-14 13:43:40 +03001159 /* kcore has no symbols, so add the call target name */
Adrian Hunterb1781702013-08-07 14:38:57 +03001160 if (dl->ins && ins__is_call(dl->ins) && !dl->ops.target.name) {
Adrian Hunter6e427ab2013-10-14 13:43:40 +03001161 struct addr_map_symbol target = {
1162 .map = map,
1163 .addr = dl->ops.target.addr,
1164 };
Adrian Hunterb1781702013-08-07 14:38:57 +03001165
Arnaldo Carvalho de Melobe39db92016-09-01 19:25:52 -03001166 if (!map_groups__find_ams(&target) &&
Adrian Hunter6e427ab2013-10-14 13:43:40 +03001167 target.sym->start == target.al_addr)
1168 dl->ops.target.name = strdup(target.sym->name);
Adrian Hunterb1781702013-08-07 14:38:57 +03001169 }
1170
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001171 disasm__add(&notes->src->source, dl);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001172
1173 return 0;
1174}
1175
Andi Kleene5924882014-11-12 18:05:26 -08001176static __attribute__((constructor)) void symbol__init_regexpr(void)
1177{
1178 regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);
1179}
1180
Adrian Hunter484a5e72013-08-07 14:38:56 +03001181static void delete_last_nop(struct symbol *sym)
1182{
1183 struct annotation *notes = symbol__annotation(sym);
1184 struct list_head *list = &notes->src->source;
1185 struct disasm_line *dl;
1186
1187 while (!list_empty(list)) {
1188 dl = list_entry(list->prev, struct disasm_line, node);
1189
1190 if (dl->ins && dl->ins->ops) {
1191 if (dl->ins->ops != &nop_ops)
1192 return;
1193 } else {
1194 if (!strstr(dl->line, " nop ") &&
1195 !strstr(dl->line, " nopl ") &&
1196 !strstr(dl->line, " nopw "))
1197 return;
1198 }
1199
1200 list_del(&dl->node);
1201 disasm_line__free(dl);
1202 }
1203}
1204
Arnaldo Carvalho de Meloee51d852016-07-29 16:27:18 -03001205int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
1206 int errnum, char *buf, size_t buflen)
1207{
1208 struct dso *dso = map->dso;
1209
1210 BUG_ON(buflen == 0);
1211
1212 if (errnum >= 0) {
1213 str_error_r(errnum, buf, buflen);
1214 return 0;
1215 }
1216
1217 switch (errnum) {
1218 case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: {
1219 char bf[SBUILD_ID_SIZE + 15] = " with build id ";
1220 char *build_id_msg = NULL;
1221
1222 if (dso->has_build_id) {
1223 build_id__sprintf(dso->build_id,
1224 sizeof(dso->build_id), bf + 15);
1225 build_id_msg = bf;
1226 }
1227 scnprintf(buf, buflen,
1228 "No vmlinux file%s\nwas found in the path.\n\n"
1229 "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
1230 "Please use:\n\n"
1231 " perf buildid-cache -vu vmlinux\n\n"
1232 "or:\n\n"
1233 " --vmlinux vmlinux\n", build_id_msg ?: "");
1234 }
1235 break;
1236 default:
1237 scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
1238 break;
1239 }
1240
1241 return 0;
1242}
1243
Arnaldo Carvalho de Melo05ed3ac2016-08-09 15:32:53 -03001244static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size)
1245{
1246 char linkname[PATH_MAX];
1247 char *build_id_filename;
1248
1249 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
1250 !dso__is_kcore(dso))
1251 return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
1252
1253 build_id_filename = dso__build_id_filename(dso, NULL, 0);
1254 if (build_id_filename) {
1255 __symbol__join_symfs(filename, filename_size, build_id_filename);
1256 free(build_id_filename);
1257 } else {
1258 if (dso->has_build_id)
1259 return ENOMEM;
1260 goto fallback;
1261 }
1262
1263 if (dso__is_kcore(dso) ||
1264 readlink(filename, linkname, sizeof(linkname)) < 0 ||
1265 strstr(linkname, DSO__NAME_KALLSYMS) ||
1266 access(filename, R_OK)) {
1267fallback:
1268 /*
1269 * If we don't have build-ids or the build-id file isn't in the
1270 * cache, or is just a kallsyms file, well, lets hope that this
1271 * DSO is the same as when 'perf record' ran.
1272 */
1273 __symbol__join_symfs(filename, filename_size, dso->long_name);
1274 }
1275
1276 return 0;
1277}
1278
Arnaldo Carvalho de Melo5cb725a2016-07-29 16:44:56 -03001279int symbol__disassemble(struct symbol *sym, struct map *map, size_t privsize)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001280{
1281 struct dso *dso = map->dso;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001282 char command[PATH_MAX * 2];
1283 FILE *file;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001284 char symfs_filename[PATH_MAX];
Adrian Hunterafba19d2013-10-09 15:01:12 +03001285 struct kcore_extract kce;
1286 bool delete_extract = false;
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001287 int stdout_fd[2];
Andi Kleene5924882014-11-12 18:05:26 -08001288 int lineno = 0;
Andi Kleen62ec9b32015-11-05 19:06:07 -08001289 int nline;
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001290 pid_t pid;
Arnaldo Carvalho de Melo05ed3ac2016-08-09 15:32:53 -03001291 int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001292
Arnaldo Carvalho de Melo05ed3ac2016-08-09 15:32:53 -03001293 if (err)
1294 return err;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001295
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001296 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
Arnaldo Carvalho de Melo3caee092016-08-09 15:16:37 -03001297 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001298 map->unmap_ip(map, sym->end));
1299
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001300 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1301 dso, dso->long_name, sym, sym->name);
1302
Adrian Hunterafba19d2013-10-09 15:01:12 +03001303 if (dso__is_kcore(dso)) {
1304 kce.kcore_filename = symfs_filename;
1305 kce.addr = map__rip_2objdump(map, sym->start);
1306 kce.offs = sym->start;
Arnaldo Carvalho de Melo2c241bd2014-10-14 17:19:44 -03001307 kce.len = sym->end - sym->start;
Adrian Hunterafba19d2013-10-09 15:01:12 +03001308 if (!kcore_extract__create(&kce)) {
1309 delete_extract = true;
1310 strlcpy(symfs_filename, kce.extract_filename,
1311 sizeof(symfs_filename));
Adrian Hunterafba19d2013-10-09 15:01:12 +03001312 }
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001313 } else if (dso__needs_decompress(dso)) {
1314 char tmp[PATH_MAX];
1315 struct kmod_path m;
1316 int fd;
1317 bool ret;
1318
1319 if (kmod_path__parse_ext(&m, symfs_filename))
Arnaldo Carvalho de Melo3caee092016-08-09 15:16:37 -03001320 goto out;
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001321
1322 snprintf(tmp, PATH_MAX, "/tmp/perf-kmod-XXXXXX");
1323
1324 fd = mkstemp(tmp);
1325 if (fd < 0) {
1326 free(m.ext);
Arnaldo Carvalho de Melo3caee092016-08-09 15:16:37 -03001327 goto out;
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001328 }
1329
1330 ret = decompress_to_file(m.ext, symfs_filename, fd);
1331
Andi Kleen62ec9b32015-11-05 19:06:07 -08001332 if (ret)
1333 pr_err("Cannot decompress %s %s\n", m.ext, symfs_filename);
1334
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001335 free(m.ext);
1336 close(fd);
1337
1338 if (!ret)
Arnaldo Carvalho de Melo3caee092016-08-09 15:16:37 -03001339 goto out;
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001340
1341 strcpy(symfs_filename, tmp);
Adrian Hunterafba19d2013-10-09 15:01:12 +03001342 }
1343
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001344 snprintf(command, sizeof(command),
Maciek Borzecki7a4ec932012-09-04 12:32:30 +02001345 "%s %s%s --start-address=0x%016" PRIx64
Stephane Eranian3e6a2a72011-05-17 17:32:07 +02001346 " --stop-address=0x%016" PRIx64
Andi Kleene5924882014-11-12 18:05:26 -08001347 " -l -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
Maciek Borzecki7a4ec932012-09-04 12:32:30 +02001348 objdump_path ? objdump_path : "objdump",
Andi Kleenf69b64f2011-09-15 14:31:41 -07001349 disassembler_style ? "-M " : "",
1350 disassembler_style ? disassembler_style : "",
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001351 map__rip_2objdump(map, sym->start),
Arnaldo Carvalho de Melo2c241bd2014-10-14 17:19:44 -03001352 map__rip_2objdump(map, sym->end),
Stephane Eranian3e6a2a72011-05-17 17:32:07 +02001353 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
1354 symbol_conf.annotate_src ? "-S" : "",
Arnaldo Carvalho de Melo3caee092016-08-09 15:16:37 -03001355 symfs_filename, symfs_filename);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001356
1357 pr_debug("Executing: %s\n", command);
1358
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001359 err = -1;
1360 if (pipe(stdout_fd) < 0) {
1361 pr_err("Failure creating the pipe to run %s\n", command);
1362 goto out_remove_tmp;
1363 }
1364
1365 pid = fork();
1366 if (pid < 0) {
1367 pr_err("Failure forking to run %s\n", command);
1368 goto out_close_stdout;
1369 }
1370
1371 if (pid == 0) {
1372 close(stdout_fd[0]);
1373 dup2(stdout_fd[1], 1);
1374 close(stdout_fd[1]);
1375 execl("/bin/sh", "sh", "-c", command, NULL);
1376 perror(command);
1377 exit(-1);
1378 }
1379
1380 close(stdout_fd[1]);
1381
1382 file = fdopen(stdout_fd[0], "r");
Andi Kleen62ec9b32015-11-05 19:06:07 -08001383 if (!file) {
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001384 pr_err("Failure creating FILE stream for %s\n", command);
Andi Kleen62ec9b32015-11-05 19:06:07 -08001385 /*
1386 * If we were using debug info should retry with
1387 * original binary.
1388 */
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001389 goto out_remove_tmp;
Andi Kleen62ec9b32015-11-05 19:06:07 -08001390 }
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001391
Andi Kleen62ec9b32015-11-05 19:06:07 -08001392 nline = 0;
1393 while (!feof(file)) {
Andi Kleene5924882014-11-12 18:05:26 -08001394 if (symbol__parse_objdump_line(sym, map, file, privsize,
1395 &lineno) < 0)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001396 break;
Andi Kleen62ec9b32015-11-05 19:06:07 -08001397 nline++;
1398 }
1399
1400 if (nline == 0)
1401 pr_err("No output from %s\n", command);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001402
Adrian Hunter484a5e72013-08-07 14:38:56 +03001403 /*
1404 * kallsyms does not have symbol sizes so there may a nop at the end.
1405 * Remove it.
1406 */
1407 if (dso__is_kcore(dso))
1408 delete_last_nop(sym);
1409
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001410 fclose(file);
1411 err = 0;
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001412out_remove_tmp:
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001413 close(stdout_fd[0]);
1414
Jiri Olsa2c7da8c2015-03-02 12:56:12 -05001415 if (dso__needs_decompress(dso))
1416 unlink(symfs_filename);
Arnaldo Carvalho de Melo3caee092016-08-09 15:16:37 -03001417
Adrian Hunterafba19d2013-10-09 15:01:12 +03001418 if (delete_extract)
1419 kcore_extract__delete(&kce);
Arnaldo Carvalho de Meloc12944f2016-08-09 14:56:13 -03001420out:
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001421 return err;
Arnaldo Carvalho de Melo9955d0b2016-06-15 15:48:08 -03001422
1423out_close_stdout:
1424 close(stdout_fd[1]);
1425 goto out_remove_tmp;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001426}
1427
1428static void insert_source_line(struct rb_root *root, struct source_line *src_line)
1429{
1430 struct source_line *iter;
1431 struct rb_node **p = &root->rb_node;
1432 struct rb_node *parent = NULL;
Namhyung Kim1491c222013-03-05 14:53:28 +09001433 int i, ret;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001434
1435 while (*p != NULL) {
1436 parent = *p;
1437 iter = rb_entry(parent, struct source_line, node);
1438
Namhyung Kim41127962012-11-09 14:58:49 +09001439 ret = strcmp(iter->path, src_line->path);
1440 if (ret == 0) {
Namhyung Kim1491c222013-03-05 14:53:28 +09001441 for (i = 0; i < src_line->nr_pcnt; i++)
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001442 iter->samples[i].percent_sum += src_line->samples[i].percent;
Namhyung Kim41127962012-11-09 14:58:49 +09001443 return;
1444 }
1445
1446 if (ret < 0)
1447 p = &(*p)->rb_left;
1448 else
1449 p = &(*p)->rb_right;
1450 }
1451
Namhyung Kim1491c222013-03-05 14:53:28 +09001452 for (i = 0; i < src_line->nr_pcnt; i++)
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001453 src_line->samples[i].percent_sum = src_line->samples[i].percent;
Namhyung Kim41127962012-11-09 14:58:49 +09001454
1455 rb_link_node(&src_line->node, parent, p);
1456 rb_insert_color(&src_line->node, root);
1457}
1458
Namhyung Kim1491c222013-03-05 14:53:28 +09001459static int cmp_source_line(struct source_line *a, struct source_line *b)
1460{
1461 int i;
1462
1463 for (i = 0; i < a->nr_pcnt; i++) {
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001464 if (a->samples[i].percent_sum == b->samples[i].percent_sum)
Namhyung Kim1491c222013-03-05 14:53:28 +09001465 continue;
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001466 return a->samples[i].percent_sum > b->samples[i].percent_sum;
Namhyung Kim1491c222013-03-05 14:53:28 +09001467 }
1468
1469 return 0;
1470}
1471
Namhyung Kim41127962012-11-09 14:58:49 +09001472static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
1473{
1474 struct source_line *iter;
1475 struct rb_node **p = &root->rb_node;
1476 struct rb_node *parent = NULL;
1477
1478 while (*p != NULL) {
1479 parent = *p;
1480 iter = rb_entry(parent, struct source_line, node);
1481
Namhyung Kim1491c222013-03-05 14:53:28 +09001482 if (cmp_source_line(src_line, iter))
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001483 p = &(*p)->rb_left;
1484 else
1485 p = &(*p)->rb_right;
1486 }
1487
1488 rb_link_node(&src_line->node, parent, p);
1489 rb_insert_color(&src_line->node, root);
1490}
1491
Namhyung Kim41127962012-11-09 14:58:49 +09001492static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
1493{
1494 struct source_line *src_line;
1495 struct rb_node *node;
1496
1497 node = rb_first(src_root);
1498 while (node) {
1499 struct rb_node *next;
1500
1501 src_line = rb_entry(node, struct source_line, node);
1502 next = rb_next(node);
1503 rb_erase(node, src_root);
1504
1505 __resort_source_line(dest_root, src_line);
1506 node = next;
1507 }
1508}
1509
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001510static void symbol__free_source_line(struct symbol *sym, int len)
1511{
1512 struct annotation *notes = symbol__annotation(sym);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001513 struct source_line *src_line = notes->src->lines;
Namhyung Kim1491c222013-03-05 14:53:28 +09001514 size_t sizeof_src_line;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001515 int i;
1516
Namhyung Kim1491c222013-03-05 14:53:28 +09001517 sizeof_src_line = sizeof(*src_line) +
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001518 (sizeof(src_line->samples) * (src_line->nr_pcnt - 1));
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001519
Namhyung Kim1491c222013-03-05 14:53:28 +09001520 for (i = 0; i < len; i++) {
Namhyung Kimf048d542013-09-11 14:09:28 +09001521 free_srcline(src_line->path);
Namhyung Kim1491c222013-03-05 14:53:28 +09001522 src_line = (void *)src_line + sizeof_src_line;
1523 }
1524
Arnaldo Carvalho de Melo04662522013-12-26 17:41:15 -03001525 zfree(&notes->src->lines);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001526}
1527
1528/* Get the filename:line for the colored entries */
1529static int symbol__get_source_line(struct symbol *sym, struct map *map,
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001530 struct perf_evsel *evsel,
Namhyung Kim86c98ca2013-09-11 14:09:30 +09001531 struct rb_root *root, int len)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001532{
1533 u64 start;
Namhyung Kim1491c222013-03-05 14:53:28 +09001534 int i, k;
1535 int evidx = evsel->idx;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001536 struct source_line *src_line;
1537 struct annotation *notes = symbol__annotation(sym);
Namhyung Kim1491c222013-03-05 14:53:28 +09001538 struct sym_hist *h = annotation__histogram(notes, evidx);
Namhyung Kim41127962012-11-09 14:58:49 +09001539 struct rb_root tmp_root = RB_ROOT;
Namhyung Kim1491c222013-03-05 14:53:28 +09001540 int nr_pcnt = 1;
1541 u64 h_sum = h->sum;
1542 size_t sizeof_src_line = sizeof(struct source_line);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001543
Namhyung Kim1491c222013-03-05 14:53:28 +09001544 if (perf_evsel__is_group_event(evsel)) {
1545 for (i = 1; i < evsel->nr_members; i++) {
1546 h = annotation__histogram(notes, evidx + i);
1547 h_sum += h->sum;
1548 }
1549 nr_pcnt = evsel->nr_members;
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001550 sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples);
Namhyung Kim1491c222013-03-05 14:53:28 +09001551 }
1552
1553 if (!h_sum)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001554 return 0;
1555
Namhyung Kim1491c222013-03-05 14:53:28 +09001556 src_line = notes->src->lines = calloc(len, sizeof_src_line);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001557 if (!notes->src->lines)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001558 return -1;
1559
David Millerf40a0632012-03-25 16:28:12 -04001560 start = map__rip_2objdump(map, sym->start);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001561
1562 for (i = 0; i < len; i++) {
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001563 u64 offset;
Namhyung Kim1491c222013-03-05 14:53:28 +09001564 double percent_max = 0.0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001565
Namhyung Kim1491c222013-03-05 14:53:28 +09001566 src_line->nr_pcnt = nr_pcnt;
1567
1568 for (k = 0; k < nr_pcnt; k++) {
1569 h = annotation__histogram(notes, evidx + k);
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001570 src_line->samples[k].percent = 100.0 * h->addr[i] / h->sum;
Namhyung Kim1491c222013-03-05 14:53:28 +09001571
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001572 if (src_line->samples[k].percent > percent_max)
1573 percent_max = src_line->samples[k].percent;
Namhyung Kim1491c222013-03-05 14:53:28 +09001574 }
1575
1576 if (percent_max <= 0.5)
1577 goto next;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001578
1579 offset = start + i;
Andi Kleen85c116a2014-11-12 18:05:27 -08001580 src_line->path = get_srcline(map->dso, offset, NULL, false);
Namhyung Kim1491c222013-03-05 14:53:28 +09001581 insert_source_line(&tmp_root, src_line);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001582
Namhyung Kim1491c222013-03-05 14:53:28 +09001583 next:
1584 src_line = (void *)src_line + sizeof_src_line;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001585 }
1586
Namhyung Kim41127962012-11-09 14:58:49 +09001587 resort_source_line(root, &tmp_root);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001588 return 0;
1589}
1590
1591static void print_summary(struct rb_root *root, const char *filename)
1592{
1593 struct source_line *src_line;
1594 struct rb_node *node;
1595
1596 printf("\nSorted summary for file %s\n", filename);
1597 printf("----------------------------------------------\n\n");
1598
1599 if (RB_EMPTY_ROOT(root)) {
1600 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
1601 return;
1602 }
1603
1604 node = rb_first(root);
1605 while (node) {
Namhyung Kim1491c222013-03-05 14:53:28 +09001606 double percent, percent_max = 0.0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001607 const char *color;
1608 char *path;
Namhyung Kim1491c222013-03-05 14:53:28 +09001609 int i;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001610
1611 src_line = rb_entry(node, struct source_line, node);
Namhyung Kim1491c222013-03-05 14:53:28 +09001612 for (i = 0; i < src_line->nr_pcnt; i++) {
Arnaldo Carvalho de Melo276af92f2015-06-19 16:36:12 -03001613 percent = src_line->samples[i].percent_sum;
Namhyung Kim1491c222013-03-05 14:53:28 +09001614 color = get_percent_color(percent);
1615 color_fprintf(stdout, color, " %7.2f", percent);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001616
Namhyung Kim1491c222013-03-05 14:53:28 +09001617 if (percent > percent_max)
1618 percent_max = percent;
1619 }
1620
1621 path = src_line->path;
1622 color = get_percent_color(percent_max);
Namhyung Kimf048d542013-09-11 14:09:28 +09001623 color_fprintf(stdout, color, " %s\n", path);
Namhyung Kim1491c222013-03-05 14:53:28 +09001624
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001625 node = rb_next(node);
1626 }
1627}
1628
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001629static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001630{
1631 struct annotation *notes = symbol__annotation(sym);
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001632 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
Arnaldo Carvalho de Melo1b2e2df2012-04-19 10:57:06 -03001633 u64 len = symbol__size(sym), offset;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001634
1635 for (offset = 0; offset < len; ++offset)
1636 if (h->addr[offset] != 0)
1637 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
1638 sym->start + offset, h->addr[offset]);
1639 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
1640}
1641
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001642int symbol__annotate_printf(struct symbol *sym, struct map *map,
1643 struct perf_evsel *evsel, bool full_paths,
1644 int min_pcnt, int max_lines, int context)
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001645{
1646 struct dso *dso = map->dso;
David Ahernbfd14b92012-09-08 09:06:50 -06001647 char *filename;
1648 const char *d_filename;
Arnaldo Carvalho de Melo9cdbadce2014-03-18 11:50:21 -03001649 const char *evsel_name = perf_evsel__name(evsel);
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001650 struct annotation *notes = symbol__annotation(sym);
Peter Zijlstra (Intel)135cce12016-06-30 10:29:55 +02001651 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001652 struct disasm_line *pos, *queue = NULL;
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001653 u64 start = map__rip_2objdump(map, sym->start);
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -02001654 int printed = 2, queue_len = 0;
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001655 int more = 0;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001656 u64 len;
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001657 int width = 8;
Peter Zijlstra (Intel)53dd9b52016-06-30 09:17:26 -03001658 int graph_dotted_len;
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001659
David Ahernbfd14b92012-09-08 09:06:50 -06001660 filename = strdup(dso->long_name);
1661 if (!filename)
1662 return -ENOMEM;
1663
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001664 if (full_paths)
1665 d_filename = filename;
1666 else
1667 d_filename = basename(filename);
1668
Arnaldo Carvalho de Melo1b2e2df2012-04-19 10:57:06 -03001669 len = symbol__size(sym);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001670
Namhyung Kim759ff492013-03-05 14:53:26 +09001671 if (perf_evsel__is_group_event(evsel))
Namhyung Kimb1dd4432013-03-05 14:53:25 +09001672 width *= evsel->nr_members;
1673
Peter Zijlstra (Intel)135cce12016-06-30 10:29:55 +02001674 graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples)\n",
1675 width, width, "Percent", d_filename, evsel_name, h->sum);
Arnaldo Carvalho de Melo9cdbadce2014-03-18 11:50:21 -03001676
Peter Zijlstra (Intel)53dd9b52016-06-30 09:17:26 -03001677 printf("%-*.*s----\n",
Arnaldo Carvalho de Melo9cdbadce2014-03-18 11:50:21 -03001678 graph_dotted_len, graph_dotted_len, graph_dotted_line);
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001679
1680 if (verbose)
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001681 symbol__annotate_hits(sym, evsel);
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001682
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001683 list_for_each_entry(pos, &notes->src->source, node) {
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -02001684 if (context && queue == NULL) {
1685 queue = pos;
1686 queue_len = 0;
1687 }
1688
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001689 switch (disasm_line__print(pos, sym, start, evsel, len,
Arnaldo Carvalho de Melo058b4cc2012-04-02 12:59:01 -03001690 min_pcnt, printed, max_lines,
1691 queue)) {
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001692 case 0:
1693 ++printed;
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -02001694 if (context) {
1695 printed += queue_len;
1696 queue = NULL;
1697 queue_len = 0;
1698 }
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001699 break;
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001700 case 1:
1701 /* filtered by max_lines */
1702 ++more;
1703 break;
1704 case -1:
1705 default:
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -02001706 /*
1707 * Filtered by min_pcnt or non IP lines when
1708 * context != 0
1709 */
1710 if (!context)
1711 break;
1712 if (queue_len == context)
1713 queue = list_entry(queue->node.next, typeof(*queue), node);
1714 else
1715 ++queue_len;
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001716 break;
1717 }
1718 }
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001719
David Ahernbfd14b92012-09-08 09:06:50 -06001720 free(filename);
1721
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001722 return more;
1723}
1724
1725void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
1726{
1727 struct annotation *notes = symbol__annotation(sym);
1728 struct sym_hist *h = annotation__histogram(notes, evidx);
1729
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001730 memset(h, 0, notes->src->sizeof_sym_hist);
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001731}
1732
Arnaldo Carvalho de Meloce6f4fa2011-02-08 13:27:39 -02001733void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001734{
1735 struct annotation *notes = symbol__annotation(sym);
1736 struct sym_hist *h = annotation__histogram(notes, evidx);
Arnaldo Carvalho de Melo1b2e2df2012-04-19 10:57:06 -03001737 int len = symbol__size(sym), offset;
Arnaldo Carvalho de Melo36532462011-02-06 14:54:44 -02001738
1739 h->sum = 0;
Arnaldo Carvalho de Melo8b84a562012-04-05 16:15:59 -03001740 for (offset = 0; offset < len; ++offset) {
1741 h->addr[offset] = h->addr[offset] * 7 / 8;
1742 h->sum += h->addr[offset];
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001743 }
1744}
1745
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001746void disasm__purge(struct list_head *head)
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001747{
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001748 struct disasm_line *pos, *n;
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001749
1750 list_for_each_entry_safe(pos, n, head, node) {
1751 list_del(&pos->node);
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001752 disasm_line__free(pos);
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001753 }
1754}
1755
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -03001756static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
1757{
1758 size_t printed;
1759
1760 if (dl->offset == -1)
1761 return fprintf(fp, "%s\n", dl->line);
1762
1763 printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
1764
Arnaldo Carvalho de Meloc7e6ead2012-04-20 14:38:46 -03001765 if (dl->ops.raw[0] != '\0') {
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -03001766 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
Arnaldo Carvalho de Meloc7e6ead2012-04-20 14:38:46 -03001767 dl->ops.raw);
Arnaldo Carvalho de Melo51454182012-04-15 15:52:18 -03001768 }
1769
1770 return printed + fprintf(fp, "\n");
1771}
1772
1773size_t disasm__fprintf(struct list_head *head, FILE *fp)
1774{
1775 struct disasm_line *pos;
1776 size_t printed = 0;
1777
1778 list_for_each_entry(pos, head, node)
1779 printed += disasm_line__fprintf(pos, fp);
1780
1781 return printed;
1782}
1783
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001784int symbol__tty_annotate(struct symbol *sym, struct map *map,
1785 struct perf_evsel *evsel, bool print_lines,
1786 bool full_paths, int min_pcnt, int max_lines)
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001787{
1788 struct dso *dso = map->dso;
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001789 struct rb_root source_line = RB_ROOT;
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001790 u64 len;
1791
Arnaldo Carvalho de Melo5cb725a2016-07-29 16:44:56 -03001792 if (symbol__disassemble(sym, map, 0) < 0)
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001793 return -1;
1794
Arnaldo Carvalho de Melo1b2e2df2012-04-19 10:57:06 -03001795 len = symbol__size(sym);
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001796
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001797 if (print_lines) {
Michael Petlan4a4c03c2015-11-09 16:33:31 +01001798 srcline_full_filename = full_paths;
Namhyung Kim86c98ca2013-09-11 14:09:30 +09001799 symbol__get_source_line(sym, map, evsel, &source_line, len);
1800 print_summary(&source_line, dso->long_name);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001801 }
1802
Namhyung Kimdb8fd072013-03-05 14:53:21 +09001803 symbol__annotate_printf(sym, map, evsel, full_paths,
Arnaldo Carvalho de Melod5e3d742011-02-08 15:29:25 -02001804 min_pcnt, max_lines, 0);
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001805 if (print_lines)
1806 symbol__free_source_line(sym, len);
1807
Arnaldo Carvalho de Melo29ed6e72012-04-15 15:24:39 -03001808 disasm__purge(&symbol__annotation(sym)->src->source);
Arnaldo Carvalho de Melof1e27012011-02-05 18:51:38 -02001809
Arnaldo Carvalho de Melo78f7def2011-02-04 09:45:46 -02001810 return 0;
1811}
Arnaldo Carvalho de Melof626adf2013-12-18 17:10:15 -03001812
Namhyung Kim48c65bd2014-02-20 10:32:53 +09001813bool ui__has_annotation(void)
1814{
Jiri Olsa2e0453a2016-05-03 13:54:44 +02001815 return use_browser == 1 && perf_hpp_list.sym;
Namhyung Kim48c65bd2014-02-20 10:32:53 +09001816}