1
2
3
4
5
6
7
8
9#include <errno.h>
10#include <inttypes.h>
11#include <libgen.h>
12#include <bpf/bpf.h>
13#include <bpf/btf.h>
14#include <bpf/libbpf.h>
15#include <linux/btf.h>
16#include "util.h"
17#include "ui/ui.h"
18#include "sort.h"
19#include "build-id.h"
20#include "color.h"
21#include "config.h"
22#include "cache.h"
23#include "map.h"
24#include "symbol.h"
25#include "units.h"
26#include "debug.h"
27#include "annotate.h"
28#include "evsel.h"
29#include "evlist.h"
30#include "bpf-event.h"
31#include "block-range.h"
32#include "string2.h"
33#include "arch/common.h"
34#include <regex.h>
35#include <pthread.h>
36#include <linux/bitops.h>
37#include <linux/kernel.h>
38#include <bpf/libbpf.h>
39
40
41#include "ui/browser.h"
42
43
44
45
46
47#define LARROW_CHAR ((unsigned char)',')
48#define RARROW_CHAR ((unsigned char)'+')
49#define DARROW_CHAR ((unsigned char)'.')
50#define UARROW_CHAR ((unsigned char)'-')
51
52#include "sane_ctype.h"
53
54struct annotation_options annotation__default_options = {
55 .use_offset = true,
56 .jump_arrows = true,
57 .annotate_src = true,
58 .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS,
59 .percent_type = PERCENT_PERIOD_LOCAL,
60};
61
62static regex_t file_lineno;
63
64static struct ins_ops *ins__find(struct arch *arch, const char *name);
65static void ins__sort(struct arch *arch);
66static int disasm_line__parse(char *line, const char **namep, char **rawp);
67
68struct arch {
69 const char *name;
70 struct ins *instructions;
71 size_t nr_instructions;
72 size_t nr_instructions_allocated;
73 struct ins_ops *(*associate_instruction_ops)(struct arch *arch, const char *name);
74 bool sorted_instructions;
75 bool initialized;
76 void *priv;
77 unsigned int model;
78 unsigned int family;
79 int (*init)(struct arch *arch, char *cpuid);
80 bool (*ins_is_fused)(struct arch *arch, const char *ins1,
81 const char *ins2);
82 struct {
83 char comment_char;
84 char skip_functions_char;
85 } objdump;
86};
87
88static struct ins_ops call_ops;
89static struct ins_ops dec_ops;
90static struct ins_ops jump_ops;
91static struct ins_ops mov_ops;
92static struct ins_ops nop_ops;
93static struct ins_ops lock_ops;
94static struct ins_ops ret_ops;
95
96static int arch__grow_instructions(struct arch *arch)
97{
98 struct ins *new_instructions;
99 size_t new_nr_allocated;
100
101 if (arch->nr_instructions_allocated == 0 && arch->instructions)
102 goto grow_from_non_allocated_table;
103
104 new_nr_allocated = arch->nr_instructions_allocated + 128;
105 new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins));
106 if (new_instructions == NULL)
107 return -1;
108
109out_update_instructions:
110 arch->instructions = new_instructions;
111 arch->nr_instructions_allocated = new_nr_allocated;
112 return 0;
113
114grow_from_non_allocated_table:
115 new_nr_allocated = arch->nr_instructions + 128;
116 new_instructions = calloc(new_nr_allocated, sizeof(struct ins));
117 if (new_instructions == NULL)
118 return -1;
119
120 memcpy(new_instructions, arch->instructions, arch->nr_instructions);
121 goto out_update_instructions;
122}
123
124static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops)
125{
126 struct ins *ins;
127
128 if (arch->nr_instructions == arch->nr_instructions_allocated &&
129 arch__grow_instructions(arch))
130 return -1;
131
132 ins = &arch->instructions[arch->nr_instructions];
133 ins->name = strdup(name);
134 if (!ins->name)
135 return -1;
136
137 ins->ops = ops;
138 arch->nr_instructions++;
139
140 ins__sort(arch);
141 return 0;
142}
143
144#include "arch/arc/annotate/instructions.c"
145#include "arch/arm/annotate/instructions.c"
146#include "arch/arm64/annotate/instructions.c"
147#include "arch/x86/annotate/instructions.c"
148#include "arch/powerpc/annotate/instructions.c"
149#include "arch/s390/annotate/instructions.c"
150#include "arch/sparc/annotate/instructions.c"
151
152static struct arch architectures[] = {
153 {
154 .name = "arc",
155 .init = arc__annotate_init,
156 },
157 {
158 .name = "arm",
159 .init = arm__annotate_init,
160 },
161 {
162 .name = "arm64",
163 .init = arm64__annotate_init,
164 },
165 {
166 .name = "x86",
167 .init = x86__annotate_init,
168 .instructions = x86__instructions,
169 .nr_instructions = ARRAY_SIZE(x86__instructions),
170 .ins_is_fused = x86__ins_is_fused,
171 .objdump = {
172 .comment_char = '#',
173 },
174 },
175 {
176 .name = "powerpc",
177 .init = powerpc__annotate_init,
178 },
179 {
180 .name = "s390",
181 .init = s390__annotate_init,
182 .objdump = {
183 .comment_char = '#',
184 },
185 },
186 {
187 .name = "sparc",
188 .init = sparc__annotate_init,
189 .objdump = {
190 .comment_char = '#',
191 },
192 },
193};
194
195static void ins__delete(struct ins_operands *ops)
196{
197 if (ops == NULL)
198 return;
199 zfree(&ops->source.raw);
200 zfree(&ops->source.name);
201 zfree(&ops->target.raw);
202 zfree(&ops->target.name);
203}
204
205static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
206 struct ins_operands *ops, int max_ins_name)
207{
208 return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->raw);
209}
210
211int ins__scnprintf(struct ins *ins, char *bf, size_t size,
212 struct ins_operands *ops, int max_ins_name)
213{
214 if (ins->ops->scnprintf)
215 return ins->ops->scnprintf(ins, bf, size, ops, max_ins_name);
216
217 return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
218}
219
220bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2)
221{
222 if (!arch || !arch->ins_is_fused)
223 return false;
224
225 return arch->ins_is_fused(arch, ins1, ins2);
226}
227
228static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
229{
230 char *endptr, *tok, *name;
231 struct map *map = ms->map;
232 struct addr_map_symbol target = {
233 .map = map,
234 };
235
236 ops->target.addr = strtoull(ops->raw, &endptr, 16);
237
238 name = strchr(endptr, '<');
239 if (name == NULL)
240 goto indirect_call;
241
242 name++;
243
244 if (arch->objdump.skip_functions_char &&
245 strchr(name, arch->objdump.skip_functions_char))
246 return -1;
247
248 tok = strchr(name, '>');
249 if (tok == NULL)
250 return -1;
251
252 *tok = '\0';
253 ops->target.name = strdup(name);
254 *tok = '>';
255
256 if (ops->target.name == NULL)
257 return -1;
258find_target:
259 target.addr = map__objdump_2mem(map, ops->target.addr);
260
261 if (map_groups__find_ams(&target) == 0 &&
262 map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
263 ops->target.sym = target.sym;
264
265 return 0;
266
267indirect_call:
268 tok = strchr(endptr, '*');
269 if (tok != NULL) {
270 endptr++;
271
272
273
274 if (strstr(endptr, "(%r") == NULL)
275 ops->target.addr = strtoull(endptr, NULL, 16);
276 }
277 goto find_target;
278}
279
280static int call__scnprintf(struct ins *ins, char *bf, size_t size,
281 struct ins_operands *ops, int max_ins_name)
282{
283 if (ops->target.sym)
284 return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name);
285
286 if (ops->target.addr == 0)
287 return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
288
289 if (ops->target.name)
290 return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.name);
291
292 return scnprintf(bf, size, "%-*s *%" PRIx64, max_ins_name, ins->name, ops->target.addr);
293}
294
295static struct ins_ops call_ops = {
296 .parse = call__parse,
297 .scnprintf = call__scnprintf,
298};
299
300bool ins__is_call(const struct ins *ins)
301{
302 return ins->ops == &call_ops || ins->ops == &s390_call_ops;
303}
304
305
306
307
308
309static inline const char *validate_comma(const char *c, struct ins_operands *ops)
310{
311 if (ops->raw_comment && c > ops->raw_comment)
312 return NULL;
313
314 return c;
315}
316
317static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
318{
319 struct map *map = ms->map;
320 struct symbol *sym = ms->sym;
321 struct addr_map_symbol target = {
322 .map = map,
323 };
324 const char *c = strchr(ops->raw, ',');
325 u64 start, end;
326
327 ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
328 c = validate_comma(c, ops);
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345 if (c++ != NULL) {
346 ops->target.addr = strtoull(c, NULL, 16);
347 if (!ops->target.addr) {
348 c = strchr(c, ',');
349 c = validate_comma(c, ops);
350 if (c++ != NULL)
351 ops->target.addr = strtoull(c, NULL, 16);
352 }
353 } else {
354 ops->target.addr = strtoull(ops->raw, NULL, 16);
355 }
356
357 target.addr = map__objdump_2mem(map, ops->target.addr);
358 start = map->unmap_ip(map, sym->start),
359 end = map->unmap_ip(map, sym->end);
360
361 ops->target.outside = target.addr < start || target.addr > end;
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 if (map_groups__find_ams(&target) == 0 &&
382 map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
383 ops->target.sym = target.sym;
384
385 if (!ops->target.outside) {
386 ops->target.offset = target.addr - start;
387 ops->target.offset_avail = true;
388 } else {
389 ops->target.offset_avail = false;
390 }
391
392 return 0;
393}
394
395static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
396 struct ins_operands *ops, int max_ins_name)
397{
398 const char *c;
399
400 if (!ops->target.addr || ops->target.offset < 0)
401 return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
402
403 if (ops->target.outside && ops->target.sym != NULL)
404 return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name, ops->target.sym->name);
405
406 c = strchr(ops->raw, ',');
407 c = validate_comma(c, ops);
408
409 if (c != NULL) {
410 const char *c2 = strchr(c + 1, ',');
411
412 c2 = validate_comma(c2, ops);
413
414 if (c2 != NULL)
415 c = c2;
416 c++;
417
418
419 if (*c == ' ')
420 c++;
421 }
422
423 return scnprintf(bf, size, "%-*s %.*s%" PRIx64, max_ins_name,
424 ins->name, c ? c - ops->raw : 0, ops->raw,
425 ops->target.offset);
426}
427
428static struct ins_ops jump_ops = {
429 .parse = jump__parse,
430 .scnprintf = jump__scnprintf,
431};
432
433bool ins__is_jump(const struct ins *ins)
434{
435 return ins->ops == &jump_ops;
436}
437
438static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
439{
440 char *endptr, *name, *t;
441
442 if (strstr(raw, "(%rip)") == NULL)
443 return 0;
444
445 *addrp = strtoull(comment, &endptr, 16);
446 if (endptr == comment)
447 return 0;
448 name = strchr(endptr, '<');
449 if (name == NULL)
450 return -1;
451
452 name++;
453
454 t = strchr(name, '>');
455 if (t == NULL)
456 return 0;
457
458 *t = '\0';
459 *namep = strdup(name);
460 *t = '>';
461
462 return 0;
463}
464
465static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
466{
467 ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
468 if (ops->locked.ops == NULL)
469 return 0;
470
471 if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0)
472 goto out_free_ops;
473
474 ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name);
475
476 if (ops->locked.ins.ops == NULL)
477 goto out_free_ops;
478
479 if (ops->locked.ins.ops->parse &&
480 ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0)
481 goto out_free_ops;
482
483 return 0;
484
485out_free_ops:
486 zfree(&ops->locked.ops);
487 return 0;
488}
489
490static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
491 struct ins_operands *ops, int max_ins_name)
492{
493 int printed;
494
495 if (ops->locked.ins.ops == NULL)
496 return ins__raw_scnprintf(ins, bf, size, ops, max_ins_name);
497
498 printed = scnprintf(bf, size, "%-*s ", max_ins_name, ins->name);
499 return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
500 size - printed, ops->locked.ops, max_ins_name);
501}
502
503static void lock__delete(struct ins_operands *ops)
504{
505 struct ins *ins = &ops->locked.ins;
506
507 if (ins->ops && ins->ops->free)
508 ins->ops->free(ops->locked.ops);
509 else
510 ins__delete(ops->locked.ops);
511
512 zfree(&ops->locked.ops);
513 zfree(&ops->target.raw);
514 zfree(&ops->target.name);
515}
516
517static struct ins_ops lock_ops = {
518 .free = lock__delete,
519 .parse = lock__parse,
520 .scnprintf = lock__scnprintf,
521};
522
523static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
524{
525 char *s = strchr(ops->raw, ','), *target, *comment, prev;
526
527 if (s == NULL)
528 return -1;
529
530 *s = '\0';
531 ops->source.raw = strdup(ops->raw);
532 *s = ',';
533
534 if (ops->source.raw == NULL)
535 return -1;
536
537 target = ++s;
538 comment = strchr(s, arch->objdump.comment_char);
539
540 if (comment != NULL)
541 s = comment - 1;
542 else
543 s = strchr(s, '\0') - 1;
544
545 while (s > target && isspace(s[0]))
546 --s;
547 s++;
548 prev = *s;
549 *s = '\0';
550
551 ops->target.raw = strdup(target);
552 *s = prev;
553
554 if (ops->target.raw == NULL)
555 goto out_free_source;
556
557 if (comment == NULL)
558 return 0;
559
560 comment = ltrim(comment);
561 comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name);
562 comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
563
564 return 0;
565
566out_free_source:
567 zfree(&ops->source.raw);
568 return -1;
569}
570
571static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
572 struct ins_operands *ops, int max_ins_name)
573{
574 return scnprintf(bf, size, "%-*s %s,%s", max_ins_name, ins->name,
575 ops->source.name ?: ops->source.raw,
576 ops->target.name ?: ops->target.raw);
577}
578
579static struct ins_ops mov_ops = {
580 .parse = mov__parse,
581 .scnprintf = mov__scnprintf,
582};
583
584static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
585{
586 char *target, *comment, *s, prev;
587
588 target = s = ops->raw;
589
590 while (s[0] != '\0' && !isspace(s[0]))
591 ++s;
592 prev = *s;
593 *s = '\0';
594
595 ops->target.raw = strdup(target);
596 *s = prev;
597
598 if (ops->target.raw == NULL)
599 return -1;
600
601 comment = strchr(s, arch->objdump.comment_char);
602 if (comment == NULL)
603 return 0;
604
605 comment = ltrim(comment);
606 comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
607
608 return 0;
609}
610
611static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
612 struct ins_operands *ops, int max_ins_name)
613{
614 return scnprintf(bf, size, "%-*s %s", max_ins_name, ins->name,
615 ops->target.name ?: ops->target.raw);
616}
617
618static struct ins_ops dec_ops = {
619 .parse = dec__parse,
620 .scnprintf = dec__scnprintf,
621};
622
623static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
624 struct ins_operands *ops __maybe_unused, int max_ins_name)
625{
626 return scnprintf(bf, size, "%-*s", max_ins_name, "nop");
627}
628
629static struct ins_ops nop_ops = {
630 .scnprintf = nop__scnprintf,
631};
632
633static struct ins_ops ret_ops = {
634 .scnprintf = ins__raw_scnprintf,
635};
636
637bool ins__is_ret(const struct ins *ins)
638{
639 return ins->ops == &ret_ops;
640}
641
642bool ins__is_lock(const struct ins *ins)
643{
644 return ins->ops == &lock_ops;
645}
646
647static int ins__key_cmp(const void *name, const void *insp)
648{
649 const struct ins *ins = insp;
650
651 return strcmp(name, ins->name);
652}
653
654static int ins__cmp(const void *a, const void *b)
655{
656 const struct ins *ia = a;
657 const struct ins *ib = b;
658
659 return strcmp(ia->name, ib->name);
660}
661
662static void ins__sort(struct arch *arch)
663{
664 const int nmemb = arch->nr_instructions;
665
666 qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
667}
668
669static struct ins_ops *__ins__find(struct arch *arch, const char *name)
670{
671 struct ins *ins;
672 const int nmemb = arch->nr_instructions;
673
674 if (!arch->sorted_instructions) {
675 ins__sort(arch);
676 arch->sorted_instructions = true;
677 }
678
679 ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
680 return ins ? ins->ops : NULL;
681}
682
683static struct ins_ops *ins__find(struct arch *arch, const char *name)
684{
685 struct ins_ops *ops = __ins__find(arch, name);
686
687 if (!ops && arch->associate_instruction_ops)
688 ops = arch->associate_instruction_ops(arch, name);
689
690 return ops;
691}
692
693static int arch__key_cmp(const void *name, const void *archp)
694{
695 const struct arch *arch = archp;
696
697 return strcmp(name, arch->name);
698}
699
700static int arch__cmp(const void *a, const void *b)
701{
702 const struct arch *aa = a;
703 const struct arch *ab = b;
704
705 return strcmp(aa->name, ab->name);
706}
707
708static void arch__sort(void)
709{
710 const int nmemb = ARRAY_SIZE(architectures);
711
712 qsort(architectures, nmemb, sizeof(struct arch), arch__cmp);
713}
714
715static struct arch *arch__find(const char *name)
716{
717 const int nmemb = ARRAY_SIZE(architectures);
718 static bool sorted;
719
720 if (!sorted) {
721 arch__sort();
722 sorted = true;
723 }
724
725 return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
726}
727
728static struct annotated_source *annotated_source__new(void)
729{
730 struct annotated_source *src = zalloc(sizeof(*src));
731
732 if (src != NULL)
733 INIT_LIST_HEAD(&src->source);
734
735 return src;
736}
737
738static __maybe_unused void annotated_source__delete(struct annotated_source *src)
739{
740 if (src == NULL)
741 return;
742 zfree(&src->histograms);
743 zfree(&src->cycles_hist);
744 free(src);
745}
746
747static int annotated_source__alloc_histograms(struct annotated_source *src,
748 size_t size, int nr_hists)
749{
750 size_t sizeof_sym_hist;
751
752
753
754
755
756
757
758
759 if (size == 0)
760 size = 1;
761
762
763 if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(struct sym_hist_entry))
764 return -1;
765
766 sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry));
767
768
769 if (sizeof_sym_hist > SIZE_MAX / nr_hists)
770 return -1;
771
772 src->sizeof_sym_hist = sizeof_sym_hist;
773 src->nr_histograms = nr_hists;
774 src->histograms = calloc(nr_hists, sizeof_sym_hist) ;
775 return src->histograms ? 0 : -1;
776}
777
778
779static int symbol__alloc_hist_cycles(struct symbol *sym)
780{
781 struct annotation *notes = symbol__annotation(sym);
782 const size_t size = symbol__size(sym);
783
784 notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
785 if (notes->src->cycles_hist == NULL)
786 return -1;
787 return 0;
788}
789
790void symbol__annotate_zero_histograms(struct symbol *sym)
791{
792 struct annotation *notes = symbol__annotation(sym);
793
794 pthread_mutex_lock(¬es->lock);
795 if (notes->src != NULL) {
796 memset(notes->src->histograms, 0,
797 notes->src->nr_histograms * notes->src->sizeof_sym_hist);
798 if (notes->src->cycles_hist)
799 memset(notes->src->cycles_hist, 0,
800 symbol__size(sym) * sizeof(struct cyc_hist));
801 }
802 pthread_mutex_unlock(¬es->lock);
803}
804
805static int __symbol__account_cycles(struct cyc_hist *ch,
806 u64 start,
807 unsigned offset, unsigned cycles,
808 unsigned have_start)
809{
810
811
812
813
814
815
816
817
818 ch[offset].num_aggr++;
819 ch[offset].cycles_aggr += cycles;
820
821 if (cycles > ch[offset].cycles_max)
822 ch[offset].cycles_max = cycles;
823
824 if (ch[offset].cycles_min) {
825 if (cycles && cycles < ch[offset].cycles_min)
826 ch[offset].cycles_min = cycles;
827 } else
828 ch[offset].cycles_min = cycles;
829
830 if (!have_start && ch[offset].have_start)
831 return 0;
832 if (ch[offset].num) {
833 if (have_start && (!ch[offset].have_start ||
834 ch[offset].start > start)) {
835 ch[offset].have_start = 0;
836 ch[offset].cycles = 0;
837 ch[offset].num = 0;
838 if (ch[offset].reset < 0xffff)
839 ch[offset].reset++;
840 } else if (have_start &&
841 ch[offset].start < start)
842 return 0;
843 }
844 ch[offset].have_start = have_start;
845 ch[offset].start = start;
846 ch[offset].cycles += cycles;
847 ch[offset].num++;
848 return 0;
849}
850
851static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
852 struct annotated_source *src, int evidx, u64 addr,
853 struct perf_sample *sample)
854{
855 unsigned offset;
856 struct sym_hist *h;
857
858 pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
859
860 if ((addr < sym->start || addr >= sym->end) &&
861 (addr != sym->end || sym->start != sym->end)) {
862 pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
863 __func__, __LINE__, sym->name, sym->start, addr, sym->end);
864 return -ERANGE;
865 }
866
867 offset = addr - sym->start;
868 h = annotated_source__histogram(src, evidx);
869 if (h == NULL) {
870 pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
871 __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
872 return -ENOMEM;
873 }
874 h->nr_samples++;
875 h->addr[offset].nr_samples++;
876 h->period += sample->period;
877 h->addr[offset].period += sample->period;
878
879 pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
880 ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n",
881 sym->start, sym->name, addr, addr - sym->start, evidx,
882 h->addr[offset].nr_samples, h->addr[offset].period);
883 return 0;
884}
885
886static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
887{
888 struct annotation *notes = symbol__annotation(sym);
889
890 if (notes->src == NULL) {
891 notes->src = annotated_source__new();
892 if (notes->src == NULL)
893 return NULL;
894 goto alloc_cycles_hist;
895 }
896
897 if (!notes->src->cycles_hist) {
898alloc_cycles_hist:
899 symbol__alloc_hist_cycles(sym);
900 }
901
902 return notes->src->cycles_hist;
903}
904
905struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
906{
907 struct annotation *notes = symbol__annotation(sym);
908
909 if (notes->src == NULL) {
910 notes->src = annotated_source__new();
911 if (notes->src == NULL)
912 return NULL;
913 goto alloc_histograms;
914 }
915
916 if (notes->src->histograms == NULL) {
917alloc_histograms:
918 annotated_source__alloc_histograms(notes->src, symbol__size(sym),
919 nr_hists);
920 }
921
922 return notes->src;
923}
924
925static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
926 struct perf_evsel *evsel, u64 addr,
927 struct perf_sample *sample)
928{
929 struct annotated_source *src;
930
931 if (sym == NULL)
932 return 0;
933 src = symbol__hists(sym, evsel->evlist->nr_entries);
934 if (src == NULL)
935 return -ENOMEM;
936 return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample);
937}
938
939static int symbol__account_cycles(u64 addr, u64 start,
940 struct symbol *sym, unsigned cycles)
941{
942 struct cyc_hist *cycles_hist;
943 unsigned offset;
944
945 if (sym == NULL)
946 return 0;
947 cycles_hist = symbol__cycles_hist(sym);
948 if (cycles_hist == NULL)
949 return -ENOMEM;
950 if (addr < sym->start || addr >= sym->end)
951 return -ERANGE;
952
953 if (start) {
954 if (start < sym->start || start >= sym->end)
955 return -ERANGE;
956 if (start >= addr)
957 start = 0;
958 }
959 offset = addr - sym->start;
960 return __symbol__account_cycles(cycles_hist,
961 start ? start - sym->start : 0,
962 offset, cycles,
963 !!start);
964}
965
966int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
967 struct addr_map_symbol *start,
968 unsigned cycles)
969{
970 u64 saddr = 0;
971 int err;
972
973 if (!cycles)
974 return 0;
975
976
977
978
979
980
981
982
983 if (start &&
984 (start->sym == ams->sym ||
985 (ams->sym &&
986 start->addr == ams->sym->start + ams->map->start)))
987 saddr = start->al_addr;
988 if (saddr == 0)
989 pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n",
990 ams->addr,
991 start ? start->addr : 0,
992 ams->sym ? ams->sym->start + ams->map->start : 0,
993 saddr);
994 err = symbol__account_cycles(ams->al_addr, saddr, ams->sym, cycles);
995 if (err)
996 pr_debug2("account_cycles failed %d\n", err);
997 return err;
998}
999
1000static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end)
1001{
1002 unsigned n_insn = 0;
1003 u64 offset;
1004
1005 for (offset = start; offset <= end; offset++) {
1006 if (notes->offsets[offset])
1007 n_insn++;
1008 }
1009 return n_insn;
1010}
1011
1012static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)
1013{
1014 unsigned n_insn;
1015 unsigned int cover_insn = 0;
1016 u64 offset;
1017
1018 n_insn = annotation__count_insn(notes, start, end);
1019 if (n_insn && ch->num && ch->cycles) {
1020 float ipc = n_insn / ((double)ch->cycles / (double)ch->num);
1021
1022
1023 if (ch->reset >= 0x7fff)
1024 return;
1025
1026 for (offset = start; offset <= end; offset++) {
1027 struct annotation_line *al = notes->offsets[offset];
1028
1029 if (al && al->ipc == 0.0) {
1030 al->ipc = ipc;
1031 cover_insn++;
1032 }
1033 }
1034
1035 if (cover_insn) {
1036 notes->hit_cycles += ch->cycles;
1037 notes->hit_insn += n_insn * ch->num;
1038 notes->cover_insn += cover_insn;
1039 }
1040 }
1041}
1042
1043void annotation__compute_ipc(struct annotation *notes, size_t size)
1044{
1045 s64 offset;
1046
1047 if (!notes->src || !notes->src->cycles_hist)
1048 return;
1049
1050 notes->total_insn = annotation__count_insn(notes, 0, size - 1);
1051 notes->hit_cycles = 0;
1052 notes->hit_insn = 0;
1053 notes->cover_insn = 0;
1054
1055 pthread_mutex_lock(¬es->lock);
1056 for (offset = size - 1; offset >= 0; --offset) {
1057 struct cyc_hist *ch;
1058
1059 ch = ¬es->src->cycles_hist[offset];
1060 if (ch && ch->cycles) {
1061 struct annotation_line *al;
1062
1063 if (ch->have_start)
1064 annotation__count_and_fill(notes, ch->start, offset, ch);
1065 al = notes->offsets[offset];
1066 if (al && ch->num_aggr) {
1067 al->cycles = ch->cycles_aggr / ch->num_aggr;
1068 al->cycles_max = ch->cycles_max;
1069 al->cycles_min = ch->cycles_min;
1070 }
1071 notes->have_cycles = true;
1072 }
1073 }
1074 pthread_mutex_unlock(¬es->lock);
1075}
1076
1077int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
1078 struct perf_evsel *evsel)
1079{
1080 return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample);
1081}
1082
1083int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
1084 struct perf_evsel *evsel, u64 ip)
1085{
1086 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample);
1087}
1088
1089static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms)
1090{
1091 dl->ins.ops = ins__find(arch, dl->ins.name);
1092
1093 if (!dl->ins.ops)
1094 return;
1095
1096 if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0)
1097 dl->ins.ops = NULL;
1098}
1099
1100static int disasm_line__parse(char *line, const char **namep, char **rawp)
1101{
1102 char tmp, *name = ltrim(line);
1103
1104 if (name[0] == '\0')
1105 return -1;
1106
1107 *rawp = name + 1;
1108
1109 while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
1110 ++*rawp;
1111
1112 tmp = (*rawp)[0];
1113 (*rawp)[0] = '\0';
1114 *namep = strdup(name);
1115
1116 if (*namep == NULL)
1117 goto out_free_name;
1118
1119 (*rawp)[0] = tmp;
1120 *rawp = ltrim(*rawp);
1121
1122 return 0;
1123
1124out_free_name:
1125 free((void *)namep);
1126 *namep = NULL;
1127 return -1;
1128}
1129
1130struct annotate_args {
1131 size_t privsize;
1132 struct arch *arch;
1133 struct map_symbol ms;
1134 struct perf_evsel *evsel;
1135 struct annotation_options *options;
1136 s64 offset;
1137 char *line;
1138 int line_nr;
1139};
1140
1141static void annotation_line__delete(struct annotation_line *al)
1142{
1143 void *ptr = (void *) al - al->privsize;
1144
1145 free_srcline(al->path);
1146 zfree(&al->line);
1147 free(ptr);
1148}
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161static struct annotation_line *
1162annotation_line__new(struct annotate_args *args, size_t privsize)
1163{
1164 struct annotation_line *al;
1165 struct perf_evsel *evsel = args->evsel;
1166 size_t size = privsize + sizeof(*al);
1167 int nr = 1;
1168
1169 if (perf_evsel__is_group_event(evsel))
1170 nr = evsel->nr_members;
1171
1172 size += sizeof(al->data[0]) * nr;
1173
1174 al = zalloc(size);
1175 if (al) {
1176 al = (void *) al + privsize;
1177 al->privsize = privsize;
1178 al->offset = args->offset;
1179 al->line = strdup(args->line);
1180 al->line_nr = args->line_nr;
1181 al->data_nr = nr;
1182 }
1183
1184 return al;
1185}
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199static struct disasm_line *disasm_line__new(struct annotate_args *args)
1200{
1201 struct disasm_line *dl = NULL;
1202 struct annotation_line *al;
1203 size_t privsize = args->privsize + offsetof(struct disasm_line, al);
1204
1205 al = annotation_line__new(args, privsize);
1206 if (al != NULL) {
1207 dl = disasm_line(al);
1208
1209 if (dl->al.line == NULL)
1210 goto out_delete;
1211
1212 if (args->offset != -1) {
1213 if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
1214 goto out_free_line;
1215
1216 disasm_line__init_ins(dl, args->arch, &args->ms);
1217 }
1218 }
1219
1220 return dl;
1221
1222out_free_line:
1223 zfree(&dl->al.line);
1224out_delete:
1225 free(dl);
1226 return NULL;
1227}
1228
1229void disasm_line__free(struct disasm_line *dl)
1230{
1231 if (dl->ins.ops && dl->ins.ops->free)
1232 dl->ins.ops->free(&dl->ops);
1233 else
1234 ins__delete(&dl->ops);
1235 free((void *)dl->ins.name);
1236 dl->ins.name = NULL;
1237 annotation_line__delete(&dl->al);
1238}
1239
1240int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw, int max_ins_name)
1241{
1242 if (raw || !dl->ins.ops)
1243 return scnprintf(bf, size, "%-*s %s", max_ins_name, dl->ins.name, dl->ops.raw);
1244
1245 return ins__scnprintf(&dl->ins, bf, size, &dl->ops, max_ins_name);
1246}
1247
1248static void annotation_line__add(struct annotation_line *al, struct list_head *head)
1249{
1250 list_add_tail(&al->node, head);
1251}
1252
1253struct annotation_line *
1254annotation_line__next(struct annotation_line *pos, struct list_head *head)
1255{
1256 list_for_each_entry_continue(pos, head, node)
1257 if (pos->offset >= 0)
1258 return pos;
1259
1260 return NULL;
1261}
1262
1263static const char *annotate__address_color(struct block_range *br)
1264{
1265 double cov = block_range__coverage(br);
1266
1267 if (cov >= 0) {
1268
1269 if (cov > 0.75)
1270 return PERF_COLOR_RED;
1271
1272
1273 if (cov < 0.01)
1274 return PERF_COLOR_NORMAL;
1275 }
1276
1277 return PERF_COLOR_MAGENTA;
1278}
1279
1280static const char *annotate__asm_color(struct block_range *br)
1281{
1282 double cov = block_range__coverage(br);
1283
1284 if (cov >= 0) {
1285
1286 if (cov < 0.01)
1287 return PERF_COLOR_NORMAL;
1288 }
1289
1290 return PERF_COLOR_BLUE;
1291}
1292
1293static void annotate__branch_printf(struct block_range *br, u64 addr)
1294{
1295 bool emit_comment = true;
1296
1297 if (!br)
1298 return;
1299
1300#if 1
1301 if (br->is_target && br->start == addr) {
1302 struct block_range *branch = br;
1303 double p;
1304
1305
1306
1307
1308 while (!branch->is_branch)
1309 branch = block_range__next(branch);
1310
1311 p = 100 *(double)br->entry / branch->coverage;
1312
1313 if (p > 0.1) {
1314 if (emit_comment) {
1315 emit_comment = false;
1316 printf("\t#");
1317 }
1318
1319
1320
1321
1322
1323 printf(" +%.2f%%", p);
1324 }
1325 }
1326#endif
1327 if (br->is_branch && br->end == addr) {
1328 double p = 100*(double)br->taken / br->coverage;
1329
1330 if (p > 0.1) {
1331 if (emit_comment) {
1332 emit_comment = false;
1333 printf("\t#");
1334 }
1335
1336
1337
1338
1339
1340 printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred / br->taken);
1341 }
1342 }
1343}
1344
1345static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width)
1346{
1347 s64 offset = dl->al.offset;
1348 const u64 addr = start + offset;
1349 struct block_range *br;
1350
1351 br = block_range__find(addr);
1352 color_fprintf(stdout, annotate__address_color(br), " %*" PRIx64 ":", addr_fmt_width, addr);
1353 color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line);
1354 annotate__branch_printf(br, addr);
1355 return 0;
1356}
1357
1358static int
1359annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start,
1360 struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
1361 int max_lines, struct annotation_line *queue, int addr_fmt_width,
1362 int percent_type)
1363{
1364 struct disasm_line *dl = container_of(al, struct disasm_line, al);
1365 static const char *prev_line;
1366 static const char *prev_color;
1367
1368 if (al->offset != -1) {
1369 double max_percent = 0.0;
1370 int i, nr_percent = 1;
1371 const char *color;
1372 struct annotation *notes = symbol__annotation(sym);
1373
1374 for (i = 0; i < al->data_nr; i++) {
1375 double percent;
1376
1377 percent = annotation_data__percent(&al->data[i],
1378 percent_type);
1379
1380 if (percent > max_percent)
1381 max_percent = percent;
1382 }
1383
1384 if (al->data_nr > nr_percent)
1385 nr_percent = al->data_nr;
1386
1387 if (max_percent < min_pcnt)
1388 return -1;
1389
1390 if (max_lines && printed >= max_lines)
1391 return 1;
1392
1393 if (queue != NULL) {
1394 list_for_each_entry_from(queue, ¬es->src->source, node) {
1395 if (queue == al)
1396 break;
1397 annotation_line__print(queue, sym, start, evsel, len,
1398 0, 0, 1, NULL, addr_fmt_width,
1399 percent_type);
1400 }
1401 }
1402
1403 color = get_percent_color(max_percent);
1404
1405
1406
1407
1408
1409
1410 if (al->path) {
1411 if (!prev_line || strcmp(prev_line, al->path)
1412 || color != prev_color) {
1413 color_fprintf(stdout, color, " %s", al->path);
1414 prev_line = al->path;
1415 prev_color = color;
1416 }
1417 }
1418
1419 for (i = 0; i < nr_percent; i++) {
1420 struct annotation_data *data = &al->data[i];
1421 double percent;
1422
1423 percent = annotation_data__percent(data, percent_type);
1424 color = get_percent_color(percent);
1425
1426 if (symbol_conf.show_total_period)
1427 color_fprintf(stdout, color, " %11" PRIu64,
1428 data->he.period);
1429 else if (symbol_conf.show_nr_samples)
1430 color_fprintf(stdout, color, " %7" PRIu64,
1431 data->he.nr_samples);
1432 else
1433 color_fprintf(stdout, color, " %7.2f", percent);
1434 }
1435
1436 printf(" : ");
1437
1438 disasm_line__print(dl, start, addr_fmt_width);
1439 printf("\n");
1440 } else if (max_lines && printed >= max_lines)
1441 return 1;
1442 else {
1443 int width = symbol_conf.show_total_period ? 12 : 8;
1444
1445 if (queue)
1446 return -1;
1447
1448 if (perf_evsel__is_group_event(evsel))
1449 width *= evsel->nr_members;
1450
1451 if (!*al->line)
1452 printf(" %*s:\n", width, " ");
1453 else
1454 printf(" %*s: %*s %s\n", width, " ", addr_fmt_width, " ", al->line);
1455 }
1456
1457 return 0;
1458}
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
1481 struct annotate_args *args,
1482 int *line_nr)
1483{
1484 struct map *map = args->ms.map;
1485 struct annotation *notes = symbol__annotation(sym);
1486 struct disasm_line *dl;
1487 char *line = NULL, *parsed_line, *tmp, *tmp2;
1488 size_t line_len;
1489 s64 line_ip, offset = -1;
1490 regmatch_t match[2];
1491
1492 if (getline(&line, &line_len, file) < 0)
1493 return -1;
1494
1495 if (!line)
1496 return -1;
1497
1498 line_ip = -1;
1499 parsed_line = rtrim(line);
1500
1501
1502 if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
1503 *line_nr = atoi(parsed_line + match[1].rm_so);
1504 return 0;
1505 }
1506
1507 tmp = ltrim(parsed_line);
1508 if (*tmp) {
1509
1510
1511
1512 line_ip = strtoull(tmp, &tmp2, 16);
1513 if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
1514 line_ip = -1;
1515 }
1516
1517 if (line_ip != -1) {
1518 u64 start = map__rip_2objdump(map, sym->start),
1519 end = map__rip_2objdump(map, sym->end);
1520
1521 offset = line_ip - start;
1522 if ((u64)line_ip < start || (u64)line_ip >= end)
1523 offset = -1;
1524 else
1525 parsed_line = tmp2 + 1;
1526 }
1527
1528 args->offset = offset;
1529 args->line = parsed_line;
1530 args->line_nr = *line_nr;
1531 args->ms.sym = sym;
1532
1533 dl = disasm_line__new(args);
1534 free(line);
1535 (*line_nr)++;
1536
1537 if (dl == NULL)
1538 return -1;
1539
1540 if (!disasm_line__has_local_offset(dl)) {
1541 dl->ops.target.offset = dl->ops.target.addr -
1542 map__rip_2objdump(map, sym->start);
1543 dl->ops.target.offset_avail = true;
1544 }
1545
1546
1547 if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) {
1548 struct addr_map_symbol target = {
1549 .map = map,
1550 .addr = dl->ops.target.addr,
1551 };
1552
1553 if (!map_groups__find_ams(&target) &&
1554 target.sym->start == target.al_addr)
1555 dl->ops.target.sym = target.sym;
1556 }
1557
1558 annotation_line__add(&dl->al, ¬es->src->source);
1559
1560 return 0;
1561}
1562
1563static __attribute__((constructor)) void symbol__init_regexpr(void)
1564{
1565 regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);
1566}
1567
1568static void delete_last_nop(struct symbol *sym)
1569{
1570 struct annotation *notes = symbol__annotation(sym);
1571 struct list_head *list = ¬es->src->source;
1572 struct disasm_line *dl;
1573
1574 while (!list_empty(list)) {
1575 dl = list_entry(list->prev, struct disasm_line, al.node);
1576
1577 if (dl->ins.ops) {
1578 if (dl->ins.ops != &nop_ops)
1579 return;
1580 } else {
1581 if (!strstr(dl->al.line, " nop ") &&
1582 !strstr(dl->al.line, " nopl ") &&
1583 !strstr(dl->al.line, " nopw "))
1584 return;
1585 }
1586
1587 list_del(&dl->al.node);
1588 disasm_line__free(dl);
1589 }
1590}
1591
1592int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
1593 int errnum, char *buf, size_t buflen)
1594{
1595 struct dso *dso = map->dso;
1596
1597 BUG_ON(buflen == 0);
1598
1599 if (errnum >= 0) {
1600 str_error_r(errnum, buf, buflen);
1601 return 0;
1602 }
1603
1604 switch (errnum) {
1605 case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: {
1606 char bf[SBUILD_ID_SIZE + 15] = " with build id ";
1607 char *build_id_msg = NULL;
1608
1609 if (dso->has_build_id) {
1610 build_id__sprintf(dso->build_id,
1611 sizeof(dso->build_id), bf + 15);
1612 build_id_msg = bf;
1613 }
1614 scnprintf(buf, buflen,
1615 "No vmlinux file%s\nwas found in the path.\n\n"
1616 "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
1617 "Please use:\n\n"
1618 " perf buildid-cache -vu vmlinux\n\n"
1619 "or:\n\n"
1620 " --vmlinux vmlinux\n", build_id_msg ?: "");
1621 }
1622 break;
1623 case SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF:
1624 scnprintf(buf, buflen, "Please link with binutils's libopcode to enable BPF annotation");
1625 break;
1626 default:
1627 scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
1628 break;
1629 }
1630
1631 return 0;
1632}
1633
1634static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size)
1635{
1636 char linkname[PATH_MAX];
1637 char *build_id_filename;
1638 char *build_id_path = NULL;
1639 char *pos;
1640
1641 if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
1642 !dso__is_kcore(dso))
1643 return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
1644
1645 build_id_filename = dso__build_id_filename(dso, NULL, 0, false);
1646 if (build_id_filename) {
1647 __symbol__join_symfs(filename, filename_size, build_id_filename);
1648 free(build_id_filename);
1649 } else {
1650 if (dso->has_build_id)
1651 return ENOMEM;
1652 goto fallback;
1653 }
1654
1655 build_id_path = strdup(filename);
1656 if (!build_id_path)
1657 return -1;
1658
1659
1660
1661
1662
1663
1664 pos = strrchr(build_id_path, '/');
1665 if (pos && strlen(pos) < SBUILD_ID_SIZE - 2)
1666 dirname(build_id_path);
1667
1668 if (dso__is_kcore(dso) ||
1669 readlink(build_id_path, linkname, sizeof(linkname)) < 0 ||
1670 strstr(linkname, DSO__NAME_KALLSYMS) ||
1671 access(filename, R_OK)) {
1672fallback:
1673
1674
1675
1676
1677
1678 __symbol__join_symfs(filename, filename_size, dso->long_name);
1679 }
1680
1681 free(build_id_path);
1682 return 0;
1683}
1684
1685#if defined(HAVE_LIBBFD_SUPPORT) && defined(HAVE_LIBBPF_SUPPORT)
1686#define PACKAGE "perf"
1687#include <bfd.h>
1688#include <dis-asm.h>
1689
1690static int symbol__disassemble_bpf(struct symbol *sym,
1691 struct annotate_args *args)
1692{
1693 struct annotation *notes = symbol__annotation(sym);
1694 struct annotation_options *opts = args->options;
1695 struct bpf_prog_info_linear *info_linear;
1696 struct bpf_prog_linfo *prog_linfo = NULL;
1697 struct bpf_prog_info_node *info_node;
1698 int len = sym->end - sym->start;
1699 disassembler_ftype disassemble;
1700 struct map *map = args->ms.map;
1701 struct disassemble_info info;
1702 struct dso *dso = map->dso;
1703 int pc = 0, count, sub_id;
1704 struct btf *btf = NULL;
1705 char tpath[PATH_MAX];
1706 size_t buf_size;
1707 int nr_skip = 0;
1708 int ret = -1;
1709 char *buf;
1710 bfd *bfdf;
1711 FILE *s;
1712
1713 if (dso->binary_type != DSO_BINARY_TYPE__BPF_PROG_INFO)
1714 return -1;
1715
1716 pr_debug("%s: handling sym %s addr %" PRIx64 " len %" PRIx64 "\n", __func__,
1717 sym->name, sym->start, sym->end - sym->start);
1718
1719 memset(tpath, 0, sizeof(tpath));
1720 perf_exe(tpath, sizeof(tpath));
1721
1722 bfdf = bfd_openr(tpath, NULL);
1723 assert(bfdf);
1724 assert(bfd_check_format(bfdf, bfd_object));
1725
1726 s = open_memstream(&buf, &buf_size);
1727 if (!s)
1728 goto out;
1729 init_disassemble_info(&info, s,
1730 (fprintf_ftype) fprintf);
1731
1732 info.arch = bfd_get_arch(bfdf);
1733 info.mach = bfd_get_mach(bfdf);
1734
1735 info_node = perf_env__find_bpf_prog_info(dso->bpf_prog.env,
1736 dso->bpf_prog.id);
1737 if (!info_node)
1738 goto out;
1739 info_linear = info_node->info_linear;
1740 sub_id = dso->bpf_prog.sub_id;
1741
1742 info.buffer = (void *)(uintptr_t)(info_linear->info.jited_prog_insns);
1743 info.buffer_length = info_linear->info.jited_prog_len;
1744
1745 if (info_linear->info.nr_line_info)
1746 prog_linfo = bpf_prog_linfo__new(&info_linear->info);
1747
1748 if (info_linear->info.btf_id) {
1749 struct btf_node *node;
1750
1751 node = perf_env__find_btf(dso->bpf_prog.env,
1752 info_linear->info.btf_id);
1753 if (node)
1754 btf = btf__new((__u8 *)(node->data),
1755 node->data_size);
1756 }
1757
1758 disassemble_init_for_target(&info);
1759
1760#ifdef DISASM_FOUR_ARGS_SIGNATURE
1761 disassemble = disassembler(info.arch,
1762 bfd_big_endian(bfdf),
1763 info.mach,
1764 bfdf);
1765#else
1766 disassemble = disassembler(bfdf);
1767#endif
1768 assert(disassemble);
1769
1770 fflush(s);
1771 do {
1772 const struct bpf_line_info *linfo = NULL;
1773 struct disasm_line *dl;
1774 size_t prev_buf_size;
1775 const char *srcline;
1776 u64 addr;
1777
1778 addr = pc + ((u64 *)(uintptr_t)(info_linear->info.jited_ksyms))[sub_id];
1779 count = disassemble(pc, &info);
1780
1781 if (prog_linfo)
1782 linfo = bpf_prog_linfo__lfind_addr_func(prog_linfo,
1783 addr, sub_id,
1784 nr_skip);
1785
1786 if (linfo && btf) {
1787 srcline = btf__name_by_offset(btf, linfo->line_off);
1788 nr_skip++;
1789 } else
1790 srcline = NULL;
1791
1792 fprintf(s, "\n");
1793 prev_buf_size = buf_size;
1794 fflush(s);
1795
1796 if (!opts->hide_src_code && srcline) {
1797 args->offset = -1;
1798 args->line = strdup(srcline);
1799 args->line_nr = 0;
1800 args->ms.sym = sym;
1801 dl = disasm_line__new(args);
1802 if (dl) {
1803 annotation_line__add(&dl->al,
1804 ¬es->src->source);
1805 }
1806 }
1807
1808 args->offset = pc;
1809 args->line = buf + prev_buf_size;
1810 args->line_nr = 0;
1811 args->ms.sym = sym;
1812 dl = disasm_line__new(args);
1813 if (dl)
1814 annotation_line__add(&dl->al, ¬es->src->source);
1815
1816 pc += count;
1817 } while (count > 0 && pc < len);
1818
1819 ret = 0;
1820out:
1821 free(prog_linfo);
1822 free(btf);
1823 fclose(s);
1824 bfd_close(bfdf);
1825 return ret;
1826}
1827#else
1828static int symbol__disassemble_bpf(struct symbol *sym __maybe_unused,
1829 struct annotate_args *args __maybe_unused)
1830{
1831 return SYMBOL_ANNOTATE_ERRNO__NO_LIBOPCODES_FOR_BPF;
1832}
1833#endif
1834
1835static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
1836{
1837 struct annotation_options *opts = args->options;
1838 struct map *map = args->ms.map;
1839 struct dso *dso = map->dso;
1840 char *command;
1841 FILE *file;
1842 char symfs_filename[PATH_MAX];
1843 struct kcore_extract kce;
1844 bool delete_extract = false;
1845 bool decomp = false;
1846 int stdout_fd[2];
1847 int lineno = 0;
1848 int nline;
1849 pid_t pid;
1850 int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));
1851
1852 if (err)
1853 return err;
1854
1855 pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1856 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
1857 map->unmap_ip(map, sym->end));
1858
1859 pr_debug("annotating [%p] %30s : [%p] %30s\n",
1860 dso, dso->long_name, sym, sym->name);
1861
1862 if (dso->binary_type == DSO_BINARY_TYPE__BPF_PROG_INFO) {
1863 return symbol__disassemble_bpf(sym, args);
1864 } else if (dso__is_kcore(dso)) {
1865 kce.kcore_filename = symfs_filename;
1866 kce.addr = map__rip_2objdump(map, sym->start);
1867 kce.offs = sym->start;
1868 kce.len = sym->end - sym->start;
1869 if (!kcore_extract__create(&kce)) {
1870 delete_extract = true;
1871 strlcpy(symfs_filename, kce.extract_filename,
1872 sizeof(symfs_filename));
1873 }
1874 } else if (dso__needs_decompress(dso)) {
1875 char tmp[KMOD_DECOMP_LEN];
1876
1877 if (dso__decompress_kmodule_path(dso, symfs_filename,
1878 tmp, sizeof(tmp)) < 0)
1879 goto out;
1880
1881 decomp = true;
1882 strcpy(symfs_filename, tmp);
1883 }
1884
1885 err = asprintf(&command,
1886 "%s %s%s --start-address=0x%016" PRIx64
1887 " --stop-address=0x%016" PRIx64
1888 " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand",
1889 opts->objdump_path ?: "objdump",
1890 opts->disassembler_style ? "-M " : "",
1891 opts->disassembler_style ?: "",
1892 map__rip_2objdump(map, sym->start),
1893 map__rip_2objdump(map, sym->end),
1894 opts->show_asm_raw ? "" : "--no-show-raw",
1895 opts->annotate_src ? "-S" : "");
1896
1897 if (err < 0) {
1898 pr_err("Failure allocating memory for the command to run\n");
1899 goto out_remove_tmp;
1900 }
1901
1902 pr_debug("Executing: %s\n", command);
1903
1904 err = -1;
1905 if (pipe(stdout_fd) < 0) {
1906 pr_err("Failure creating the pipe to run %s\n", command);
1907 goto out_free_command;
1908 }
1909
1910 pid = fork();
1911 if (pid < 0) {
1912 pr_err("Failure forking to run %s\n", command);
1913 goto out_close_stdout;
1914 }
1915
1916 if (pid == 0) {
1917 close(stdout_fd[0]);
1918 dup2(stdout_fd[1], 1);
1919 close(stdout_fd[1]);
1920 execl("/bin/sh", "sh", "-c", command, "--", symfs_filename,
1921 NULL);
1922 perror(command);
1923 exit(-1);
1924 }
1925
1926 close(stdout_fd[1]);
1927
1928 file = fdopen(stdout_fd[0], "r");
1929 if (!file) {
1930 pr_err("Failure creating FILE stream for %s\n", command);
1931
1932
1933
1934
1935 goto out_free_command;
1936 }
1937
1938 nline = 0;
1939 while (!feof(file)) {
1940
1941
1942
1943
1944
1945
1946 if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
1947 break;
1948 nline++;
1949 }
1950
1951 if (nline == 0)
1952 pr_err("No output from %s\n", command);
1953
1954
1955
1956
1957
1958 if (dso__is_kcore(dso))
1959 delete_last_nop(sym);
1960
1961 fclose(file);
1962 err = 0;
1963out_free_command:
1964 free(command);
1965out_remove_tmp:
1966 close(stdout_fd[0]);
1967
1968 if (decomp)
1969 unlink(symfs_filename);
1970
1971 if (delete_extract)
1972 kcore_extract__delete(&kce);
1973out:
1974 return err;
1975
1976out_close_stdout:
1977 close(stdout_fd[1]);
1978 goto out_free_command;
1979}
1980
1981static void calc_percent(struct sym_hist *sym_hist,
1982 struct hists *hists,
1983 struct annotation_data *data,
1984 s64 offset, s64 end)
1985{
1986 unsigned int hits = 0;
1987 u64 period = 0;
1988
1989 while (offset < end) {
1990 hits += sym_hist->addr[offset].nr_samples;
1991 period += sym_hist->addr[offset].period;
1992 ++offset;
1993 }
1994
1995 if (sym_hist->nr_samples) {
1996 data->he.period = period;
1997 data->he.nr_samples = hits;
1998 data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples;
1999 }
2000
2001 if (hists->stats.nr_non_filtered_samples)
2002 data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples;
2003
2004 if (sym_hist->period)
2005 data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period;
2006
2007 if (hists->stats.total_period)
2008 data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period;
2009}
2010
2011static void annotation__calc_percent(struct annotation *notes,
2012 struct perf_evsel *leader, s64 len)
2013{
2014 struct annotation_line *al, *next;
2015 struct perf_evsel *evsel;
2016
2017 list_for_each_entry(al, ¬es->src->source, node) {
2018 s64 end;
2019 int i = 0;
2020
2021 if (al->offset == -1)
2022 continue;
2023
2024 next = annotation_line__next(al, ¬es->src->source);
2025 end = next ? next->offset : len;
2026
2027 for_each_group_evsel(evsel, leader) {
2028 struct hists *hists = evsel__hists(evsel);
2029 struct annotation_data *data;
2030 struct sym_hist *sym_hist;
2031
2032 BUG_ON(i >= al->data_nr);
2033
2034 sym_hist = annotation__histogram(notes, evsel->idx);
2035 data = &al->data[i++];
2036
2037 calc_percent(sym_hist, hists, data, al->offset, end);
2038 }
2039 }
2040}
2041
2042void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel)
2043{
2044 struct annotation *notes = symbol__annotation(sym);
2045
2046 annotation__calc_percent(notes, evsel, symbol__size(sym));
2047}
2048
2049int symbol__annotate(struct symbol *sym, struct map *map,
2050 struct perf_evsel *evsel, size_t privsize,
2051 struct annotation_options *options,
2052 struct arch **parch)
2053{
2054 struct annotation *notes = symbol__annotation(sym);
2055 struct annotate_args args = {
2056 .privsize = privsize,
2057 .evsel = evsel,
2058 .options = options,
2059 };
2060 struct perf_env *env = perf_evsel__env(evsel);
2061 const char *arch_name = perf_env__arch(env);
2062 struct arch *arch;
2063 int err;
2064
2065 if (!arch_name)
2066 return -1;
2067
2068 args.arch = arch = arch__find(arch_name);
2069 if (arch == NULL)
2070 return -ENOTSUP;
2071
2072 if (parch)
2073 *parch = arch;
2074
2075 if (arch->init) {
2076 err = arch->init(arch, env ? env->cpuid : NULL);
2077 if (err) {
2078 pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
2079 return err;
2080 }
2081 }
2082
2083 args.ms.map = map;
2084 args.ms.sym = sym;
2085 notes->start = map__rip_2objdump(map, sym->start);
2086
2087 return symbol__disassemble(sym, &args);
2088}
2089
2090static void insert_source_line(struct rb_root *root, struct annotation_line *al,
2091 struct annotation_options *opts)
2092{
2093 struct annotation_line *iter;
2094 struct rb_node **p = &root->rb_node;
2095 struct rb_node *parent = NULL;
2096 int i, ret;
2097
2098 while (*p != NULL) {
2099 parent = *p;
2100 iter = rb_entry(parent, struct annotation_line, rb_node);
2101
2102 ret = strcmp(iter->path, al->path);
2103 if (ret == 0) {
2104 for (i = 0; i < al->data_nr; i++) {
2105 iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
2106 opts->percent_type);
2107 }
2108 return;
2109 }
2110
2111 if (ret < 0)
2112 p = &(*p)->rb_left;
2113 else
2114 p = &(*p)->rb_right;
2115 }
2116
2117 for (i = 0; i < al->data_nr; i++) {
2118 al->data[i].percent_sum = annotation_data__percent(&al->data[i],
2119 opts->percent_type);
2120 }
2121
2122 rb_link_node(&al->rb_node, parent, p);
2123 rb_insert_color(&al->rb_node, root);
2124}
2125
2126static int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
2127{
2128 int i;
2129
2130 for (i = 0; i < a->data_nr; i++) {
2131 if (a->data[i].percent_sum == b->data[i].percent_sum)
2132 continue;
2133 return a->data[i].percent_sum > b->data[i].percent_sum;
2134 }
2135
2136 return 0;
2137}
2138
2139static void __resort_source_line(struct rb_root *root, struct annotation_line *al)
2140{
2141 struct annotation_line *iter;
2142 struct rb_node **p = &root->rb_node;
2143 struct rb_node *parent = NULL;
2144
2145 while (*p != NULL) {
2146 parent = *p;
2147 iter = rb_entry(parent, struct annotation_line, rb_node);
2148
2149 if (cmp_source_line(al, iter))
2150 p = &(*p)->rb_left;
2151 else
2152 p = &(*p)->rb_right;
2153 }
2154
2155 rb_link_node(&al->rb_node, parent, p);
2156 rb_insert_color(&al->rb_node, root);
2157}
2158
2159static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
2160{
2161 struct annotation_line *al;
2162 struct rb_node *node;
2163
2164 node = rb_first(src_root);
2165 while (node) {
2166 struct rb_node *next;
2167
2168 al = rb_entry(node, struct annotation_line, rb_node);
2169 next = rb_next(node);
2170 rb_erase(node, src_root);
2171
2172 __resort_source_line(dest_root, al);
2173 node = next;
2174 }
2175}
2176
2177static void print_summary(struct rb_root *root, const char *filename)
2178{
2179 struct annotation_line *al;
2180 struct rb_node *node;
2181
2182 printf("\nSorted summary for file %s\n", filename);
2183 printf("----------------------------------------------\n\n");
2184
2185 if (RB_EMPTY_ROOT(root)) {
2186 printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
2187 return;
2188 }
2189
2190 node = rb_first(root);
2191 while (node) {
2192 double percent, percent_max = 0.0;
2193 const char *color;
2194 char *path;
2195 int i;
2196
2197 al = rb_entry(node, struct annotation_line, rb_node);
2198 for (i = 0; i < al->data_nr; i++) {
2199 percent = al->data[i].percent_sum;
2200 color = get_percent_color(percent);
2201 color_fprintf(stdout, color, " %7.2f", percent);
2202
2203 if (percent > percent_max)
2204 percent_max = percent;
2205 }
2206
2207 path = al->path;
2208 color = get_percent_color(percent_max);
2209 color_fprintf(stdout, color, " %s\n", path);
2210
2211 node = rb_next(node);
2212 }
2213}
2214
2215static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
2216{
2217 struct annotation *notes = symbol__annotation(sym);
2218 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
2219 u64 len = symbol__size(sym), offset;
2220
2221 for (offset = 0; offset < len; ++offset)
2222 if (h->addr[offset].nr_samples != 0)
2223 printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
2224 sym->start + offset, h->addr[offset].nr_samples);
2225 printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);
2226}
2227
2228static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start)
2229{
2230 char bf[32];
2231 struct annotation_line *line;
2232
2233 list_for_each_entry_reverse(line, lines, node) {
2234 if (line->offset != -1)
2235 return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset);
2236 }
2237
2238 return 0;
2239}
2240
2241int symbol__annotate_printf(struct symbol *sym, struct map *map,
2242 struct perf_evsel *evsel,
2243 struct annotation_options *opts)
2244{
2245 struct dso *dso = map->dso;
2246 char *filename;
2247 const char *d_filename;
2248 const char *evsel_name = perf_evsel__name(evsel);
2249 struct annotation *notes = symbol__annotation(sym);
2250 struct sym_hist *h = annotation__histogram(notes, evsel->idx);
2251 struct annotation_line *pos, *queue = NULL;
2252 u64 start = map__rip_2objdump(map, sym->start);
2253 int printed = 2, queue_len = 0, addr_fmt_width;
2254 int more = 0;
2255 bool context = opts->context;
2256 u64 len;
2257 int width = symbol_conf.show_total_period ? 12 : 8;
2258 int graph_dotted_len;
2259 char buf[512];
2260
2261 filename = strdup(dso->long_name);
2262 if (!filename)
2263 return -ENOMEM;
2264
2265 if (opts->full_path)
2266 d_filename = filename;
2267 else
2268 d_filename = basename(filename);
2269
2270 len = symbol__size(sym);
2271
2272 if (perf_evsel__is_group_event(evsel)) {
2273 width *= evsel->nr_members;
2274 perf_evsel__group_desc(evsel, buf, sizeof(buf));
2275 evsel_name = buf;
2276 }
2277
2278 graph_dotted_len = printf(" %-*.*s| Source code & Disassembly of %s for %s (%" PRIu64 " samples, "
2279 "percent: %s)\n",
2280 width, width, symbol_conf.show_total_period ? "Period" :
2281 symbol_conf.show_nr_samples ? "Samples" : "Percent",
2282 d_filename, evsel_name, h->nr_samples,
2283 percent_type_str(opts->percent_type));
2284
2285 printf("%-*.*s----\n",
2286 graph_dotted_len, graph_dotted_len, graph_dotted_line);
2287
2288 if (verbose > 0)
2289 symbol__annotate_hits(sym, evsel);
2290
2291 addr_fmt_width = annotated_source__addr_fmt_width(¬es->src->source, start);
2292
2293 list_for_each_entry(pos, ¬es->src->source, node) {
2294 int err;
2295
2296 if (context && queue == NULL) {
2297 queue = pos;
2298 queue_len = 0;
2299 }
2300
2301 err = annotation_line__print(pos, sym, start, evsel, len,
2302 opts->min_pcnt, printed, opts->max_lines,
2303 queue, addr_fmt_width, opts->percent_type);
2304
2305 switch (err) {
2306 case 0:
2307 ++printed;
2308 if (context) {
2309 printed += queue_len;
2310 queue = NULL;
2311 queue_len = 0;
2312 }
2313 break;
2314 case 1:
2315
2316 ++more;
2317 break;
2318 case -1:
2319 default:
2320
2321
2322
2323
2324 if (!context)
2325 break;
2326 if (queue_len == context)
2327 queue = list_entry(queue->node.next, typeof(*queue), node);
2328 else
2329 ++queue_len;
2330 break;
2331 }
2332 }
2333
2334 free(filename);
2335
2336 return more;
2337}
2338
2339static void FILE__set_percent_color(void *fp __maybe_unused,
2340 double percent __maybe_unused,
2341 bool current __maybe_unused)
2342{
2343}
2344
2345static int FILE__set_jumps_percent_color(void *fp __maybe_unused,
2346 int nr __maybe_unused, bool current __maybe_unused)
2347{
2348 return 0;
2349}
2350
2351static int FILE__set_color(void *fp __maybe_unused, int color __maybe_unused)
2352{
2353 return 0;
2354}
2355
2356static void FILE__printf(void *fp, const char *fmt, ...)
2357{
2358 va_list args;
2359
2360 va_start(args, fmt);
2361 vfprintf(fp, fmt, args);
2362 va_end(args);
2363}
2364
2365static void FILE__write_graph(void *fp, int graph)
2366{
2367 const char *s;
2368 switch (graph) {
2369
2370 case DARROW_CHAR: s = "↓"; break;
2371 case UARROW_CHAR: s = "↑"; break;
2372 case LARROW_CHAR: s = "←"; break;
2373 case RARROW_CHAR: s = "→"; break;
2374 default: s = "?"; break;
2375 }
2376
2377 fputs(s, fp);
2378}
2379
2380static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,
2381 struct annotation_options *opts)
2382{
2383 struct annotation *notes = symbol__annotation(sym);
2384 struct annotation_write_ops wops = {
2385 .first_line = true,
2386 .obj = fp,
2387 .set_color = FILE__set_color,
2388 .set_percent_color = FILE__set_percent_color,
2389 .set_jumps_percent_color = FILE__set_jumps_percent_color,
2390 .printf = FILE__printf,
2391 .write_graph = FILE__write_graph,
2392 };
2393 struct annotation_line *al;
2394
2395 list_for_each_entry(al, ¬es->src->source, node) {
2396 if (annotation_line__filter(al, notes))
2397 continue;
2398 annotation_line__write(al, notes, &wops, opts);
2399 fputc('\n', fp);
2400 wops.first_line = false;
2401 }
2402
2403 return 0;
2404}
2405
2406int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel,
2407 struct annotation_options *opts)
2408{
2409 const char *ev_name = perf_evsel__name(evsel);
2410 char buf[1024];
2411 char *filename;
2412 int err = -1;
2413 FILE *fp;
2414
2415 if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0)
2416 return -1;
2417
2418 fp = fopen(filename, "w");
2419 if (fp == NULL)
2420 goto out_free_filename;
2421
2422 if (perf_evsel__is_group_event(evsel)) {
2423 perf_evsel__group_desc(evsel, buf, sizeof(buf));
2424 ev_name = buf;
2425 }
2426
2427 fprintf(fp, "%s() %s\nEvent: %s\n\n",
2428 ms->sym->name, ms->map->dso->long_name, ev_name);
2429 symbol__annotate_fprintf2(ms->sym, fp, opts);
2430
2431 fclose(fp);
2432 err = 0;
2433out_free_filename:
2434 free(filename);
2435 return err;
2436}
2437
2438void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
2439{
2440 struct annotation *notes = symbol__annotation(sym);
2441 struct sym_hist *h = annotation__histogram(notes, evidx);
2442
2443 memset(h, 0, notes->src->sizeof_sym_hist);
2444}
2445
2446void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
2447{
2448 struct annotation *notes = symbol__annotation(sym);
2449 struct sym_hist *h = annotation__histogram(notes, evidx);
2450 int len = symbol__size(sym), offset;
2451
2452 h->nr_samples = 0;
2453 for (offset = 0; offset < len; ++offset) {
2454 h->addr[offset].nr_samples = h->addr[offset].nr_samples * 7 / 8;
2455 h->nr_samples += h->addr[offset].nr_samples;
2456 }
2457}
2458
2459void annotated_source__purge(struct annotated_source *as)
2460{
2461 struct annotation_line *al, *n;
2462
2463 list_for_each_entry_safe(al, n, &as->source, node) {
2464 list_del(&al->node);
2465 disasm_line__free(disasm_line(al));
2466 }
2467}
2468
2469static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
2470{
2471 size_t printed;
2472
2473 if (dl->al.offset == -1)
2474 return fprintf(fp, "%s\n", dl->al.line);
2475
2476 printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name);
2477
2478 if (dl->ops.raw[0] != '\0') {
2479 printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
2480 dl->ops.raw);
2481 }
2482
2483 return printed + fprintf(fp, "\n");
2484}
2485
2486size_t disasm__fprintf(struct list_head *head, FILE *fp)
2487{
2488 struct disasm_line *pos;
2489 size_t printed = 0;
2490
2491 list_for_each_entry(pos, head, al.node)
2492 printed += disasm_line__fprintf(pos, fp);
2493
2494 return printed;
2495}
2496
2497bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym)
2498{
2499 if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) ||
2500 !disasm_line__has_local_offset(dl) || dl->ops.target.offset < 0 ||
2501 dl->ops.target.offset >= (s64)symbol__size(sym))
2502 return false;
2503
2504 return true;
2505}
2506
2507void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
2508{
2509 u64 offset, size = symbol__size(sym);
2510
2511
2512 if (strstr(sym->name, "@plt"))
2513 return;
2514
2515 for (offset = 0; offset < size; ++offset) {
2516 struct annotation_line *al = notes->offsets[offset];
2517 struct disasm_line *dl;
2518
2519 dl = disasm_line(al);
2520
2521 if (!disasm_line__is_valid_local_jump(dl, sym))
2522 continue;
2523
2524 al = notes->offsets[dl->ops.target.offset];
2525
2526
2527
2528
2529
2530 if (al == NULL)
2531 continue;
2532
2533 if (++al->jump_sources > notes->max_jump_sources)
2534 notes->max_jump_sources = al->jump_sources;
2535
2536 ++notes->nr_jumps;
2537 }
2538}
2539
2540void annotation__set_offsets(struct annotation *notes, s64 size)
2541{
2542 struct annotation_line *al;
2543
2544 notes->max_line_len = 0;
2545
2546 list_for_each_entry(al, ¬es->src->source, node) {
2547 size_t line_len = strlen(al->line);
2548
2549 if (notes->max_line_len < line_len)
2550 notes->max_line_len = line_len;
2551 al->idx = notes->nr_entries++;
2552 if (al->offset != -1) {
2553 al->idx_asm = notes->nr_asm_entries++;
2554
2555
2556
2557
2558
2559
2560
2561 if (al->offset < size)
2562 notes->offsets[al->offset] = al;
2563 } else
2564 al->idx_asm = -1;
2565 }
2566}
2567
2568static inline int width_jumps(int n)
2569{
2570 if (n >= 100)
2571 return 5;
2572 if (n / 10)
2573 return 2;
2574 return 1;
2575}
2576
2577static int annotation__max_ins_name(struct annotation *notes)
2578{
2579 int max_name = 0, len;
2580 struct annotation_line *al;
2581
2582 list_for_each_entry(al, ¬es->src->source, node) {
2583 if (al->offset == -1)
2584 continue;
2585
2586 len = strlen(disasm_line(al)->ins.name);
2587 if (max_name < len)
2588 max_name = len;
2589 }
2590
2591 return max_name;
2592}
2593
2594void annotation__init_column_widths(struct annotation *notes, struct symbol *sym)
2595{
2596 notes->widths.addr = notes->widths.target =
2597 notes->widths.min_addr = hex_width(symbol__size(sym));
2598 notes->widths.max_addr = hex_width(sym->end);
2599 notes->widths.jumps = width_jumps(notes->max_jump_sources);
2600 notes->widths.max_ins_name = annotation__max_ins_name(notes);
2601}
2602
2603void annotation__update_column_widths(struct annotation *notes)
2604{
2605 if (notes->options->use_offset)
2606 notes->widths.target = notes->widths.min_addr;
2607 else
2608 notes->widths.target = notes->widths.max_addr;
2609
2610 notes->widths.addr = notes->widths.target;
2611
2612 if (notes->options->show_nr_jumps)
2613 notes->widths.addr += notes->widths.jumps + 1;
2614}
2615
2616static void annotation__calc_lines(struct annotation *notes, struct map *map,
2617 struct rb_root *root,
2618 struct annotation_options *opts)
2619{
2620 struct annotation_line *al;
2621 struct rb_root tmp_root = RB_ROOT;
2622
2623 list_for_each_entry(al, ¬es->src->source, node) {
2624 double percent_max = 0.0;
2625 int i;
2626
2627 for (i = 0; i < al->data_nr; i++) {
2628 double percent;
2629
2630 percent = annotation_data__percent(&al->data[i],
2631 opts->percent_type);
2632
2633 if (percent > percent_max)
2634 percent_max = percent;
2635 }
2636
2637 if (percent_max <= 0.5)
2638 continue;
2639
2640 al->path = get_srcline(map->dso, notes->start + al->offset, NULL,
2641 false, true, notes->start + al->offset);
2642 insert_source_line(&tmp_root, al, opts);
2643 }
2644
2645 resort_source_line(root, &tmp_root);
2646}
2647
2648static void symbol__calc_lines(struct symbol *sym, struct map *map,
2649 struct rb_root *root,
2650 struct annotation_options *opts)
2651{
2652 struct annotation *notes = symbol__annotation(sym);
2653
2654 annotation__calc_lines(notes, map, root, opts);
2655}
2656
2657int symbol__tty_annotate2(struct symbol *sym, struct map *map,
2658 struct perf_evsel *evsel,
2659 struct annotation_options *opts)
2660{
2661 struct dso *dso = map->dso;
2662 struct rb_root source_line = RB_ROOT;
2663 struct hists *hists = evsel__hists(evsel);
2664 char buf[1024];
2665
2666 if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
2667 return -1;
2668
2669 if (opts->print_lines) {
2670 srcline_full_filename = opts->full_path;
2671 symbol__calc_lines(sym, map, &source_line, opts);
2672 print_summary(&source_line, dso->long_name);
2673 }
2674
2675 hists__scnprintf_title(hists, buf, sizeof(buf));
2676 fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
2677 buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);
2678 symbol__annotate_fprintf2(sym, stdout, opts);
2679
2680 annotated_source__purge(symbol__annotation(sym)->src);
2681
2682 return 0;
2683}
2684
2685int symbol__tty_annotate(struct symbol *sym, struct map *map,
2686 struct perf_evsel *evsel,
2687 struct annotation_options *opts)
2688{
2689 struct dso *dso = map->dso;
2690 struct rb_root source_line = RB_ROOT;
2691
2692 if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0)
2693 return -1;
2694
2695 symbol__calc_percent(sym, evsel);
2696
2697 if (opts->print_lines) {
2698 srcline_full_filename = opts->full_path;
2699 symbol__calc_lines(sym, map, &source_line, opts);
2700 print_summary(&source_line, dso->long_name);
2701 }
2702
2703 symbol__annotate_printf(sym, map, evsel, opts);
2704
2705 annotated_source__purge(symbol__annotation(sym)->src);
2706
2707 return 0;
2708}
2709
2710bool ui__has_annotation(void)
2711{
2712 return use_browser == 1 && perf_hpp_list.sym;
2713}
2714
2715
2716static double annotation_line__max_percent(struct annotation_line *al,
2717 struct annotation *notes,
2718 unsigned int percent_type)
2719{
2720 double percent_max = 0.0;
2721 int i;
2722
2723 for (i = 0; i < notes->nr_events; i++) {
2724 double percent;
2725
2726 percent = annotation_data__percent(&al->data[i],
2727 percent_type);
2728
2729 if (percent > percent_max)
2730 percent_max = percent;
2731 }
2732
2733 return percent_max;
2734}
2735
2736static void disasm_line__write(struct disasm_line *dl, struct annotation *notes,
2737 void *obj, char *bf, size_t size,
2738 void (*obj__printf)(void *obj, const char *fmt, ...),
2739 void (*obj__write_graph)(void *obj, int graph))
2740{
2741 if (dl->ins.ops && dl->ins.ops->scnprintf) {
2742 if (ins__is_jump(&dl->ins)) {
2743 bool fwd;
2744
2745 if (dl->ops.target.outside)
2746 goto call_like;
2747 fwd = dl->ops.target.offset > dl->al.offset;
2748 obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR);
2749 obj__printf(obj, " ");
2750 } else if (ins__is_call(&dl->ins)) {
2751call_like:
2752 obj__write_graph(obj, RARROW_CHAR);
2753 obj__printf(obj, " ");
2754 } else if (ins__is_ret(&dl->ins)) {
2755 obj__write_graph(obj, LARROW_CHAR);
2756 obj__printf(obj, " ");
2757 } else {
2758 obj__printf(obj, " ");
2759 }
2760 } else {
2761 obj__printf(obj, " ");
2762 }
2763
2764 disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset, notes->widths.max_ins_name);
2765}
2766
2767static void ipc_coverage_string(char *bf, int size, struct annotation *notes)
2768{
2769 double ipc = 0.0, coverage = 0.0;
2770
2771 if (notes->hit_cycles)
2772 ipc = notes->hit_insn / ((double)notes->hit_cycles);
2773
2774 if (notes->total_insn) {
2775 coverage = notes->cover_insn * 100.0 /
2776 ((double)notes->total_insn);
2777 }
2778
2779 scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",
2780 ipc, coverage);
2781}
2782
2783static void __annotation_line__write(struct annotation_line *al, struct annotation *notes,
2784 bool first_line, bool current_entry, bool change_color, int width,
2785 void *obj, unsigned int percent_type,
2786 int (*obj__set_color)(void *obj, int color),
2787 void (*obj__set_percent_color)(void *obj, double percent, bool current),
2788 int (*obj__set_jumps_percent_color)(void *obj, int nr, bool current),
2789 void (*obj__printf)(void *obj, const char *fmt, ...),
2790 void (*obj__write_graph)(void *obj, int graph))
2791
2792{
2793 double percent_max = annotation_line__max_percent(al, notes, percent_type);
2794 int pcnt_width = annotation__pcnt_width(notes),
2795 cycles_width = annotation__cycles_width(notes);
2796 bool show_title = false;
2797 char bf[256];
2798 int printed;
2799
2800 if (first_line && (al->offset == -1 || percent_max == 0.0)) {
2801 if (notes->have_cycles) {
2802 if (al->ipc == 0.0 && al->cycles == 0)
2803 show_title = true;
2804 } else
2805 show_title = true;
2806 }
2807
2808 if (al->offset != -1 && percent_max != 0.0) {
2809 int i;
2810
2811 for (i = 0; i < notes->nr_events; i++) {
2812 double percent;
2813
2814 percent = annotation_data__percent(&al->data[i], percent_type);
2815
2816 obj__set_percent_color(obj, percent, current_entry);
2817 if (notes->options->show_total_period) {
2818 obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
2819 } else if (notes->options->show_nr_samples) {
2820 obj__printf(obj, "%6" PRIu64 " ",
2821 al->data[i].he.nr_samples);
2822 } else {
2823 obj__printf(obj, "%6.2f ", percent);
2824 }
2825 }
2826 } else {
2827 obj__set_percent_color(obj, 0, current_entry);
2828
2829 if (!show_title)
2830 obj__printf(obj, "%-*s", pcnt_width, " ");
2831 else {
2832 obj__printf(obj, "%-*s", pcnt_width,
2833 notes->options->show_total_period ? "Period" :
2834 notes->options->show_nr_samples ? "Samples" : "Percent");
2835 }
2836 }
2837
2838 if (notes->have_cycles) {
2839 if (al->ipc)
2840 obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
2841 else if (!show_title)
2842 obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " ");
2843 else
2844 obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");
2845
2846 if (!notes->options->show_minmax_cycle) {
2847 if (al->cycles)
2848 obj__printf(obj, "%*" PRIu64 " ",
2849 ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
2850 else if (!show_title)
2851 obj__printf(obj, "%*s",
2852 ANNOTATION__CYCLES_WIDTH, " ");
2853 else
2854 obj__printf(obj, "%*s ",
2855 ANNOTATION__CYCLES_WIDTH - 1,
2856 "Cycle");
2857 } else {
2858 if (al->cycles) {
2859 char str[32];
2860
2861 scnprintf(str, sizeof(str),
2862 "%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",
2863 al->cycles, al->cycles_min,
2864 al->cycles_max);
2865
2866 obj__printf(obj, "%*s ",
2867 ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
2868 str);
2869 } else if (!show_title)
2870 obj__printf(obj, "%*s",
2871 ANNOTATION__MINMAX_CYCLES_WIDTH,
2872 " ");
2873 else
2874 obj__printf(obj, "%*s ",
2875 ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
2876 "Cycle(min/max)");
2877 }
2878
2879 if (show_title && !*al->line) {
2880 ipc_coverage_string(bf, sizeof(bf), notes);
2881 obj__printf(obj, "%*s", ANNOTATION__AVG_IPC_WIDTH, bf);
2882 }
2883 }
2884
2885 obj__printf(obj, " ");
2886
2887 if (!*al->line)
2888 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " ");
2889 else if (al->offset == -1) {
2890 if (al->line_nr && notes->options->show_linenr)
2891 printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr);
2892 else
2893 printed = scnprintf(bf, sizeof(bf), "%-*s ", notes->widths.addr, " ");
2894 obj__printf(obj, bf);
2895 obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line);
2896 } else {
2897 u64 addr = al->offset;
2898 int color = -1;
2899
2900 if (!notes->options->use_offset)
2901 addr += notes->start;
2902
2903 if (!notes->options->use_offset) {
2904 printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
2905 } else {
2906 if (al->jump_sources &&
2907 notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {
2908 if (notes->options->show_nr_jumps) {
2909 int prev;
2910 printed = scnprintf(bf, sizeof(bf), "%*d ",
2911 notes->widths.jumps,
2912 al->jump_sources);
2913 prev = obj__set_jumps_percent_color(obj, al->jump_sources,
2914 current_entry);
2915 obj__printf(obj, bf);
2916 obj__set_color(obj, prev);
2917 }
2918print_addr:
2919 printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
2920 notes->widths.target, addr);
2921 } else if (ins__is_call(&disasm_line(al)->ins) &&
2922 notes->options->offset_level >= ANNOTATION__OFFSET_CALL) {
2923 goto print_addr;
2924 } else if (notes->options->offset_level == ANNOTATION__MAX_OFFSET_LEVEL) {
2925 goto print_addr;
2926 } else {
2927 printed = scnprintf(bf, sizeof(bf), "%-*s ",
2928 notes->widths.addr, " ");
2929 }
2930 }
2931
2932 if (change_color)
2933 color = obj__set_color(obj, HE_COLORSET_ADDR);
2934 obj__printf(obj, bf);
2935 if (change_color)
2936 obj__set_color(obj, color);
2937
2938 disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph);
2939
2940 obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf);
2941 }
2942
2943}
2944
2945void annotation_line__write(struct annotation_line *al, struct annotation *notes,
2946 struct annotation_write_ops *wops,
2947 struct annotation_options *opts)
2948{
2949 __annotation_line__write(al, notes, wops->first_line, wops->current_entry,
2950 wops->change_color, wops->width, wops->obj,
2951 opts->percent_type,
2952 wops->set_color, wops->set_percent_color,
2953 wops->set_jumps_percent_color, wops->printf,
2954 wops->write_graph);
2955}
2956
2957int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel,
2958 struct annotation_options *options, struct arch **parch)
2959{
2960 struct annotation *notes = symbol__annotation(sym);
2961 size_t size = symbol__size(sym);
2962 int nr_pcnt = 1, err;
2963
2964 notes->offsets = zalloc(size * sizeof(struct annotation_line *));
2965 if (notes->offsets == NULL)
2966 return -1;
2967
2968 if (perf_evsel__is_group_event(evsel))
2969 nr_pcnt = evsel->nr_members;
2970
2971 err = symbol__annotate(sym, map, evsel, 0, options, parch);
2972 if (err)
2973 goto out_free_offsets;
2974
2975 notes->options = options;
2976
2977 symbol__calc_percent(sym, evsel);
2978
2979 annotation__set_offsets(notes, size);
2980 annotation__mark_jump_targets(notes, sym);
2981 annotation__compute_ipc(notes, size);
2982 annotation__init_column_widths(notes, sym);
2983 notes->nr_events = nr_pcnt;
2984
2985 annotation__update_column_widths(notes);
2986 sym->annotate2 = true;
2987
2988 return 0;
2989
2990out_free_offsets:
2991 zfree(¬es->offsets);
2992 return -1;
2993}
2994
2995#define ANNOTATION__CFG(n) \
2996 { .name = #n, .value = &annotation__default_options.n, }
2997
2998
2999
3000
3001static struct annotation_config {
3002 const char *name;
3003 void *value;
3004} annotation__configs[] = {
3005 ANNOTATION__CFG(hide_src_code),
3006 ANNOTATION__CFG(jump_arrows),
3007 ANNOTATION__CFG(offset_level),
3008 ANNOTATION__CFG(show_linenr),
3009 ANNOTATION__CFG(show_nr_jumps),
3010 ANNOTATION__CFG(show_nr_samples),
3011 ANNOTATION__CFG(show_total_period),
3012 ANNOTATION__CFG(use_offset),
3013};
3014
3015#undef ANNOTATION__CFG
3016
3017static int annotation_config__cmp(const void *name, const void *cfgp)
3018{
3019 const struct annotation_config *cfg = cfgp;
3020
3021 return strcmp(name, cfg->name);
3022}
3023
3024static int annotation__config(const char *var, const char *value,
3025 void *data __maybe_unused)
3026{
3027 struct annotation_config *cfg;
3028 const char *name;
3029
3030 if (!strstarts(var, "annotate."))
3031 return 0;
3032
3033 name = var + 9;
3034 cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs),
3035 sizeof(struct annotation_config), annotation_config__cmp);
3036
3037 if (cfg == NULL)
3038 pr_debug("%s variable unknown, ignoring...", var);
3039 else if (strcmp(var, "annotate.offset_level") == 0) {
3040 perf_config_int(cfg->value, name, value);
3041
3042 if (*(int *)cfg->value > ANNOTATION__MAX_OFFSET_LEVEL)
3043 *(int *)cfg->value = ANNOTATION__MAX_OFFSET_LEVEL;
3044 else if (*(int *)cfg->value < ANNOTATION__MIN_OFFSET_LEVEL)
3045 *(int *)cfg->value = ANNOTATION__MIN_OFFSET_LEVEL;
3046 } else {
3047 *(bool *)cfg->value = perf_config_bool(name, value);
3048 }
3049 return 0;
3050}
3051
3052void annotation_config__init(void)
3053{
3054 perf_config(annotation__config, NULL);
3055
3056 annotation__default_options.show_total_period = symbol_conf.show_total_period;
3057 annotation__default_options.show_nr_samples = symbol_conf.show_nr_samples;
3058}
3059
3060static unsigned int parse_percent_type(char *str1, char *str2)
3061{
3062 unsigned int type = (unsigned int) -1;
3063
3064 if (!strcmp("period", str1)) {
3065 if (!strcmp("local", str2))
3066 type = PERCENT_PERIOD_LOCAL;
3067 else if (!strcmp("global", str2))
3068 type = PERCENT_PERIOD_GLOBAL;
3069 }
3070
3071 if (!strcmp("hits", str1)) {
3072 if (!strcmp("local", str2))
3073 type = PERCENT_HITS_LOCAL;
3074 else if (!strcmp("global", str2))
3075 type = PERCENT_HITS_GLOBAL;
3076 }
3077
3078 return type;
3079}
3080
3081int annotate_parse_percent_type(const struct option *opt, const char *_str,
3082 int unset __maybe_unused)
3083{
3084 struct annotation_options *opts = opt->value;
3085 unsigned int type;
3086 char *str1, *str2;
3087 int err = -1;
3088
3089 str1 = strdup(_str);
3090 if (!str1)
3091 return -ENOMEM;
3092
3093 str2 = strchr(str1, '-');
3094 if (!str2)
3095 goto out;
3096
3097 *str2++ = 0;
3098
3099 type = parse_percent_type(str1, str2);
3100 if (type == (unsigned int) -1)
3101 type = parse_percent_type(str2, str1);
3102 if (type != (unsigned int) -1) {
3103 opts->percent_type = type;
3104 err = 0;
3105 }
3106
3107out:
3108 free(str1);
3109 return err;
3110}
3111