Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-block.git] / tools / perf / util / annotate.c
1 /*
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"
11 #include "build-id.h"
12 #include "color.h"
13 #include "cache.h"
14 #include "symbol.h"
15 #include "debug.h"
16 #include "annotate.h"
17 #include <pthread.h>
18
19 const char      *disassembler_style;
20
21 static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
22                               struct ins_operands *ops)
23 {
24         return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
25 }
26
27 int ins__scnprintf(struct ins *ins, char *bf, size_t size,
28                   struct ins_operands *ops)
29 {
30         if (ins->ops->scnprintf)
31                 return ins->ops->scnprintf(ins, bf, size, ops);
32
33         return ins__raw_scnprintf(ins, bf, size, ops);
34 }
35
36 static int call__parse(struct ins_operands *ops)
37 {
38         char *endptr, *tok, *name;
39
40         ops->target.addr = strtoull(ops->raw, &endptr, 16);
41
42         name = strchr(endptr, '<');
43         if (name == NULL)
44                 goto indirect_call;
45
46         name++;
47
48         tok = strchr(name, '>');
49         if (tok == NULL)
50                 return -1;
51
52         *tok = '\0';
53         ops->target.name = strdup(name);
54         *tok = '>';
55
56         return ops->target.name == NULL ? -1 : 0;
57
58 indirect_call:
59         tok = strchr(endptr, '*');
60         if (tok == NULL)
61                 return -1;
62
63         ops->target.addr = strtoull(tok + 1, NULL, 16);
64         return 0;
65 }
66
67 static int call__scnprintf(struct ins *ins, char *bf, size_t size,
68                            struct ins_operands *ops)
69 {
70         if (ops->target.name)
71                 return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name);
72
73         return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr);
74 }
75
76 static struct ins_ops call_ops = {
77         .parse     = call__parse,
78         .scnprintf = call__scnprintf,
79 };
80
81 bool ins__is_call(const struct ins *ins)
82 {
83         return ins->ops == &call_ops;
84 }
85
86 static int jump__parse(struct ins_operands *ops)
87 {
88         const char *s = strchr(ops->raw, '+');
89
90         ops->target.addr = strtoll(ops->raw, NULL, 16);
91
92         if (s++ != NULL)
93                 ops->target.offset = strtoll(s, NULL, 16);
94         else
95                 ops->target.offset = UINT64_MAX;
96
97         return 0;
98 }
99
100 static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
101                            struct ins_operands *ops)
102 {
103         return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset);
104 }
105
106 static struct ins_ops jump_ops = {
107         .parse     = jump__parse,
108         .scnprintf = jump__scnprintf,
109 };
110
111 bool ins__is_jump(const struct ins *ins)
112 {
113         return ins->ops == &jump_ops;
114 }
115
116 static int nop__scnprintf(struct ins *ins __used, char *bf, size_t size,
117                           struct ins_operands *ops __used)
118 {
119         return scnprintf(bf, size, "%-6.6s", "nop");
120 }
121
122 static struct ins_ops nop_ops = {
123         .scnprintf = nop__scnprintf,
124 };
125
126 /*
127  * Must be sorted by name!
128  */
129 static struct ins instructions[] = {
130         { .name = "call",  .ops  = &call_ops, },
131         { .name = "callq", .ops  = &call_ops, },
132         { .name = "ja",    .ops  = &jump_ops, },
133         { .name = "jae",   .ops  = &jump_ops, },
134         { .name = "jb",    .ops  = &jump_ops, },
135         { .name = "jbe",   .ops  = &jump_ops, },
136         { .name = "jc",    .ops  = &jump_ops, },
137         { .name = "jcxz",  .ops  = &jump_ops, },
138         { .name = "je",    .ops  = &jump_ops, },
139         { .name = "jecxz", .ops  = &jump_ops, },
140         { .name = "jg",    .ops  = &jump_ops, },
141         { .name = "jge",   .ops  = &jump_ops, },
142         { .name = "jl",    .ops  = &jump_ops, },
143         { .name = "jle",   .ops  = &jump_ops, },
144         { .name = "jmp",   .ops  = &jump_ops, },
145         { .name = "jmpq",  .ops  = &jump_ops, },
146         { .name = "jna",   .ops  = &jump_ops, },
147         { .name = "jnae",  .ops  = &jump_ops, },
148         { .name = "jnb",   .ops  = &jump_ops, },
149         { .name = "jnbe",  .ops  = &jump_ops, },
150         { .name = "jnc",   .ops  = &jump_ops, },
151         { .name = "jne",   .ops  = &jump_ops, },
152         { .name = "jng",   .ops  = &jump_ops, },
153         { .name = "jnge",  .ops  = &jump_ops, },
154         { .name = "jnl",   .ops  = &jump_ops, },
155         { .name = "jnle",  .ops  = &jump_ops, },
156         { .name = "jno",   .ops  = &jump_ops, },
157         { .name = "jnp",   .ops  = &jump_ops, },
158         { .name = "jns",   .ops  = &jump_ops, },
159         { .name = "jnz",   .ops  = &jump_ops, },
160         { .name = "jo",    .ops  = &jump_ops, },
161         { .name = "jp",    .ops  = &jump_ops, },
162         { .name = "jpe",   .ops  = &jump_ops, },
163         { .name = "jpo",   .ops  = &jump_ops, },
164         { .name = "jrcxz", .ops  = &jump_ops, },
165         { .name = "js",    .ops  = &jump_ops, },
166         { .name = "jz",    .ops  = &jump_ops, },
167         { .name = "nop",   .ops  = &nop_ops, },
168         { .name = "nopl",  .ops  = &nop_ops, },
169         { .name = "nopw",  .ops  = &nop_ops, },
170 };
171
172 static int ins__cmp(const void *name, const void *insp)
173 {
174         const struct ins *ins = insp;
175
176         return strcmp(name, ins->name);
177 }
178
179 static struct ins *ins__find(const char *name)
180 {
181         const int nmemb = ARRAY_SIZE(instructions);
182
183         return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
184 }
185
186 int symbol__annotate_init(struct map *map __used, struct symbol *sym)
187 {
188         struct annotation *notes = symbol__annotation(sym);
189         pthread_mutex_init(&notes->lock, NULL);
190         return 0;
191 }
192
193 int symbol__alloc_hist(struct symbol *sym)
194 {
195         struct annotation *notes = symbol__annotation(sym);
196         const size_t size = symbol__size(sym);
197         size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
198
199         notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
200         if (notes->src == NULL)
201                 return -1;
202         notes->src->sizeof_sym_hist = sizeof_sym_hist;
203         notes->src->nr_histograms   = symbol_conf.nr_events;
204         INIT_LIST_HEAD(&notes->src->source);
205         return 0;
206 }
207
208 void symbol__annotate_zero_histograms(struct symbol *sym)
209 {
210         struct annotation *notes = symbol__annotation(sym);
211
212         pthread_mutex_lock(&notes->lock);
213         if (notes->src != NULL)
214                 memset(notes->src->histograms, 0,
215                        notes->src->nr_histograms * notes->src->sizeof_sym_hist);
216         pthread_mutex_unlock(&notes->lock);
217 }
218
219 int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
220                              int evidx, u64 addr)
221 {
222         unsigned offset;
223         struct annotation *notes;
224         struct sym_hist *h;
225
226         notes = symbol__annotation(sym);
227         if (notes->src == NULL)
228                 return -ENOMEM;
229
230         pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
231
232         if (addr < sym->start || addr > sym->end)
233                 return -ERANGE;
234
235         offset = addr - sym->start;
236         h = annotation__histogram(notes, evidx);
237         h->sum++;
238         h->addr[offset]++;
239
240         pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
241                   ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
242                   addr, addr - sym->start, evidx, h->addr[offset]);
243         return 0;
244 }
245
246 static void disasm_line__init_ins(struct disasm_line *dl)
247 {
248         dl->ins = ins__find(dl->name);
249
250         if (dl->ins == NULL)
251                 return;
252
253         if (!dl->ins->ops)
254                 return;
255
256         if (dl->ins->ops->parse)
257                 dl->ins->ops->parse(&dl->ops);
258 }
259
260 static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
261 {
262         struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
263
264         if (dl != NULL) {
265                 dl->offset = offset;
266                 dl->line = strdup(line);
267                 if (dl->line == NULL)
268                         goto out_delete;
269
270                 if (offset != -1) {
271                         char *name = dl->line, tmp;
272
273                         while (isspace(name[0]))
274                                 ++name;
275
276                         if (name[0] == '\0')
277                                 goto out_delete;
278
279                         dl->ops.raw = name + 1;
280
281                         while (dl->ops.raw[0] != '\0' &&
282                                !isspace(dl->ops.raw[0]))
283                                 ++dl->ops.raw;
284
285                         tmp = dl->ops.raw[0];
286                         dl->ops.raw[0] = '\0';
287                         dl->name = strdup(name);
288
289                         if (dl->name == NULL)
290                                 goto out_free_line;
291
292                         dl->ops.raw[0] = tmp;
293
294                         if (dl->ops.raw[0] != '\0') {
295                                 dl->ops.raw++;
296                                 while (isspace(dl->ops.raw[0]))
297                                         ++dl->ops.raw;
298                         }
299
300                         disasm_line__init_ins(dl);
301                 }
302         }
303
304         return dl;
305
306 out_free_line:
307         free(dl->line);
308 out_delete:
309         free(dl);
310         return NULL;
311 }
312
313 void disasm_line__free(struct disasm_line *dl)
314 {
315         free(dl->line);
316         free(dl->name);
317         free(dl->ops.target.name);
318         free(dl);
319 }
320
321 int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
322 {
323         if (raw || !dl->ins)
324                 return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw);
325
326         return ins__scnprintf(dl->ins, bf, size, &dl->ops);
327 }
328
329 static void disasm__add(struct list_head *head, struct disasm_line *line)
330 {
331         list_add_tail(&line->node, head);
332 }
333
334 struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
335 {
336         list_for_each_entry_continue(pos, head, node)
337                 if (pos->offset >= 0)
338                         return pos;
339
340         return NULL;
341 }
342
343 static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
344                       int evidx, u64 len, int min_pcnt, int printed,
345                       int max_lines, struct disasm_line *queue)
346 {
347         static const char *prev_line;
348         static const char *prev_color;
349
350         if (dl->offset != -1) {
351                 const char *path = NULL;
352                 unsigned int hits = 0;
353                 double percent = 0.0;
354                 const char *color;
355                 struct annotation *notes = symbol__annotation(sym);
356                 struct source_line *src_line = notes->src->lines;
357                 struct sym_hist *h = annotation__histogram(notes, evidx);
358                 s64 offset = dl->offset;
359                 const u64 addr = start + offset;
360                 struct disasm_line *next;
361
362                 next = disasm__get_next_ip_line(&notes->src->source, dl);
363
364                 while (offset < (s64)len &&
365                        (next == NULL || offset < next->offset)) {
366                         if (src_line) {
367                                 if (path == NULL)
368                                         path = src_line[offset].path;
369                                 percent += src_line[offset].percent;
370                         } else
371                                 hits += h->addr[offset];
372
373                         ++offset;
374                 }
375
376                 if (src_line == NULL && h->sum)
377                         percent = 100.0 * hits / h->sum;
378
379                 if (percent < min_pcnt)
380                         return -1;
381
382                 if (max_lines && printed >= max_lines)
383                         return 1;
384
385                 if (queue != NULL) {
386                         list_for_each_entry_from(queue, &notes->src->source, node) {
387                                 if (queue == dl)
388                                         break;
389                                 disasm_line__print(queue, sym, start, evidx, len,
390                                                     0, 0, 1, NULL);
391                         }
392                 }
393
394                 color = get_percent_color(percent);
395
396                 /*
397                  * Also color the filename and line if needed, with
398                  * the same color than the percentage. Don't print it
399                  * twice for close colored addr with the same filename:line
400                  */
401                 if (path) {
402                         if (!prev_line || strcmp(prev_line, path)
403                                        || color != prev_color) {
404                                 color_fprintf(stdout, color, " %s", path);
405                                 prev_line = path;
406                                 prev_color = color;
407                         }
408                 }
409
410                 color_fprintf(stdout, color, " %7.2f", percent);
411                 printf(" :      ");
412                 color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
413                 color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
414         } else if (max_lines && printed >= max_lines)
415                 return 1;
416         else {
417                 if (queue)
418                         return -1;
419
420                 if (!*dl->line)
421                         printf("         :\n");
422                 else
423                         printf("         :      %s\n", dl->line);
424         }
425
426         return 0;
427 }
428
429 static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
430                                       FILE *file, size_t privsize)
431 {
432         struct annotation *notes = symbol__annotation(sym);
433         struct disasm_line *dl;
434         char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
435         size_t line_len;
436         s64 line_ip, offset = -1;
437
438         if (getline(&line, &line_len, file) < 0)
439                 return -1;
440
441         if (!line)
442                 return -1;
443
444         while (line_len != 0 && isspace(line[line_len - 1]))
445                 line[--line_len] = '\0';
446
447         c = strchr(line, '\n');
448         if (c)
449                 *c = 0;
450
451         line_ip = -1;
452         parsed_line = line;
453
454         /*
455          * Strip leading spaces:
456          */
457         tmp = line;
458         while (*tmp) {
459                 if (*tmp != ' ')
460                         break;
461                 tmp++;
462         }
463
464         if (*tmp) {
465                 /*
466                  * Parse hexa addresses followed by ':'
467                  */
468                 line_ip = strtoull(tmp, &tmp2, 16);
469                 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
470                         line_ip = -1;
471         }
472
473         if (line_ip != -1) {
474                 u64 start = map__rip_2objdump(map, sym->start),
475                     end = map__rip_2objdump(map, sym->end);
476
477                 offset = line_ip - start;
478                 if (offset < 0 || (u64)line_ip > end)
479                         offset = -1;
480                 else
481                         parsed_line = tmp2 + 1;
482         }
483
484         dl = disasm_line__new(offset, parsed_line, privsize);
485         free(line);
486
487         if (dl == NULL)
488                 return -1;
489
490         disasm__add(&notes->src->source, dl);
491
492         return 0;
493 }
494
495 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
496 {
497         struct dso *dso = map->dso;
498         char *filename = dso__build_id_filename(dso, NULL, 0);
499         bool free_filename = true;
500         char command[PATH_MAX * 2];
501         FILE *file;
502         int err = 0;
503         char symfs_filename[PATH_MAX];
504
505         if (filename) {
506                 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
507                          symbol_conf.symfs, filename);
508         }
509
510         if (filename == NULL) {
511                 if (dso->has_build_id) {
512                         pr_err("Can't annotate %s: not enough memory\n",
513                                sym->name);
514                         return -ENOMEM;
515                 }
516                 goto fallback;
517         } else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
518                    strstr(command, "[kernel.kallsyms]") ||
519                    access(symfs_filename, R_OK)) {
520                 free(filename);
521 fallback:
522                 /*
523                  * If we don't have build-ids or the build-id file isn't in the
524                  * cache, or is just a kallsyms file, well, lets hope that this
525                  * DSO is the same as when 'perf record' ran.
526                  */
527                 filename = dso->long_name;
528                 snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
529                          symbol_conf.symfs, filename);
530                 free_filename = false;
531         }
532
533         if (dso->symtab_type == SYMTAB__KALLSYMS) {
534                 char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
535                 char *build_id_msg = NULL;
536
537                 if (dso->annotate_warned)
538                         goto out_free_filename;
539
540                 if (dso->has_build_id) {
541                         build_id__sprintf(dso->build_id,
542                                           sizeof(dso->build_id), bf + 15);
543                         build_id_msg = bf;
544                 }
545                 err = -ENOENT;
546                 dso->annotate_warned = 1;
547                 pr_err("Can't annotate %s:\n\n"
548                        "No vmlinux file%s\nwas found in the path.\n\n"
549                        "Please use:\n\n"
550                        "  perf buildid-cache -av vmlinux\n\n"
551                        "or:\n\n"
552                        "  --vmlinux vmlinux\n",
553                        sym->name, build_id_msg ?: "");
554                 goto out_free_filename;
555         }
556
557         pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
558                  filename, sym->name, map->unmap_ip(map, sym->start),
559                  map->unmap_ip(map, sym->end));
560
561         pr_debug("annotating [%p] %30s : [%p] %30s\n",
562                  dso, dso->long_name, sym, sym->name);
563
564         snprintf(command, sizeof(command),
565                  "objdump %s%s --start-address=0x%016" PRIx64
566                  " --stop-address=0x%016" PRIx64
567                  " -d %s %s -C %s|grep -v %s|expand",
568                  disassembler_style ? "-M " : "",
569                  disassembler_style ? disassembler_style : "",
570                  map__rip_2objdump(map, sym->start),
571                  map__rip_2objdump(map, sym->end+1),
572                  symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
573                  symbol_conf.annotate_src ? "-S" : "",
574                  symfs_filename, filename);
575
576         pr_debug("Executing: %s\n", command);
577
578         file = popen(command, "r");
579         if (!file)
580                 goto out_free_filename;
581
582         while (!feof(file))
583                 if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
584                         break;
585
586         pclose(file);
587 out_free_filename:
588         if (free_filename)
589                 free(filename);
590         return err;
591 }
592
593 static void insert_source_line(struct rb_root *root, struct source_line *src_line)
594 {
595         struct source_line *iter;
596         struct rb_node **p = &root->rb_node;
597         struct rb_node *parent = NULL;
598
599         while (*p != NULL) {
600                 parent = *p;
601                 iter = rb_entry(parent, struct source_line, node);
602
603                 if (src_line->percent > iter->percent)
604                         p = &(*p)->rb_left;
605                 else
606                         p = &(*p)->rb_right;
607         }
608
609         rb_link_node(&src_line->node, parent, p);
610         rb_insert_color(&src_line->node, root);
611 }
612
613 static void symbol__free_source_line(struct symbol *sym, int len)
614 {
615         struct annotation *notes = symbol__annotation(sym);
616         struct source_line *src_line = notes->src->lines;
617         int i;
618
619         for (i = 0; i < len; i++)
620                 free(src_line[i].path);
621
622         free(src_line);
623         notes->src->lines = NULL;
624 }
625
626 /* Get the filename:line for the colored entries */
627 static int symbol__get_source_line(struct symbol *sym, struct map *map,
628                                    int evidx, struct rb_root *root, int len,
629                                    const char *filename)
630 {
631         u64 start;
632         int i;
633         char cmd[PATH_MAX * 2];
634         struct source_line *src_line;
635         struct annotation *notes = symbol__annotation(sym);
636         struct sym_hist *h = annotation__histogram(notes, evidx);
637
638         if (!h->sum)
639                 return 0;
640
641         src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
642         if (!notes->src->lines)
643                 return -1;
644
645         start = map__rip_2objdump(map, sym->start);
646
647         for (i = 0; i < len; i++) {
648                 char *path = NULL;
649                 size_t line_len;
650                 u64 offset;
651                 FILE *fp;
652
653                 src_line[i].percent = 100.0 * h->addr[i] / h->sum;
654                 if (src_line[i].percent <= 0.5)
655                         continue;
656
657                 offset = start + i;
658                 sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
659                 fp = popen(cmd, "r");
660                 if (!fp)
661                         continue;
662
663                 if (getline(&path, &line_len, fp) < 0 || !line_len)
664                         goto next;
665
666                 src_line[i].path = malloc(sizeof(char) * line_len + 1);
667                 if (!src_line[i].path)
668                         goto next;
669
670                 strcpy(src_line[i].path, path);
671                 insert_source_line(root, &src_line[i]);
672
673         next:
674                 pclose(fp);
675         }
676
677         return 0;
678 }
679
680 static void print_summary(struct rb_root *root, const char *filename)
681 {
682         struct source_line *src_line;
683         struct rb_node *node;
684
685         printf("\nSorted summary for file %s\n", filename);
686         printf("----------------------------------------------\n\n");
687
688         if (RB_EMPTY_ROOT(root)) {
689                 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
690                 return;
691         }
692
693         node = rb_first(root);
694         while (node) {
695                 double percent;
696                 const char *color;
697                 char *path;
698
699                 src_line = rb_entry(node, struct source_line, node);
700                 percent = src_line->percent;
701                 color = get_percent_color(percent);
702                 path = src_line->path;
703
704                 color_fprintf(stdout, color, " %7.2f %s", percent, path);
705                 node = rb_next(node);
706         }
707 }
708
709 static void symbol__annotate_hits(struct symbol *sym, int evidx)
710 {
711         struct annotation *notes = symbol__annotation(sym);
712         struct sym_hist *h = annotation__histogram(notes, evidx);
713         u64 len = symbol__size(sym), offset;
714
715         for (offset = 0; offset < len; ++offset)
716                 if (h->addr[offset] != 0)
717                         printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
718                                sym->start + offset, h->addr[offset]);
719         printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
720 }
721
722 int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
723                             bool full_paths, int min_pcnt, int max_lines,
724                             int context)
725 {
726         struct dso *dso = map->dso;
727         const char *filename = dso->long_name, *d_filename;
728         struct annotation *notes = symbol__annotation(sym);
729         struct disasm_line *pos, *queue = NULL;
730         u64 start = map__rip_2objdump(map, sym->start);
731         int printed = 2, queue_len = 0;
732         int more = 0;
733         u64 len;
734
735         if (full_paths)
736                 d_filename = filename;
737         else
738                 d_filename = basename(filename);
739
740         len = symbol__size(sym);
741
742         printf(" Percent |      Source code & Disassembly of %s\n", d_filename);
743         printf("------------------------------------------------\n");
744
745         if (verbose)
746                 symbol__annotate_hits(sym, evidx);
747
748         list_for_each_entry(pos, &notes->src->source, node) {
749                 if (context && queue == NULL) {
750                         queue = pos;
751                         queue_len = 0;
752                 }
753
754                 switch (disasm_line__print(pos, sym, start, evidx, len,
755                                             min_pcnt, printed, max_lines,
756                                             queue)) {
757                 case 0:
758                         ++printed;
759                         if (context) {
760                                 printed += queue_len;
761                                 queue = NULL;
762                                 queue_len = 0;
763                         }
764                         break;
765                 case 1:
766                         /* filtered by max_lines */
767                         ++more;
768                         break;
769                 case -1:
770                 default:
771                         /*
772                          * Filtered by min_pcnt or non IP lines when
773                          * context != 0
774                          */
775                         if (!context)
776                                 break;
777                         if (queue_len == context)
778                                 queue = list_entry(queue->node.next, typeof(*queue), node);
779                         else
780                                 ++queue_len;
781                         break;
782                 }
783         }
784
785         return more;
786 }
787
788 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
789 {
790         struct annotation *notes = symbol__annotation(sym);
791         struct sym_hist *h = annotation__histogram(notes, evidx);
792
793         memset(h, 0, notes->src->sizeof_sym_hist);
794 }
795
796 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
797 {
798         struct annotation *notes = symbol__annotation(sym);
799         struct sym_hist *h = annotation__histogram(notes, evidx);
800         int len = symbol__size(sym), offset;
801
802         h->sum = 0;
803         for (offset = 0; offset < len; ++offset) {
804                 h->addr[offset] = h->addr[offset] * 7 / 8;
805                 h->sum += h->addr[offset];
806         }
807 }
808
809 void disasm__purge(struct list_head *head)
810 {
811         struct disasm_line *pos, *n;
812
813         list_for_each_entry_safe(pos, n, head, node) {
814                 list_del(&pos->node);
815                 disasm_line__free(pos);
816         }
817 }
818
819 static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
820 {
821         size_t printed;
822
823         if (dl->offset == -1)
824                 return fprintf(fp, "%s\n", dl->line);
825
826         printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
827
828         if (dl->ops.raw[0] != '\0') {
829                 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
830                                    dl->ops.raw);
831         }
832
833         return printed + fprintf(fp, "\n");
834 }
835
836 size_t disasm__fprintf(struct list_head *head, FILE *fp)
837 {
838         struct disasm_line *pos;
839         size_t printed = 0;
840
841         list_for_each_entry(pos, head, node)
842                 printed += disasm_line__fprintf(pos, fp);
843
844         return printed;
845 }
846
847 int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
848                          bool print_lines, bool full_paths, int min_pcnt,
849                          int max_lines)
850 {
851         struct dso *dso = map->dso;
852         const char *filename = dso->long_name;
853         struct rb_root source_line = RB_ROOT;
854         u64 len;
855
856         if (symbol__annotate(sym, map, 0) < 0)
857                 return -1;
858
859         len = symbol__size(sym);
860
861         if (print_lines) {
862                 symbol__get_source_line(sym, map, evidx, &source_line,
863                                         len, filename);
864                 print_summary(&source_line, filename);
865         }
866
867         symbol__annotate_printf(sym, map, evidx, full_paths,
868                                 min_pcnt, max_lines, 0);
869         if (print_lines)
870                 symbol__free_source_line(sym, len);
871
872         disasm__purge(&symbol__annotation(sym)->src->source);
873
874         return 0;
875 }