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