annotate.c 70.4 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*
 * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
 *
 * Parts came from builtin-annotate.c, see those files for further
 * copyright notes.
 *
 * Released under the GPL v2. (and only v2, not any later version)
 */

10
#include <errno.h>
11
#include <inttypes.h>
12
#include <libgen.h>
13
#include "util.h"
14 15
#include "ui/ui.h"
#include "sort.h"
16 17
#include "build-id.h"
#include "color.h"
18
#include "config.h"
19 20
#include "cache.h"
#include "symbol.h"
21
#include "units.h"
22 23
#include "debug.h"
#include "annotate.h"
24
#include "evsel.h"
25
#include "evlist.h"
26
#include "block-range.h"
27
#include "string2.h"
28
#include "arch/common.h"
29
#include <regex.h>
30
#include <pthread.h>
31
#include <linux/bitops.h>
32
#include <linux/kernel.h>
33

34 35 36 37 38 39 40
/* FIXME: For the HE_COLORSET */
#include "ui/browser.h"

/*
 * FIXME: Using the same values as slang.h,
 * but that header may not be available everywhere
 */
41 42 43 44
#define LARROW_CHAR	((unsigned char)',')
#define RARROW_CHAR	((unsigned char)'+')
#define DARROW_CHAR	((unsigned char)'.')
#define UARROW_CHAR	((unsigned char)'-')
45

46 47
#include "sane_ctype.h"

48 49 50
struct annotation_options annotation__default_options = {
	.use_offset     = true,
	.jump_arrows    = true,
51
	.annotate_src	= true,
52
	.offset_level	= ANNOTATION__OFFSET_JUMP_TARGETS,
53
	.percent_type	= PERCENT_PERIOD_LOCAL,
54 55
};

56
static regex_t	 file_lineno;
57

58
static struct ins_ops *ins__find(struct arch *arch, const char *name);
59
static void ins__sort(struct arch *arch);
60
static int disasm_line__parse(char *line, const char **namep, char **rawp);
61

62 63
struct arch {
	const char	*name;
64 65
	struct ins	*instructions;
	size_t		nr_instructions;
66 67
	size_t		nr_instructions_allocated;
	struct ins_ops  *(*associate_instruction_ops)(struct arch *arch, const char *name);
68
	bool		sorted_instructions;
69 70
	bool		initialized;
	void		*priv;
71 72
	unsigned int	model;
	unsigned int	family;
73
	int		(*init)(struct arch *arch, char *cpuid);
74 75
	bool		(*ins_is_fused)(struct arch *arch, const char *ins1,
					const char *ins2);
76 77
	struct		{
		char comment_char;
78
		char skip_functions_char;
79 80 81
	} objdump;
};

82 83 84 85 86 87 88 89
static struct ins_ops call_ops;
static struct ins_ops dec_ops;
static struct ins_ops jump_ops;
static struct ins_ops mov_ops;
static struct ins_ops nop_ops;
static struct ins_ops lock_ops;
static struct ins_ops ret_ops;

90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
static int arch__grow_instructions(struct arch *arch)
{
	struct ins *new_instructions;
	size_t new_nr_allocated;

	if (arch->nr_instructions_allocated == 0 && arch->instructions)
		goto grow_from_non_allocated_table;

	new_nr_allocated = arch->nr_instructions_allocated + 128;
	new_instructions = realloc(arch->instructions, new_nr_allocated * sizeof(struct ins));
	if (new_instructions == NULL)
		return -1;

out_update_instructions:
	arch->instructions = new_instructions;
	arch->nr_instructions_allocated = new_nr_allocated;
	return 0;

grow_from_non_allocated_table:
	new_nr_allocated = arch->nr_instructions + 128;
	new_instructions = calloc(new_nr_allocated, sizeof(struct ins));
	if (new_instructions == NULL)
		return -1;

	memcpy(new_instructions, arch->instructions, arch->nr_instructions);
	goto out_update_instructions;
}

118
static int arch__associate_ins_ops(struct arch* arch, const char *name, struct ins_ops *ops)
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
{
	struct ins *ins;

	if (arch->nr_instructions == arch->nr_instructions_allocated &&
	    arch__grow_instructions(arch))
		return -1;

	ins = &arch->instructions[arch->nr_instructions];
	ins->name = strdup(name);
	if (!ins->name)
		return -1;

	ins->ops  = ops;
	arch->nr_instructions++;

	ins__sort(arch);
	return 0;
}

138
#include "arch/arc/annotate/instructions.c"
139
#include "arch/arm/annotate/instructions.c"
K
Kim Phillips 已提交
140
#include "arch/arm64/annotate/instructions.c"
141
#include "arch/x86/annotate/instructions.c"
142
#include "arch/powerpc/annotate/instructions.c"
143
#include "arch/s390/annotate/instructions.c"
D
David Miller 已提交
144
#include "arch/sparc/annotate/instructions.c"
145

146
static struct arch architectures[] = {
147 148 149 150
	{
		.name = "arc",
		.init = arc__annotate_init,
	},
151 152
	{
		.name = "arm",
153
		.init = arm__annotate_init,
154
	},
K
Kim Phillips 已提交
155 156 157 158
	{
		.name = "arm64",
		.init = arm64__annotate_init,
	},
159 160
	{
		.name = "x86",
161
		.init = x86__annotate_init,
162 163
		.instructions = x86__instructions,
		.nr_instructions = ARRAY_SIZE(x86__instructions),
164
		.ins_is_fused = x86__ins_is_fused,
165 166 167 168
		.objdump =  {
			.comment_char = '#',
		},
	},
169 170 171 172
	{
		.name = "powerpc",
		.init = powerpc__annotate_init,
	},
173 174
	{
		.name = "s390",
175
		.init = s390__annotate_init,
176 177 178 179
		.objdump =  {
			.comment_char = '#',
		},
	},
D
David Miller 已提交
180 181 182 183 184 185 186
	{
		.name = "sparc",
		.init = sparc__annotate_init,
		.objdump = {
			.comment_char = '#',
		},
	},
187 188
};

189 190
static void ins__delete(struct ins_operands *ops)
{
191 192
	if (ops == NULL)
		return;
193 194 195 196
	zfree(&ops->source.raw);
	zfree(&ops->source.name);
	zfree(&ops->target.raw);
	zfree(&ops->target.name);
197 198
}

199 200 201
static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size,
			      struct ins_operands *ops)
{
202
	return scnprintf(bf, size, "%-6s %s", ins->name, ops->raw);
203 204 205 206 207 208 209 210 211 212 213
}

int ins__scnprintf(struct ins *ins, char *bf, size_t size,
		  struct ins_operands *ops)
{
	if (ins->ops->scnprintf)
		return ins->ops->scnprintf(ins, bf, size, ops);

	return ins__raw_scnprintf(ins, bf, size, ops);
}

214 215 216 217 218 219 220 221
bool ins__is_fused(struct arch *arch, const char *ins1, const char *ins2)
{
	if (!arch || !arch->ins_is_fused)
		return false;

	return arch->ins_is_fused(arch, ins1, ins2);
}

222
static int call__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
223
{
224
	char *endptr, *tok, *name;
225
	struct map *map = ms->map;
226 227 228
	struct addr_map_symbol target = {
		.map = map,
	};
229

230
	ops->target.addr = strtoull(ops->raw, &endptr, 16);
231 232 233 234 235 236 237

	name = strchr(endptr, '<');
	if (name == NULL)
		goto indirect_call;

	name++;

238 239
	if (arch->objdump.skip_functions_char &&
	    strchr(name, arch->objdump.skip_functions_char))
R
Russell King 已提交
240 241
		return -1;

242 243 244 245 246
	tok = strchr(name, '>');
	if (tok == NULL)
		return -1;

	*tok = '\0';
247
	ops->target.name = strdup(name);
248 249
	*tok = '>';

250 251 252 253
	if (ops->target.name == NULL)
		return -1;
find_target:
	target.addr = map__objdump_2mem(map, ops->target.addr);
254

255 256 257
	if (map_groups__find_ams(&target) == 0 &&
	    map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
		ops->target.sym = target.sym;
258

259
	return 0;
260 261 262

indirect_call:
	tok = strchr(endptr, '*');
263 264 265 266 267 268 269 270
	if (tok != NULL) {
		endptr++;

		/* Indirect call can use a non-rip register and offset: callq  *0x8(%rbx).
		 * Do not parse such instruction.  */
		if (strstr(endptr, "(%r") == NULL)
			ops->target.addr = strtoull(endptr, NULL, 16);
	}
271
	goto find_target;
272 273
}

274
static int call__scnprintf(struct ins *ins, char *bf, size_t size,
275
			   struct ins_operands *ops)
276
{
277 278
	if (ops->target.sym)
		return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name);
279

280 281 282
	if (ops->target.addr == 0)
		return ins__raw_scnprintf(ins, bf, size, ops);

283 284 285
	if (ops->target.name)
		return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.name);

286
	return scnprintf(bf, size, "%-6s *%" PRIx64, ins->name, ops->target.addr);
287 288
}

289
static struct ins_ops call_ops = {
290 291
	.parse	   = call__parse,
	.scnprintf = call__scnprintf,
292 293 294 295
};

bool ins__is_call(const struct ins *ins)
{
296
	return ins->ops == &call_ops || ins->ops == &s390_call_ops;
297 298
}

299 300 301 302 303 304 305 306 307 308 309 310 311
/*
 * Prevents from matching commas in the comment section, e.g.:
 * ffff200008446e70:       b.cs    ffff2000084470f4 <generic_exec_single+0x314>  // b.hs, b.nlast
 */
static inline const char *validate_comma(const char *c, struct ins_operands *ops)
{
	if (ops->raw_comment && c > ops->raw_comment)
		return NULL;

	return c;
}

static int jump__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
312
{
313 314 315 316 317
	struct map *map = ms->map;
	struct symbol *sym = ms->sym;
	struct addr_map_symbol target = {
		.map = map,
	};
318
	const char *c = strchr(ops->raw, ',');
319
	u64 start, end;
320 321 322 323

	ops->raw_comment = strchr(ops->raw, arch->objdump.comment_char);
	c = validate_comma(c, ops);

324 325 326 327 328 329 330 331 332 333 334
	/*
	 * Examples of lines to parse for the _cpp_lex_token@@Base
	 * function:
	 *
	 * 1159e6c: jne    115aa32 <_cpp_lex_token@@Base+0xf92>
	 * 1159e8b: jne    c469be <cpp_named_operator2name@@Base+0xa72>
	 *
	 * The first is a jump to an offset inside the same function,
	 * the second is to another function, i.e. that 0xa72 is an
	 * offset in the cpp_named_operator2name@@base function.
	 */
335 336 337 338 339
	/*
	 * skip over possible up to 2 operands to get to address, e.g.:
	 * tbnz	 w0, #26, ffff0000083cd190 <security_file_permission+0xd0>
	 */
	if (c++ != NULL) {
340
		ops->target.addr = strtoull(c, NULL, 16);
341 342
		if (!ops->target.addr) {
			c = strchr(c, ',');
343
			c = validate_comma(c, ops);
344 345 346 347
			if (c++ != NULL)
				ops->target.addr = strtoull(c, NULL, 16);
		}
	} else {
348
		ops->target.addr = strtoull(ops->raw, NULL, 16);
349
	}
350

351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
	target.addr = map__objdump_2mem(map, ops->target.addr);
	start = map->unmap_ip(map, sym->start),
	end = map->unmap_ip(map, sym->end);

	ops->target.outside = target.addr < start || target.addr > end;

	/*
	 * FIXME: things like this in _cpp_lex_token (gcc's cc1 program):

		cpp_named_operator2name@@Base+0xa72

	 * Point to a place that is after the cpp_named_operator2name
	 * boundaries, i.e.  in the ELF symbol table for cc1
	 * cpp_named_operator2name is marked as being 32-bytes long, but it in
	 * fact is much larger than that, so we seem to need a symbols__find()
	 * routine that looks for >= current->start and  < next_symbol->start,
	 * possibly just for C++ objects?
	 *
	 * For now lets just make some progress by marking jumps to outside the
	 * current function as call like.
	 *
	 * Actual navigation will come next, with further understanding of how
	 * the symbol searching and disassembly should be done.
374
	 */
375 376 377 378
	if (map_groups__find_ams(&target) == 0 &&
	    map__rip_2objdump(target.map, map->map_ip(target.map, target.addr)) == ops->target.addr)
		ops->target.sym = target.sym;

379 380
	if (!ops->target.outside) {
		ops->target.offset = target.addr - start;
381 382 383 384
		ops->target.offset_avail = true;
	} else {
		ops->target.offset_avail = false;
	}
385 386 387 388

	return 0;
}

389
static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
390
			   struct ins_operands *ops)
391
{
392
	const char *c;
393

394
	if (!ops->target.addr || ops->target.offset < 0)
395 396
		return ins__raw_scnprintf(ins, bf, size, ops);

397 398 399
	if (ops->target.outside && ops->target.sym != NULL)
		return scnprintf(bf, size, "%-6s %s", ins->name, ops->target.sym->name);

400
	c = strchr(ops->raw, ',');
401 402
	c = validate_comma(c, ops);

403 404 405
	if (c != NULL) {
		const char *c2 = strchr(c + 1, ',');

406
		c2 = validate_comma(c2, ops);
407 408 409 410 411 412 413 414 415 416
		/* check for 3-op insn */
		if (c2 != NULL)
			c = c2;
		c++;

		/* mirror arch objdump's space-after-comma style */
		if (*c == ' ')
			c++;
	}

417
	return scnprintf(bf, size, "%-6s %.*s%" PRIx64,
418 419
			 ins->name, c ? c - ops->raw : 0, ops->raw,
			 ops->target.offset);
420 421
}

422
static struct ins_ops jump_ops = {
423 424
	.parse	   = jump__parse,
	.scnprintf = jump__scnprintf,
425 426 427 428 429 430 431
};

bool ins__is_jump(const struct ins *ins)
{
	return ins->ops == &jump_ops;
}

432 433 434 435 436 437 438 439
static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep)
{
	char *endptr, *name, *t;

	if (strstr(raw, "(%rip)") == NULL)
		return 0;

	*addrp = strtoull(comment, &endptr, 16);
440 441
	if (endptr == comment)
		return 0;
442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458
	name = strchr(endptr, '<');
	if (name == NULL)
		return -1;

	name++;

	t = strchr(name, '>');
	if (t == NULL)
		return 0;

	*t = '\0';
	*namep = strdup(name);
	*t = '>';

	return 0;
}

459
static int lock__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms)
460 461 462 463 464
{
	ops->locked.ops = zalloc(sizeof(*ops->locked.ops));
	if (ops->locked.ops == NULL)
		return 0;

465
	if (disasm_line__parse(ops->raw, &ops->locked.ins.name, &ops->locked.ops->raw) < 0)
466 467
		goto out_free_ops;

468
	ops->locked.ins.ops = ins__find(arch, ops->locked.ins.name);
469

470
	if (ops->locked.ins.ops == NULL)
N
Namhyung Kim 已提交
471
		goto out_free_ops;
472

473
	if (ops->locked.ins.ops->parse &&
474
	    ops->locked.ins.ops->parse(arch, ops->locked.ops, ms) < 0)
475
		goto out_free_ops;
476 477 478 479

	return 0;

out_free_ops:
480
	zfree(&ops->locked.ops);
481 482 483 484 485 486 487 488
	return 0;
}

static int lock__scnprintf(struct ins *ins, char *bf, size_t size,
			   struct ins_operands *ops)
{
	int printed;

489
	if (ops->locked.ins.ops == NULL)
490 491
		return ins__raw_scnprintf(ins, bf, size, ops);

492
	printed = scnprintf(bf, size, "%-6s ", ins->name);
493
	return printed + ins__scnprintf(&ops->locked.ins, bf + printed,
494 495 496
					size - printed, ops->locked.ops);
}

497 498
static void lock__delete(struct ins_operands *ops)
{
499
	struct ins *ins = &ops->locked.ins;
500

501
	if (ins->ops && ins->ops->free)
502 503 504 505
		ins->ops->free(ops->locked.ops);
	else
		ins__delete(ops->locked.ops);

506 507 508
	zfree(&ops->locked.ops);
	zfree(&ops->target.raw);
	zfree(&ops->target.name);
509 510
}

511
static struct ins_ops lock_ops = {
512
	.free	   = lock__delete,
513 514 515 516
	.parse	   = lock__parse,
	.scnprintf = lock__scnprintf,
};

517
static int mov__parse(struct arch *arch, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
518 519 520 521 522 523 524 525 526
{
	char *s = strchr(ops->raw, ','), *target, *comment, prev;

	if (s == NULL)
		return -1;

	*s = '\0';
	ops->source.raw = strdup(ops->raw);
	*s = ',';
527

528 529 530 531
	if (ops->source.raw == NULL)
		return -1;

	target = ++s;
532
	comment = strchr(s, arch->objdump.comment_char);
533 534 535 536 537

	if (comment != NULL)
		s = comment - 1;
	else
		s = strchr(s, '\0') - 1;
538

539 540 541
	while (s > target && isspace(s[0]))
		--s;
	s++;
542 543 544 545 546 547 548 549 550 551 552 553
	prev = *s;
	*s = '\0';

	ops->target.raw = strdup(target);
	*s = prev;

	if (ops->target.raw == NULL)
		goto out_free_source;

	if (comment == NULL)
		return 0;

554
	comment = ltrim(comment);
555 556
	comment__symbol(ops->source.raw, comment + 1, &ops->source.addr, &ops->source.name);
	comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
557 558 559 560

	return 0;

out_free_source:
561
	zfree(&ops->source.raw);
562 563 564 565 566 567
	return -1;
}

static int mov__scnprintf(struct ins *ins, char *bf, size_t size,
			   struct ins_operands *ops)
{
568
	return scnprintf(bf, size, "%-6s %s,%s", ins->name,
569 570 571 572 573 574 575 576 577
			 ops->source.name ?: ops->source.raw,
			 ops->target.name ?: ops->target.raw);
}

static struct ins_ops mov_ops = {
	.parse	   = mov__parse,
	.scnprintf = mov__scnprintf,
};

578
static int dec__parse(struct arch *arch __maybe_unused, struct ins_operands *ops, struct map_symbol *ms __maybe_unused)
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
{
	char *target, *comment, *s, prev;

	target = s = ops->raw;

	while (s[0] != '\0' && !isspace(s[0]))
		++s;
	prev = *s;
	*s = '\0';

	ops->target.raw = strdup(target);
	*s = prev;

	if (ops->target.raw == NULL)
		return -1;

595
	comment = strchr(s, arch->objdump.comment_char);
596 597 598
	if (comment == NULL)
		return 0;

599
	comment = ltrim(comment);
600
	comment__symbol(ops->target.raw, comment + 1, &ops->target.addr, &ops->target.name);
601 602 603 604 605 606 607

	return 0;
}

static int dec__scnprintf(struct ins *ins, char *bf, size_t size,
			   struct ins_operands *ops)
{
608
	return scnprintf(bf, size, "%-6s %s", ins->name,
609 610 611 612 613 614 615 616
			 ops->target.name ?: ops->target.raw);
}

static struct ins_ops dec_ops = {
	.parse	   = dec__parse,
	.scnprintf = dec__scnprintf,
};

617 618
static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size,
			  struct ins_operands *ops __maybe_unused)
619
{
620
	return scnprintf(bf, size, "%-6s", "nop");
621 622 623 624 625 626
}

static struct ins_ops nop_ops = {
	.scnprintf = nop__scnprintf,
};

627 628 629 630 631 632 633 634 635
static struct ins_ops ret_ops = {
	.scnprintf = ins__raw_scnprintf,
};

bool ins__is_ret(const struct ins *ins)
{
	return ins->ops == &ret_ops;
}

636 637 638 639 640
bool ins__is_lock(const struct ins *ins)
{
	return ins->ops == &lock_ops;
}

641
static int ins__key_cmp(const void *name, const void *insp)
642 643 644 645 646 647
{
	const struct ins *ins = insp;

	return strcmp(name, ins->name);
}

648 649 650 651 652 653 654 655
static int ins__cmp(const void *a, const void *b)
{
	const struct ins *ia = a;
	const struct ins *ib = b;

	return strcmp(ia->name, ib->name);
}

656
static void ins__sort(struct arch *arch)
657
{
658
	const int nmemb = arch->nr_instructions;
659

660
	qsort(arch->instructions, nmemb, sizeof(struct ins), ins__cmp);
661 662
}

663
static struct ins_ops *__ins__find(struct arch *arch, const char *name)
664
{
665
	struct ins *ins;
666
	const int nmemb = arch->nr_instructions;
667

668 669 670
	if (!arch->sorted_instructions) {
		ins__sort(arch);
		arch->sorted_instructions = true;
671
	}
672

673 674
	ins = bsearch(name, arch->instructions, nmemb, sizeof(struct ins), ins__key_cmp);
	return ins ? ins->ops : NULL;
675 676
}

677 678 679 680 681 682 683 684 685 686
static struct ins_ops *ins__find(struct arch *arch, const char *name)
{
	struct ins_ops *ops = __ins__find(arch, name);

	if (!ops && arch->associate_instruction_ops)
		ops = arch->associate_instruction_ops(arch, name);

	return ops;
}

687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
static int arch__key_cmp(const void *name, const void *archp)
{
	const struct arch *arch = archp;

	return strcmp(name, arch->name);
}

static int arch__cmp(const void *a, const void *b)
{
	const struct arch *aa = a;
	const struct arch *ab = b;

	return strcmp(aa->name, ab->name);
}

static void arch__sort(void)
{
	const int nmemb = ARRAY_SIZE(architectures);

	qsort(architectures, nmemb, sizeof(struct arch), arch__cmp);
}

static struct arch *arch__find(const char *name)
{
	const int nmemb = ARRAY_SIZE(architectures);
	static bool sorted;

	if (!sorted) {
		arch__sort();
		sorted = true;
	}

	return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp);
}

722 723 724 725 726 727 728 729 730 731
static struct annotated_source *annotated_source__new(void)
{
	struct annotated_source *src = zalloc(sizeof(*src));

	if (src != NULL)
		INIT_LIST_HEAD(&src->source);

	return src;
}

732
static __maybe_unused void annotated_source__delete(struct annotated_source *src)
733 734 735 736 737 738 739 740
{
	if (src == NULL)
		return;
	zfree(&src->histograms);
	zfree(&src->cycles_hist);
	free(src);
}

741 742
static int annotated_source__alloc_histograms(struct annotated_source *src,
					      size_t size, int nr_hists)
743
{
744 745
	size_t sizeof_sym_hist;

746 747 748 749 750 751 752 753 754 755
	/*
	 * Add buffer of one element for zero length symbol.
	 * When sample is taken from first instruction of
	 * zero length symbol, perf still resolves it and
	 * shows symbol name in perf report and allows to
	 * annotate it.
	 */
	if (size == 0)
		size = 1;

756
	/* Check for overflow when calculating sizeof_sym_hist */
757
	if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(struct sym_hist_entry))
758 759
		return -1;

760
	sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry));
761 762

	/* Check for overflow in zalloc argument */
763
	if (sizeof_sym_hist > SIZE_MAX / nr_hists)
764
		return -1;
765

766 767 768 769 770 771
	src->sizeof_sym_hist = sizeof_sym_hist;
	src->nr_histograms   = nr_hists;
	src->histograms	     = calloc(nr_hists, sizeof_sym_hist) ;
	return src->histograms ? 0 : -1;
}

772 773 774 775 776 777 778 779 780 781 782 783
/* The cycles histogram is lazily allocated. */
static int symbol__alloc_hist_cycles(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);
	const size_t size = symbol__size(sym);

	notes->src->cycles_hist = calloc(size, sizeof(struct cyc_hist));
	if (notes->src->cycles_hist == NULL)
		return -1;
	return 0;
}

784 785 786 787
void symbol__annotate_zero_histograms(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);

788
	pthread_mutex_lock(&notes->lock);
789
	if (notes->src != NULL) {
790 791
		memset(notes->src->histograms, 0,
		       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
792 793 794 795
		if (notes->src->cycles_hist)
			memset(notes->src->cycles_hist, 0,
				symbol__size(sym) * sizeof(struct cyc_hist));
	}
796
	pthread_mutex_unlock(&notes->lock);
797 798
}

799
static int __symbol__account_cycles(struct cyc_hist *ch,
800 801 802 803 804 805 806 807 808 809 810 811 812 813 814
				    u64 start,
				    unsigned offset, unsigned cycles,
				    unsigned have_start)
{
	/*
	 * For now we can only account one basic block per
	 * final jump. But multiple could be overlapping.
	 * Always account the longest one. So when
	 * a shorter one has been already seen throw it away.
	 *
	 * We separately always account the full cycles.
	 */
	ch[offset].num_aggr++;
	ch[offset].cycles_aggr += cycles;

815 816 817 818 819 820 821 822 823
	if (cycles > ch[offset].cycles_max)
		ch[offset].cycles_max = cycles;

	if (ch[offset].cycles_min) {
		if (cycles && cycles < ch[offset].cycles_min)
			ch[offset].cycles_min = cycles;
	} else
		ch[offset].cycles_min = cycles;

824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844
	if (!have_start && ch[offset].have_start)
		return 0;
	if (ch[offset].num) {
		if (have_start && (!ch[offset].have_start ||
				   ch[offset].start > start)) {
			ch[offset].have_start = 0;
			ch[offset].cycles = 0;
			ch[offset].num = 0;
			if (ch[offset].reset < 0xffff)
				ch[offset].reset++;
		} else if (have_start &&
			   ch[offset].start < start)
			return 0;
	}
	ch[offset].have_start = have_start;
	ch[offset].start = start;
	ch[offset].cycles += cycles;
	ch[offset].num++;
	return 0;
}

845
static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map,
846
				      struct annotated_source *src, int evidx, u64 addr,
847
				      struct perf_sample *sample)
848
{
849
	unsigned offset;
850 851 852 853
	struct sym_hist *h;

	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));

854 855
	if ((addr < sym->start || addr >= sym->end) &&
	    (addr != sym->end || sym->start != sym->end)) {
856 857
		pr_debug("%s(%d): ERANGE! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 "\n",
		       __func__, __LINE__, sym->name, sym->start, addr, sym->end);
858
		return -ERANGE;
859
	}
860

861
	offset = addr - sym->start;
862
	h = annotated_source__histogram(src, evidx);
863 864 865 866 867
	if (h == NULL) {
		pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n",
			 __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC);
		return -ENOMEM;
	}
868
	h->nr_samples++;
869
	h->addr[offset].nr_samples++;
870 871
	h->period += sample->period;
	h->addr[offset].period += sample->period;
872 873

	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
874 875 876
		  ", evidx=%d] => nr_samples: %" PRIu64 ", period: %" PRIu64 "\n",
		  sym->start, sym->name, addr, addr - sym->start, evidx,
		  h->addr[offset].nr_samples, h->addr[offset].period);
877 878 879
	return 0;
}

880
static struct cyc_hist *symbol__cycles_hist(struct symbol *sym)
881 882 883 884
{
	struct annotation *notes = symbol__annotation(sym);

	if (notes->src == NULL) {
885 886
		notes->src = annotated_source__new();
		if (notes->src == NULL)
887
			return NULL;
888
		goto alloc_cycles_hist;
889
	}
890 891 892 893

	if (!notes->src->cycles_hist) {
alloc_cycles_hist:
		symbol__alloc_hist_cycles(sym);
894
	}
895 896

	return notes->src->cycles_hist;
897 898
}

899
struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists)
900 901 902 903 904 905 906 907 908 909 910 911 912
{
	struct annotation *notes = symbol__annotation(sym);

	if (notes->src == NULL) {
		notes->src = annotated_source__new();
		if (notes->src == NULL)
			return NULL;
		goto alloc_histograms;
	}

	if (notes->src->histograms == NULL) {
alloc_histograms:
		annotated_source__alloc_histograms(notes->src, symbol__size(sym),
913
						   nr_hists);
914 915 916 917 918
	}

	return notes->src;
}

919
static int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
920
				    struct perf_evsel *evsel, u64 addr,
921
				    struct perf_sample *sample)
922
{
923
	struct annotated_source *src;
924

925
	if (sym == NULL)
926
		return 0;
927
	src = symbol__hists(sym, evsel->evlist->nr_entries);
928
	if (src == NULL)
929
		return -ENOMEM;
930
	return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample);
931 932
}

933 934 935
static int symbol__account_cycles(u64 addr, u64 start,
				  struct symbol *sym, unsigned cycles)
{
936
	struct cyc_hist *cycles_hist;
937 938 939 940
	unsigned offset;

	if (sym == NULL)
		return 0;
941 942
	cycles_hist = symbol__cycles_hist(sym);
	if (cycles_hist == NULL)
943 944 945 946 947 948 949 950 951 952 953
		return -ENOMEM;
	if (addr < sym->start || addr >= sym->end)
		return -ERANGE;

	if (start) {
		if (start < sym->start || start >= sym->end)
			return -ERANGE;
		if (start >= addr)
			start = 0;
	}
	offset = addr - sym->start;
954
	return __symbol__account_cycles(cycles_hist,
955 956 957 958 959 960 961 962 963
					start ? start - sym->start : 0,
					offset, cycles,
					!!start);
}

int addr_map_symbol__account_cycles(struct addr_map_symbol *ams,
				    struct addr_map_symbol *start,
				    unsigned cycles)
{
964
	u64 saddr = 0;
965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982
	int err;

	if (!cycles)
		return 0;

	/*
	 * Only set start when IPC can be computed. We can only
	 * compute it when the basic block is completely in a single
	 * function.
	 * Special case the case when the jump is elsewhere, but
	 * it starts on the function start.
	 */
	if (start &&
		(start->sym == ams->sym ||
		 (ams->sym &&
		   start->addr == ams->sym->start + ams->map->start)))
		saddr = start->al_addr;
	if (saddr == 0)
983
		pr_debug2("BB with bad start: addr %"PRIx64" start %"PRIx64" sym %"PRIx64" saddr %"PRIx64"\n",
984 985 986 987 988 989 990 991 992 993
			ams->addr,
			start ? start->addr : 0,
			ams->sym ? ams->sym->start + ams->map->start : 0,
			saddr);
	err = symbol__account_cycles(ams->al_addr, saddr, ams->sym, cycles);
	if (err)
		pr_debug2("account_cycles failed %d\n", err);
	return err;
}

994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008
static unsigned annotation__count_insn(struct annotation *notes, u64 start, u64 end)
{
	unsigned n_insn = 0;
	u64 offset;

	for (offset = start; offset <= end; offset++) {
		if (notes->offsets[offset])
			n_insn++;
	}
	return n_insn;
}

static void annotation__count_and_fill(struct annotation *notes, u64 start, u64 end, struct cyc_hist *ch)
{
	unsigned n_insn;
1009
	unsigned int cover_insn = 0;
1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022
	u64 offset;

	n_insn = annotation__count_insn(notes, start, end);
	if (n_insn && ch->num && ch->cycles) {
		float ipc = n_insn / ((double)ch->cycles / (double)ch->num);

		/* Hide data when there are too many overlaps. */
		if (ch->reset >= 0x7fff || ch->reset >= ch->num / 2)
			return;

		for (offset = start; offset <= end; offset++) {
			struct annotation_line *al = notes->offsets[offset];

1023
			if (al && al->ipc == 0.0) {
1024
				al->ipc = ipc;
1025 1026 1027 1028 1029 1030 1031 1032
				cover_insn++;
			}
		}

		if (cover_insn) {
			notes->hit_cycles += ch->cycles;
			notes->hit_insn += n_insn * ch->num;
			notes->cover_insn += cover_insn;
1033 1034 1035 1036 1037 1038
		}
	}
}

void annotation__compute_ipc(struct annotation *notes, size_t size)
{
1039
	s64 offset;
1040 1041 1042 1043

	if (!notes->src || !notes->src->cycles_hist)
		return;

1044 1045 1046 1047 1048
	notes->total_insn = annotation__count_insn(notes, 0, size - 1);
	notes->hit_cycles = 0;
	notes->hit_insn = 0;
	notes->cover_insn = 0;

1049
	pthread_mutex_lock(&notes->lock);
1050
	for (offset = size - 1; offset >= 0; --offset) {
1051 1052 1053 1054 1055 1056 1057 1058 1059
		struct cyc_hist *ch;

		ch = &notes->src->cycles_hist[offset];
		if (ch && ch->cycles) {
			struct annotation_line *al;

			if (ch->have_start)
				annotation__count_and_fill(notes, ch->start, offset, ch);
			al = notes->offsets[offset];
1060
			if (al && ch->num_aggr) {
1061
				al->cycles = ch->cycles_aggr / ch->num_aggr;
1062 1063 1064
				al->cycles_max = ch->cycles_max;
				al->cycles_min = ch->cycles_min;
			}
1065 1066 1067 1068 1069 1070
			notes->have_cycles = true;
		}
	}
	pthread_mutex_unlock(&notes->lock);
}

1071
int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample,
1072
				 struct perf_evsel *evsel)
1073
{
1074
	return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample);
1075 1076
}

1077
int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample,
1078
				 struct perf_evsel *evsel, u64 ip)
1079
{
1080
	return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample);
1081 1082
}

1083
static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms)
1084
{
1085
	dl->ins.ops = ins__find(arch, dl->ins.name);
1086

1087
	if (!dl->ins.ops)
1088 1089
		return;

1090
	if (dl->ins.ops->parse && dl->ins.ops->parse(arch, &dl->ops, ms) < 0)
1091
		dl->ins.ops = NULL;
1092 1093
}

1094
static int disasm_line__parse(char *line, const char **namep, char **rawp)
1095
{
1096
	char tmp, *name = ltrim(line);
1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113

	if (name[0] == '\0')
		return -1;

	*rawp = name + 1;

	while ((*rawp)[0] != '\0' && !isspace((*rawp)[0]))
		++*rawp;

	tmp = (*rawp)[0];
	(*rawp)[0] = '\0';
	*namep = strdup(name);

	if (*namep == NULL)
		goto out_free_name;

	(*rawp)[0] = tmp;
1114
	*rawp = ltrim(*rawp);
1115 1116 1117 1118

	return 0;

out_free_name:
1119 1120
	free((void *)namep);
	*namep = NULL;
1121 1122 1123
	return -1;
}

1124 1125
struct annotate_args {
	size_t			 privsize;
1126
	struct arch		*arch;
1127
	struct map_symbol	 ms;
1128
	struct perf_evsel	*evsel;
1129
	struct annotation_options *options;
1130 1131 1132
	s64			 offset;
	char			*line;
	int			 line_nr;
1133 1134
};

1135 1136 1137 1138
static void annotation_line__delete(struct annotation_line *al)
{
	void *ptr = (void *) al - al->privsize;

1139
	free_srcline(al->path);
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158
	zfree(&al->line);
	free(ptr);
}

/*
 * Allocating the annotation line data with following
 * structure:
 *
 *    --------------------------------------
 *    private space | struct annotation_line
 *    --------------------------------------
 *
 * Size of the private space is stored in 'struct annotation_line'.
 *
 */
static struct annotation_line *
annotation_line__new(struct annotate_args *args, size_t privsize)
{
	struct annotation_line *al;
1159
	struct perf_evsel *evsel = args->evsel;
1160
	size_t size = privsize + sizeof(*al);
1161 1162 1163 1164 1165
	int nr = 1;

	if (perf_evsel__is_group_event(evsel))
		nr = evsel->nr_members;

1166
	size += sizeof(al->data[0]) * nr;
1167 1168 1169 1170 1171 1172 1173 1174

	al = zalloc(size);
	if (al) {
		al = (void *) al + privsize;
		al->privsize   = privsize;
		al->offset     = args->offset;
		al->line       = strdup(args->line);
		al->line_nr    = args->line_nr;
1175
		al->data_nr    = nr;
1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
	}

	return al;
}

/*
 * Allocating the disasm annotation line data with
 * following structure:
 *
 *    ------------------------------------------------------------
 *    privsize space | struct disasm_line | struct annotation_line
 *    ------------------------------------------------------------
 *
 * We have 'struct annotation_line' member as last member
 * of 'struct disasm_line' to have an easy access.
 *
 */
1193
static struct disasm_line *disasm_line__new(struct annotate_args *args)
1194
{
1195 1196 1197
	struct disasm_line *dl = NULL;
	struct annotation_line *al;
	size_t privsize = args->privsize + offsetof(struct disasm_line, al);
1198

1199 1200 1201
	al = annotation_line__new(args, privsize);
	if (al != NULL) {
		dl = disasm_line(al);
1202 1203

		if (dl->al.line == NULL)
1204
			goto out_delete;
1205

1206
		if (args->offset != -1) {
1207
			if (disasm_line__parse(dl->al.line, &dl->ins.name, &dl->ops.raw) < 0)
1208 1209
				goto out_free_line;

1210
			disasm_line__init_ins(dl, args->arch, &args->ms);
1211
		}
1212 1213
	}

1214
	return dl;
1215 1216

out_free_line:
1217
	zfree(&dl->al.line);
1218
out_delete:
1219
	free(dl);
1220
	return NULL;
1221 1222
}

1223
void disasm_line__free(struct disasm_line *dl)
1224
{
1225 1226
	if (dl->ins.ops && dl->ins.ops->free)
		dl->ins.ops->free(&dl->ops);
1227 1228
	else
		ins__delete(&dl->ops);
1229 1230
	free((void *)dl->ins.name);
	dl->ins.name = NULL;
1231
	annotation_line__delete(&dl->al);
1232 1233
}

1234 1235
int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw)
{
1236
	if (raw || !dl->ins.ops)
1237
		return scnprintf(bf, size, "%-6s %s", dl->ins.name, dl->ops.raw);
1238

1239
	return ins__scnprintf(&dl->ins, bf, size, &dl->ops);
1240 1241
}

1242
static void annotation_line__add(struct annotation_line *al, struct list_head *head)
1243
{
1244
	list_add_tail(&al->node, head);
1245 1246
}

1247 1248
struct annotation_line *
annotation_line__next(struct annotation_line *pos, struct list_head *head)
1249
{
1250 1251
	list_for_each_entry_continue(pos, head, node)
		if (pos->offset >= 0)
1252 1253 1254 1255 1256
			return pos;

	return NULL;
}

1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338
static const char *annotate__address_color(struct block_range *br)
{
	double cov = block_range__coverage(br);

	if (cov >= 0) {
		/* mark red for >75% coverage */
		if (cov > 0.75)
			return PERF_COLOR_RED;

		/* mark dull for <1% coverage */
		if (cov < 0.01)
			return PERF_COLOR_NORMAL;
	}

	return PERF_COLOR_MAGENTA;
}

static const char *annotate__asm_color(struct block_range *br)
{
	double cov = block_range__coverage(br);

	if (cov >= 0) {
		/* mark dull for <1% coverage */
		if (cov < 0.01)
			return PERF_COLOR_NORMAL;
	}

	return PERF_COLOR_BLUE;
}

static void annotate__branch_printf(struct block_range *br, u64 addr)
{
	bool emit_comment = true;

	if (!br)
		return;

#if 1
	if (br->is_target && br->start == addr) {
		struct block_range *branch = br;
		double p;

		/*
		 * Find matching branch to our target.
		 */
		while (!branch->is_branch)
			branch = block_range__next(branch);

		p = 100 *(double)br->entry / branch->coverage;

		if (p > 0.1) {
			if (emit_comment) {
				emit_comment = false;
				printf("\t#");
			}

			/*
			 * The percentage of coverage joined at this target in relation
			 * to the next branch.
			 */
			printf(" +%.2f%%", p);
		}
	}
#endif
	if (br->is_branch && br->end == addr) {
		double p = 100*(double)br->taken / br->coverage;

		if (p > 0.1) {
			if (emit_comment) {
				emit_comment = false;
				printf("\t#");
			}

			/*
			 * The percentage of coverage leaving at this branch, and
			 * its prediction ratio.
			 */
			printf(" -%.2f%% (p:%.2f%%)", p, 100*(double)br->pred  / br->taken);
		}
	}
}

1339
static int disasm_line__print(struct disasm_line *dl, u64 start, int addr_fmt_width)
1340
{
1341 1342 1343 1344 1345
	s64 offset = dl->al.offset;
	const u64 addr = start + offset;
	struct block_range *br;

	br = block_range__find(addr);
1346
	color_fprintf(stdout, annotate__address_color(br), "  %*" PRIx64 ":", addr_fmt_width, addr);
1347 1348 1349 1350 1351 1352 1353 1354
	color_fprintf(stdout, annotate__asm_color(br), "%s", dl->al.line);
	annotate__branch_printf(br, addr);
	return 0;
}

static int
annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start,
		       struct perf_evsel *evsel, u64 len, int min_pcnt, int printed,
1355 1356
		       int max_lines, struct annotation_line *queue, int addr_fmt_width,
		       int percent_type)
1357 1358
{
	struct disasm_line *dl = container_of(al, struct disasm_line, al);
1359 1360 1361
	static const char *prev_line;
	static const char *prev_color;

1362
	if (al->offset != -1) {
1363
		double max_percent = 0.0;
1364
		int i, nr_percent = 1;
1365 1366
		const char *color;
		struct annotation *notes = symbol__annotation(sym);
1367

1368
		for (i = 0; i < al->data_nr; i++) {
1369 1370 1371
			double percent;

			percent = annotation_data__percent(&al->data[i],
1372
							   percent_type);
1373

1374 1375
			if (percent > max_percent)
				max_percent = percent;
1376 1377
		}

1378 1379
		if (al->data_nr > nr_percent)
			nr_percent = al->data_nr;
1380

1381
		if (max_percent < min_pcnt)
1382 1383
			return -1;

1384
		if (max_lines && printed >= max_lines)
1385
			return 1;
1386

1387
		if (queue != NULL) {
1388 1389
			list_for_each_entry_from(queue, &notes->src->source, node) {
				if (queue == al)
1390
					break;
1391
				annotation_line__print(queue, sym, start, evsel, len,
1392 1393
						       0, 0, 1, NULL, addr_fmt_width,
						       percent_type);
1394 1395 1396
			}
		}

1397
		color = get_percent_color(max_percent);
1398 1399 1400 1401 1402 1403

		/*
		 * Also color the filename and line if needed, with
		 * the same color than the percentage. Don't print it
		 * twice for close colored addr with the same filename:line
		 */
1404 1405
		if (al->path) {
			if (!prev_line || strcmp(prev_line, al->path)
1406
				       || color != prev_color) {
1407 1408
				color_fprintf(stdout, color, " %s", al->path);
				prev_line = al->path;
1409 1410 1411 1412
				prev_color = color;
			}
		}

1413
		for (i = 0; i < nr_percent; i++) {
1414
			struct annotation_data *data = &al->data[i];
1415
			double percent;
1416

1417
			percent = annotation_data__percent(data, percent_type);
1418
			color = get_percent_color(percent);
1419 1420

			if (symbol_conf.show_total_period)
1421
				color_fprintf(stdout, color, " %11" PRIu64,
1422
					      data->he.period);
1423 1424
			else if (symbol_conf.show_nr_samples)
				color_fprintf(stdout, color, " %7" PRIu64,
1425
					      data->he.nr_samples);
1426
			else
1427
				color_fprintf(stdout, color, " %7.2f", percent);
1428 1429
		}

1430
		printf(" : ");
1431

1432
		disasm_line__print(dl, start, addr_fmt_width);
1433
		printf("\n");
1434
	} else if (max_lines && printed >= max_lines)
1435 1436
		return 1;
	else {
1437
		int width = symbol_conf.show_total_period ? 12 : 8;
1438

1439 1440 1441
		if (queue)
			return -1;

1442
		if (perf_evsel__is_group_event(evsel))
1443 1444
			width *= evsel->nr_members;

1445
		if (!*al->line)
1446
			printf(" %*s:\n", width, " ");
1447
		else
1448
			printf(" %*s:     %*s %s\n", width, " ", addr_fmt_width, " ", al->line);
1449
	}
1450 1451

	return 0;
1452 1453
}

1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473
/*
 * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
 * which looks like following
 *
 *  0000000000415500 <_init>:
 *    415500:       sub    $0x8,%rsp
 *    415504:       mov    0x2f5ad5(%rip),%rax        # 70afe0 <_DYNAMIC+0x2f8>
 *    41550b:       test   %rax,%rax
 *    41550e:       je     415515 <_init+0x15>
 *    415510:       callq  416e70 <__gmon_start__@plt>
 *    415515:       add    $0x8,%rsp
 *    415519:       retq
 *
 * it will be parsed and saved into struct disasm_line as
 *  <offset>       <name>  <ops.raw>
 *
 * The offset will be a relative offset from the start of the symbol and -1
 * means that it's not a disassembly line so should be treated differently.
 * The ops.raw part will be parsed further according to type of the instruction.
 */
1474
static int symbol__parse_objdump_line(struct symbol *sym, FILE *file,
1475
				      struct annotate_args *args,
1476
				      int *line_nr)
1477
{
1478
	struct map *map = args->ms.map;
1479
	struct annotation *notes = symbol__annotation(sym);
1480
	struct disasm_line *dl;
1481
	char *line = NULL, *parsed_line, *tmp, *tmp2;
1482 1483
	size_t line_len;
	s64 line_ip, offset = -1;
1484
	regmatch_t match[2];
1485 1486 1487 1488 1489 1490 1491 1492

	if (getline(&line, &line_len, file) < 0)
		return -1;

	if (!line)
		return -1;

	line_ip = -1;
1493
	parsed_line = rtrim(line);
1494

1495
	/* /filename:linenr ? Save line number and ignore. */
1496 1497
	if (regexec(&file_lineno, parsed_line, 2, match, 0) == 0) {
		*line_nr = atoi(parsed_line + match[1].rm_so);
1498 1499 1500
		return 0;
	}

1501
	tmp = ltrim(parsed_line);
1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515
	if (*tmp) {
		/*
		 * Parse hexa addresses followed by ':'
		 */
		line_ip = strtoull(tmp, &tmp2, 16);
		if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
			line_ip = -1;
	}

	if (line_ip != -1) {
		u64 start = map__rip_2objdump(map, sym->start),
		    end = map__rip_2objdump(map, sym->end);

		offset = line_ip - start;
1516
		if ((u64)line_ip < start || (u64)line_ip >= end)
1517
			offset = -1;
1518 1519
		else
			parsed_line = tmp2 + 1;
N
Namhyung Kim 已提交
1520
	}
1521

1522 1523 1524
	args->offset  = offset;
	args->line    = parsed_line;
	args->line_nr = *line_nr;
1525
	args->ms.sym  = sym;
1526 1527

	dl = disasm_line__new(args);
1528
	free(line);
1529
	(*line_nr)++;
1530

1531
	if (dl == NULL)
1532
		return -1;
1533

1534
	if (!disasm_line__has_local_offset(dl)) {
1535 1536
		dl->ops.target.offset = dl->ops.target.addr -
					map__rip_2objdump(map, sym->start);
1537 1538
		dl->ops.target.offset_avail = true;
	}
1539

1540 1541
	/* kcore has no symbols, so add the call target symbol */
	if (dl->ins.ops && ins__is_call(&dl->ins) && !dl->ops.target.sym) {
1542 1543 1544 1545 1546
		struct addr_map_symbol target = {
			.map = map,
			.addr = dl->ops.target.addr,
		};

1547
		if (!map_groups__find_ams(&target) &&
1548
		    target.sym->start == target.al_addr)
1549
			dl->ops.target.sym = target.sym;
1550 1551
	}

1552
	annotation_line__add(&dl->al, &notes->src->source);
1553 1554 1555 1556

	return 0;
}

1557 1558 1559 1560 1561
static __attribute__((constructor)) void symbol__init_regexpr(void)
{
	regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);
}

1562 1563 1564 1565 1566 1567 1568
static void delete_last_nop(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);
	struct list_head *list = &notes->src->source;
	struct disasm_line *dl;

	while (!list_empty(list)) {
1569
		dl = list_entry(list->prev, struct disasm_line, al.node);
1570

1571 1572
		if (dl->ins.ops) {
			if (dl->ins.ops != &nop_ops)
1573 1574
				return;
		} else {
1575 1576 1577
			if (!strstr(dl->al.line, " nop ") &&
			    !strstr(dl->al.line, " nopl ") &&
			    !strstr(dl->al.line, " nopw "))
1578 1579 1580
				return;
		}

1581
		list_del(&dl->al.node);
1582 1583 1584 1585
		disasm_line__free(dl);
	}
}

1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624
int symbol__strerror_disassemble(struct symbol *sym __maybe_unused, struct map *map,
			      int errnum, char *buf, size_t buflen)
{
	struct dso *dso = map->dso;

	BUG_ON(buflen == 0);

	if (errnum >= 0) {
		str_error_r(errnum, buf, buflen);
		return 0;
	}

	switch (errnum) {
	case SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX: {
		char bf[SBUILD_ID_SIZE + 15] = " with build id ";
		char *build_id_msg = NULL;

		if (dso->has_build_id) {
			build_id__sprintf(dso->build_id,
					  sizeof(dso->build_id), bf + 15);
			build_id_msg = bf;
		}
		scnprintf(buf, buflen,
			  "No vmlinux file%s\nwas found in the path.\n\n"
			  "Note that annotation using /proc/kcore requires CAP_SYS_RAWIO capability.\n\n"
			  "Please use:\n\n"
			  "  perf buildid-cache -vu vmlinux\n\n"
			  "or:\n\n"
			  "  --vmlinux vmlinux\n", build_id_msg ?: "");
	}
		break;
	default:
		scnprintf(buf, buflen, "Internal error: Invalid %d error code\n", errnum);
		break;
	}

	return 0;
}

1625
static int dso__disassemble_filename(struct dso *dso, char *filename, size_t filename_size)
1626
{
1627 1628
	char linkname[PATH_MAX];
	char *build_id_filename;
1629
	char *build_id_path = NULL;
1630
	char *pos;
1631

1632 1633
	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS &&
	    !dso__is_kcore(dso))
1634
		return SYMBOL_ANNOTATE_ERRNO__NO_VMLINUX;
1635

1636
	build_id_filename = dso__build_id_filename(dso, NULL, 0, false);
1637 1638 1639
	if (build_id_filename) {
		__symbol__join_symfs(filename, filename_size, build_id_filename);
		free(build_id_filename);
1640
	} else {
1641 1642
		if (dso->has_build_id)
			return ENOMEM;
1643
		goto fallback;
1644 1645
	}

1646 1647 1648 1649
	build_id_path = strdup(filename);
	if (!build_id_path)
		return -1;

1650 1651 1652 1653 1654 1655 1656 1657
	/*
	 * old style build-id cache has name of XX/XXXXXXX.. while
	 * new style has XX/XXXXXXX../{elf,kallsyms,vdso}.
	 * extract the build-id part of dirname in the new style only.
	 */
	pos = strrchr(build_id_path, '/');
	if (pos && strlen(pos) < SBUILD_ID_SIZE - 2)
		dirname(build_id_path);
1658

1659
	if (dso__is_kcore(dso) ||
1660
	    readlink(build_id_path, linkname, sizeof(linkname)) < 0 ||
1661 1662
	    strstr(linkname, DSO__NAME_KALLSYMS) ||
	    access(filename, R_OK)) {
1663 1664 1665 1666 1667 1668
fallback:
		/*
		 * If we don't have build-ids or the build-id file isn't in the
		 * cache, or is just a kallsyms file, well, lets hope that this
		 * DSO is the same as when 'perf record' ran.
		 */
1669
		__symbol__join_symfs(filename, filename_size, dso->long_name);
1670 1671
	}

1672
	free(build_id_path);
1673 1674 1675
	return 0;
}

1676
static int symbol__disassemble(struct symbol *sym, struct annotate_args *args)
1677
{
1678
	struct annotation_options *opts = args->options;
1679
	struct map *map = args->ms.map;
1680
	struct dso *dso = map->dso;
1681
	char *command;
1682 1683 1684 1685
	FILE *file;
	char symfs_filename[PATH_MAX];
	struct kcore_extract kce;
	bool delete_extract = false;
1686
	bool decomp = false;
1687 1688 1689 1690 1691 1692 1693 1694 1695
	int stdout_fd[2];
	int lineno = 0;
	int nline;
	pid_t pid;
	int err = dso__disassemble_filename(dso, symfs_filename, sizeof(symfs_filename));

	if (err)
		return err;

1696
	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
1697
		 symfs_filename, sym->name, map->unmap_ip(map, sym->start),
1698 1699 1700 1701 1702
		 map->unmap_ip(map, sym->end));

	pr_debug("annotating [%p] %30s : [%p] %30s\n",
		 dso, dso->long_name, sym, sym->name);

1703 1704 1705 1706
	if (dso__is_kcore(dso)) {
		kce.kcore_filename = symfs_filename;
		kce.addr = map__rip_2objdump(map, sym->start);
		kce.offs = sym->start;
1707
		kce.len = sym->end - sym->start;
1708 1709 1710 1711 1712
		if (!kcore_extract__create(&kce)) {
			delete_extract = true;
			strlcpy(symfs_filename, kce.extract_filename,
				sizeof(symfs_filename));
		}
1713
	} else if (dso__needs_decompress(dso)) {
1714
		char tmp[KMOD_DECOMP_LEN];
1715

1716 1717
		if (dso__decompress_kmodule_path(dso, symfs_filename,
						 tmp, sizeof(tmp)) < 0)
1718
			goto out;
1719

1720
		decomp = true;
1721
		strcpy(symfs_filename, tmp);
1722 1723
	}

1724
	err = asprintf(&command,
1725
		 "%s %s%s --start-address=0x%016" PRIx64
1726
		 " --stop-address=0x%016" PRIx64
1727
		 " -l -d %s %s -C \"$1\" 2>/dev/null|grep -v \"$1:\"|expand",
1728
		 opts->objdump_path ?: "objdump",
1729 1730
		 opts->disassembler_style ? "-M " : "",
		 opts->disassembler_style ?: "",
1731
		 map__rip_2objdump(map, sym->start),
1732
		 map__rip_2objdump(map, sym->end),
1733
		 opts->show_asm_raw ? "" : "--no-show-raw",
1734
		 opts->annotate_src ? "-S" : "");
1735

1736 1737 1738 1739 1740
	if (err < 0) {
		pr_err("Failure allocating memory for the command to run\n");
		goto out_remove_tmp;
	}

1741 1742
	pr_debug("Executing: %s\n", command);

1743 1744 1745
	err = -1;
	if (pipe(stdout_fd) < 0) {
		pr_err("Failure creating the pipe to run %s\n", command);
1746
		goto out_free_command;
1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758
	}

	pid = fork();
	if (pid < 0) {
		pr_err("Failure forking to run %s\n", command);
		goto out_close_stdout;
	}

	if (pid == 0) {
		close(stdout_fd[0]);
		dup2(stdout_fd[1], 1);
		close(stdout_fd[1]);
1759 1760
		execl("/bin/sh", "sh", "-c", command, "--", symfs_filename,
		      NULL);
1761 1762 1763 1764 1765 1766 1767
		perror(command);
		exit(-1);
	}

	close(stdout_fd[1]);

	file = fdopen(stdout_fd[0], "r");
1768
	if (!file) {
1769
		pr_err("Failure creating FILE stream for %s\n", command);
1770 1771 1772 1773
		/*
		 * If we were using debug info should retry with
		 * original binary.
		 */
1774
		goto out_free_command;
1775
	}
1776

1777 1778
	nline = 0;
	while (!feof(file)) {
1779 1780
		/*
		 * The source code line number (lineno) needs to be kept in
1781
		 * across calls to symbol__parse_objdump_line(), so that it
1782 1783 1784
		 * can associate it with the instructions till the next one.
		 * See disasm_line__new() and struct disasm_line::line_nr.
		 */
1785
		if (symbol__parse_objdump_line(sym, file, args, &lineno) < 0)
1786
			break;
1787 1788 1789 1790 1791
		nline++;
	}

	if (nline == 0)
		pr_err("No output from %s\n", command);
1792

1793 1794 1795 1796 1797 1798 1799
	/*
	 * kallsyms does not have symbol sizes so there may a nop at the end.
	 * Remove it.
	 */
	if (dso__is_kcore(dso))
		delete_last_nop(sym);

1800 1801
	fclose(file);
	err = 0;
1802 1803
out_free_command:
	free(command);
1804
out_remove_tmp:
1805 1806
	close(stdout_fd[0]);

1807
	if (decomp)
1808
		unlink(symfs_filename);
1809

1810 1811
	if (delete_extract)
		kcore_extract__delete(&kce);
1812
out:
1813
	return err;
1814 1815 1816

out_close_stdout:
	close(stdout_fd[1]);
1817
	goto out_free_command;
1818 1819
}

1820
static void calc_percent(struct sym_hist *sym_hist,
1821
			 struct hists *hists,
1822
			 struct annotation_data *data,
1823 1824 1825 1826 1827 1828
			 s64 offset, s64 end)
{
	unsigned int hits = 0;
	u64 period = 0;

	while (offset < end) {
1829 1830
		hits   += sym_hist->addr[offset].nr_samples;
		period += sym_hist->addr[offset].period;
1831 1832 1833
		++offset;
	}

1834
	if (sym_hist->nr_samples) {
1835 1836
		data->he.period     = period;
		data->he.nr_samples = hits;
1837
		data->percent[PERCENT_HITS_LOCAL] = 100.0 * hits / sym_hist->nr_samples;
1838
	}
1839 1840 1841 1842

	if (hists->stats.nr_non_filtered_samples)
		data->percent[PERCENT_HITS_GLOBAL] = 100.0 * hits / hists->stats.nr_non_filtered_samples;

1843 1844
	if (sym_hist->period)
		data->percent[PERCENT_PERIOD_LOCAL] = 100.0 * period / sym_hist->period;
1845 1846 1847

	if (hists->stats.total_period)
		data->percent[PERCENT_PERIOD_GLOBAL] = 100.0 * period / hists->stats.total_period;
1848 1849
}

1850
static void annotation__calc_percent(struct annotation *notes,
1851
				     struct perf_evsel *leader, s64 len)
1852 1853
{
	struct annotation_line *al, *next;
1854
	struct perf_evsel *evsel;
1855 1856 1857

	list_for_each_entry(al, &notes->src->source, node) {
		s64 end;
1858
		int i = 0;
1859 1860 1861 1862 1863 1864 1865

		if (al->offset == -1)
			continue;

		next = annotation_line__next(al, &notes->src->source);
		end  = next ? next->offset : len;

1866
		for_each_group_evsel(evsel, leader) {
1867
			struct hists *hists = evsel__hists(evsel);
1868
			struct annotation_data *data;
1869
			struct sym_hist *sym_hist;
1870

1871 1872 1873 1874
			BUG_ON(i >= al->data_nr);

			sym_hist = annotation__histogram(notes, evsel->idx);
			data = &al->data[i++];
1875

1876
			calc_percent(sym_hist, hists, data, al->offset, end);
1877 1878 1879 1880
		}
	}
}

1881
void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel)
1882 1883 1884
{
	struct annotation *notes = symbol__annotation(sym);

1885
	annotation__calc_percent(notes, evsel, symbol__size(sym));
1886 1887
}

1888
int symbol__annotate(struct symbol *sym, struct map *map,
1889
		     struct perf_evsel *evsel, size_t privsize,
1890
		     struct annotation_options *options,
1891
		     struct arch **parch)
1892
{
1893 1894
	struct annotate_args args = {
		.privsize	= privsize,
1895
		.evsel		= evsel,
1896
		.options	= options,
1897
	};
1898
	struct perf_env *env = perf_evsel__env(evsel);
1899
	const char *arch_name = perf_env__arch(env);
1900 1901 1902 1903 1904 1905
	struct arch *arch;
	int err;

	if (!arch_name)
		return -1;

1906
	args.arch = arch = arch__find(arch_name);
1907 1908 1909 1910 1911 1912 1913
	if (arch == NULL)
		return -ENOTSUP;

	if (parch)
		*parch = arch;

	if (arch->init) {
1914
		err = arch->init(arch, env ? env->cpuid : NULL);
1915 1916 1917 1918 1919 1920
		if (err) {
			pr_err("%s: failed to initialize %s arch priv area\n", __func__, arch->name);
			return err;
		}
	}

1921 1922 1923
	args.ms.map = map;
	args.ms.sym = sym;

1924
	return symbol__disassemble(sym, &args);
1925 1926
}

1927 1928
static void insert_source_line(struct rb_root *root, struct annotation_line *al,
			       struct annotation_options *opts)
1929
{
1930
	struct annotation_line *iter;
1931 1932
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;
1933
	int i, ret;
1934 1935 1936

	while (*p != NULL) {
		parent = *p;
1937
		iter = rb_entry(parent, struct annotation_line, rb_node);
1938

1939
		ret = strcmp(iter->path, al->path);
1940
		if (ret == 0) {
1941 1942
			for (i = 0; i < al->data_nr; i++) {
				iter->data[i].percent_sum += annotation_data__percent(&al->data[i],
1943
										      opts->percent_type);
1944
			}
1945 1946 1947 1948 1949 1950 1951 1952 1953
			return;
		}

		if (ret < 0)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

1954 1955
	for (i = 0; i < al->data_nr; i++) {
		al->data[i].percent_sum = annotation_data__percent(&al->data[i],
1956
								   opts->percent_type);
1957
	}
1958

1959 1960
	rb_link_node(&al->rb_node, parent, p);
	rb_insert_color(&al->rb_node, root);
1961 1962
}

1963
static int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
1964 1965 1966
{
	int i;

1967 1968
	for (i = 0; i < a->data_nr; i++) {
		if (a->data[i].percent_sum == b->data[i].percent_sum)
1969
			continue;
1970
		return a->data[i].percent_sum > b->data[i].percent_sum;
1971 1972 1973 1974 1975
	}

	return 0;
}

1976
static void __resort_source_line(struct rb_root *root, struct annotation_line *al)
1977
{
1978
	struct annotation_line *iter;
1979 1980 1981 1982 1983
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;

	while (*p != NULL) {
		parent = *p;
1984
		iter = rb_entry(parent, struct annotation_line, rb_node);
1985

1986
		if (cmp_source_line(al, iter))
1987 1988 1989 1990 1991
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

1992 1993
	rb_link_node(&al->rb_node, parent, p);
	rb_insert_color(&al->rb_node, root);
1994 1995
}

1996 1997
static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
{
1998
	struct annotation_line *al;
1999 2000 2001 2002 2003 2004
	struct rb_node *node;

	node = rb_first(src_root);
	while (node) {
		struct rb_node *next;

2005
		al = rb_entry(node, struct annotation_line, rb_node);
2006 2007 2008
		next = rb_next(node);
		rb_erase(node, src_root);

2009
		__resort_source_line(dest_root, al);
2010 2011 2012 2013
		node = next;
	}
}

2014 2015
static void print_summary(struct rb_root *root, const char *filename)
{
2016
	struct annotation_line *al;
2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028
	struct rb_node *node;

	printf("\nSorted summary for file %s\n", filename);
	printf("----------------------------------------------\n\n");

	if (RB_EMPTY_ROOT(root)) {
		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
		return;
	}

	node = rb_first(root);
	while (node) {
2029
		double percent, percent_max = 0.0;
2030 2031
		const char *color;
		char *path;
2032
		int i;
2033

2034
		al = rb_entry(node, struct annotation_line, rb_node);
2035 2036
		for (i = 0; i < al->data_nr; i++) {
			percent = al->data[i].percent_sum;
2037 2038 2039 2040 2041 2042 2043
			color = get_percent_color(percent);
			color_fprintf(stdout, color, " %7.2f", percent);

			if (percent > percent_max)
				percent_max = percent;
		}

2044
		path = al->path;
2045
		color = get_percent_color(percent_max);
2046
		color_fprintf(stdout, color, " %s\n", path);
2047 2048 2049 2050 2051

		node = rb_next(node);
	}
}

2052
static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
2053 2054
{
	struct annotation *notes = symbol__annotation(sym);
2055
	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
2056
	u64 len = symbol__size(sym), offset;
2057 2058

	for (offset = 0; offset < len; ++offset)
2059
		if (h->addr[offset].nr_samples != 0)
2060
			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
2061
			       sym->start + offset, h->addr[offset].nr_samples);
2062
	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->nr_samples", h->nr_samples);
2063 2064
}

2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077
static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start)
{
	char bf[32];
	struct annotation_line *line;

	list_for_each_entry_reverse(line, lines, node) {
		if (line->offset != -1)
			return scnprintf(bf, sizeof(bf), "%" PRIx64, start + line->offset);
	}

	return 0;
}

2078
int symbol__annotate_printf(struct symbol *sym, struct map *map,
2079 2080
			    struct perf_evsel *evsel,
			    struct annotation_options *opts)
2081 2082
{
	struct dso *dso = map->dso;
2083 2084
	char *filename;
	const char *d_filename;
2085
	const char *evsel_name = perf_evsel__name(evsel);
2086
	struct annotation *notes = symbol__annotation(sym);
2087
	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
2088
	struct annotation_line *pos, *queue = NULL;
2089
	u64 start = map__rip_2objdump(map, sym->start);
2090
	int printed = 2, queue_len = 0, addr_fmt_width;
2091
	int more = 0;
2092
	bool context = opts->context;
2093
	u64 len;
2094
	int width = symbol_conf.show_total_period ? 12 : 8;
2095
	int graph_dotted_len;
2096
	char buf[512];
2097

2098 2099 2100 2101
	filename = strdup(dso->long_name);
	if (!filename)
		return -ENOMEM;

2102
	if (opts->full_path)
2103 2104 2105 2106
		d_filename = filename;
	else
		d_filename = basename(filename);

2107
	len = symbol__size(sym);
2108

2109
	if (perf_evsel__is_group_event(evsel)) {
2110
		width *= evsel->nr_members;
2111 2112 2113
		perf_evsel__group_desc(evsel, buf, sizeof(buf));
		evsel_name = buf;
	}
2114

2115 2116
	graph_dotted_len = printf(" %-*.*s|	Source code & Disassembly of %s for %s (%" PRIu64 " samples, "
				  "percent: %s)\n",
2117 2118
				  width, width, symbol_conf.show_total_period ? "Period" :
				  symbol_conf.show_nr_samples ? "Samples" : "Percent",
2119 2120
				  d_filename, evsel_name, h->nr_samples,
				  percent_type_str(opts->percent_type));
2121

2122
	printf("%-*.*s----\n",
2123
	       graph_dotted_len, graph_dotted_len, graph_dotted_line);
2124

2125
	if (verbose > 0)
2126
		symbol__annotate_hits(sym, evsel);
2127

2128 2129
	addr_fmt_width = annotated_source__addr_fmt_width(&notes->src->source, start);

2130 2131 2132
	list_for_each_entry(pos, &notes->src->source, node) {
		int err;

2133 2134 2135 2136 2137
		if (context && queue == NULL) {
			queue = pos;
			queue_len = 0;
		}

2138
		err = annotation_line__print(pos, sym, start, evsel, len,
2139
					     opts->min_pcnt, printed, opts->max_lines,
2140
					     queue, addr_fmt_width, opts->percent_type);
2141 2142

		switch (err) {
2143 2144
		case 0:
			++printed;
2145 2146 2147 2148 2149
			if (context) {
				printed += queue_len;
				queue = NULL;
				queue_len = 0;
			}
2150 2151 2152 2153
			break;
		case 1:
			/* filtered by max_lines */
			++more;
2154
			break;
2155 2156
		case -1:
		default:
2157 2158 2159 2160 2161 2162 2163
			/*
			 * Filtered by min_pcnt or non IP lines when
			 * context != 0
			 */
			if (!context)
				break;
			if (queue_len == context)
2164
				queue = list_entry(queue->node.next, typeof(*queue), node);
2165 2166
			else
				++queue_len;
2167 2168 2169 2170
			break;
		}
	}

2171 2172
	free(filename);

2173 2174
	return more;
}
2175

2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216
static void FILE__set_percent_color(void *fp __maybe_unused,
				    double percent __maybe_unused,
				    bool current __maybe_unused)
{
}

static int FILE__set_jumps_percent_color(void *fp __maybe_unused,
					 int nr __maybe_unused, bool current __maybe_unused)
{
	return 0;
}

static int FILE__set_color(void *fp __maybe_unused, int color __maybe_unused)
{
	return 0;
}

static void FILE__printf(void *fp, const char *fmt, ...)
{
	va_list args;

	va_start(args, fmt);
	vfprintf(fp, fmt, args);
	va_end(args);
}

static void FILE__write_graph(void *fp, int graph)
{
	const char *s;
	switch (graph) {

	case DARROW_CHAR: s = "↓"; break;
	case UARROW_CHAR: s = "↑"; break;
	case LARROW_CHAR: s = "←"; break;
	case RARROW_CHAR: s = "→"; break;
	default:		s = "?"; break;
	}

	fputs(s, fp);
}

2217 2218
static int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp,
				     struct annotation_options *opts)
2219 2220
{
	struct annotation *notes = symbol__annotation(sym);
2221
	struct annotation_write_ops wops = {
2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234
		.first_line		 = true,
		.obj			 = fp,
		.set_color		 = FILE__set_color,
		.set_percent_color	 = FILE__set_percent_color,
		.set_jumps_percent_color = FILE__set_jumps_percent_color,
		.printf			 = FILE__printf,
		.write_graph		 = FILE__write_graph,
	};
	struct annotation_line *al;

	list_for_each_entry(al, &notes->src->source, node) {
		if (annotation_line__filter(al, notes))
			continue;
2235
		annotation_line__write(al, notes, &wops, opts);
2236
		fputc('\n', fp);
2237
		wops.first_line = false;
2238 2239 2240 2241 2242
	}

	return 0;
}

2243 2244
int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel,
				struct annotation_options *opts)
2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265
{
	const char *ev_name = perf_evsel__name(evsel);
	char buf[1024];
	char *filename;
	int err = -1;
	FILE *fp;

	if (asprintf(&filename, "%s.annotation", ms->sym->name) < 0)
		return -1;

	fp = fopen(filename, "w");
	if (fp == NULL)
		goto out_free_filename;

	if (perf_evsel__is_group_event(evsel)) {
		perf_evsel__group_desc(evsel, buf, sizeof(buf));
		ev_name = buf;
	}

	fprintf(fp, "%s() %s\nEvent: %s\n\n",
		ms->sym->name, ms->map->dso->long_name, ev_name);
2266
	symbol__annotate_fprintf2(ms->sym, fp, opts);
2267 2268 2269 2270 2271 2272 2273 2274

	fclose(fp);
	err = 0;
out_free_filename:
	free(filename);
	return err;
}

2275 2276 2277 2278 2279
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);

2280
	memset(h, 0, notes->src->sizeof_sym_hist);
2281 2282
}

2283
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
2284 2285 2286
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);
2287
	int len = symbol__size(sym), offset;
2288

2289
	h->nr_samples = 0;
2290
	for (offset = 0; offset < len; ++offset) {
2291
		h->addr[offset].nr_samples = h->addr[offset].nr_samples * 7 / 8;
2292
		h->nr_samples += h->addr[offset].nr_samples;
2293 2294 2295
	}
}

2296
void annotated_source__purge(struct annotated_source *as)
2297
{
2298
	struct annotation_line *al, *n;
2299

2300 2301 2302
	list_for_each_entry_safe(al, n, &as->source, node) {
		list_del(&al->node);
		disasm_line__free(disasm_line(al));
2303 2304 2305
	}
}

2306 2307 2308 2309
static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
{
	size_t printed;

2310 2311
	if (dl->al.offset == -1)
		return fprintf(fp, "%s\n", dl->al.line);
2312

2313
	printed = fprintf(fp, "%#" PRIx64 " %s", dl->al.offset, dl->ins.name);
2314

2315
	if (dl->ops.raw[0] != '\0') {
2316
		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
2317
				   dl->ops.raw);
2318 2319 2320 2321 2322 2323 2324 2325 2326 2327
	}

	return printed + fprintf(fp, "\n");
}

size_t disasm__fprintf(struct list_head *head, FILE *fp)
{
	struct disasm_line *pos;
	size_t printed = 0;

2328
	list_for_each_entry(pos, head, al.node)
2329 2330 2331 2332 2333
		printed += disasm_line__fprintf(pos, fp);

	return printed;
}

2334
bool disasm_line__is_valid_local_jump(struct disasm_line *dl, struct symbol *sym)
2335 2336
{
	if (!dl || !dl->ins.ops || !ins__is_jump(&dl->ins) ||
2337
	    !disasm_line__has_local_offset(dl) || dl->ops.target.offset < 0 ||
2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2356 2357
	    dl->ops.target.offset >= (s64)symbol__size(sym))
		return false;

	return true;
}

void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym)
{
	u64 offset, size = symbol__size(sym);

	/* PLT symbols contain external offsets */
	if (strstr(sym->name, "@plt"))
		return;

	for (offset = 0; offset < size; ++offset) {
		struct annotation_line *al = notes->offsets[offset];
		struct disasm_line *dl;

		dl = disasm_line(al);

2358
		if (!disasm_line__is_valid_local_jump(dl, sym))
2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376
			continue;

		al = notes->offsets[dl->ops.target.offset];

		/*
		 * FIXME: Oops, no jump target? Buggy disassembler? Or do we
		 * have to adjust to the previous offset?
		 */
		if (al == NULL)
			continue;

		if (++al->jump_sources > notes->max_jump_sources)
			notes->max_jump_sources = al->jump_sources;

		++notes->nr_jumps;
	}
}

2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404
void annotation__set_offsets(struct annotation *notes, s64 size)
{
	struct annotation_line *al;

	notes->max_line_len = 0;

	list_for_each_entry(al, &notes->src->source, node) {
		size_t line_len = strlen(al->line);

		if (notes->max_line_len < line_len)
			notes->max_line_len = line_len;
		al->idx = notes->nr_entries++;
		if (al->offset != -1) {
			al->idx_asm = notes->nr_asm_entries++;
			/*
			 * FIXME: short term bandaid to cope with assembly
			 * routines that comes with labels in the same column
			 * as the address in objdump, sigh.
			 *
			 * E.g. copy_user_generic_unrolled
 			 */
			if (al->offset < size)
				notes->offsets[al->offset] = al;
		} else
			al->idx_asm = -1;
	}
}

2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421
static inline int width_jumps(int n)
{
	if (n >= 100)
		return 5;
	if (n / 10)
		return 2;
	return 1;
}

void annotation__init_column_widths(struct annotation *notes, struct symbol *sym)
{
	notes->widths.addr = notes->widths.target =
		notes->widths.min_addr = hex_width(symbol__size(sym));
	notes->widths.max_addr = hex_width(sym->end);
	notes->widths.jumps = width_jumps(notes->max_jump_sources);
}

2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434
void annotation__update_column_widths(struct annotation *notes)
{
	if (notes->options->use_offset)
		notes->widths.target = notes->widths.min_addr;
	else
		notes->widths.target = notes->widths.max_addr;

	notes->widths.addr = notes->widths.target;

	if (notes->options->show_nr_jumps)
		notes->widths.addr += notes->widths.jumps + 1;
}

2435
static void annotation__calc_lines(struct annotation *notes, struct map *map,
2436 2437
				   struct rb_root *root,
				   struct annotation_options *opts)
2438 2439 2440 2441 2442 2443 2444 2445
{
	struct annotation_line *al;
	struct rb_root tmp_root = RB_ROOT;

	list_for_each_entry(al, &notes->src->source, node) {
		double percent_max = 0.0;
		int i;

2446
		for (i = 0; i < al->data_nr; i++) {
2447
			double percent;
2448

2449
			percent = annotation_data__percent(&al->data[i],
2450
							   opts->percent_type);
2451

2452 2453
			if (percent > percent_max)
				percent_max = percent;
2454 2455 2456 2457 2458
		}

		if (percent_max <= 0.5)
			continue;

2459 2460
		al->path = get_srcline(map->dso, notes->start + al->offset, NULL,
				       false, true, notes->start + al->offset);
2461
		insert_source_line(&tmp_root, al, opts);
2462 2463 2464 2465 2466 2467
	}

	resort_source_line(root, &tmp_root);
}

static void symbol__calc_lines(struct symbol *sym, struct map *map,
2468 2469
			       struct rb_root *root,
			       struct annotation_options *opts)
2470 2471 2472
{
	struct annotation *notes = symbol__annotation(sym);

2473
	annotation__calc_lines(notes, map, root, opts);
2474 2475
}

2476
int symbol__tty_annotate2(struct symbol *sym, struct map *map,
2477 2478
			  struct perf_evsel *evsel,
			  struct annotation_options *opts)
2479 2480 2481
{
	struct dso *dso = map->dso;
	struct rb_root source_line = RB_ROOT;
2482
	struct hists *hists = evsel__hists(evsel);
2483
	char buf[1024];
2484

2485
	if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0)
2486 2487
		return -1;

2488 2489
	if (opts->print_lines) {
		srcline_full_filename = opts->full_path;
2490
		symbol__calc_lines(sym, map, &source_line, opts);
2491 2492 2493
		print_summary(&source_line, dso->long_name);
	}

2494
	hists__scnprintf_title(hists, buf, sizeof(buf));
2495 2496
	fprintf(stdout, "%s, [percent: %s]\n%s() %s\n",
		buf, percent_type_str(opts->percent_type), sym->name, dso->long_name);
2497
	symbol__annotate_fprintf2(sym, stdout, opts);
2498 2499 2500 2501 2502 2503

	annotated_source__purge(symbol__annotation(sym)->src);

	return 0;
}

2504
int symbol__tty_annotate(struct symbol *sym, struct map *map,
2505 2506
			 struct perf_evsel *evsel,
			 struct annotation_options *opts)
2507 2508 2509 2510
{
	struct dso *dso = map->dso;
	struct rb_root source_line = RB_ROOT;

2511
	if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0)
2512 2513
		return -1;

2514 2515
	symbol__calc_percent(sym, evsel);

2516 2517
	if (opts->print_lines) {
		srcline_full_filename = opts->full_path;
2518
		symbol__calc_lines(sym, map, &source_line, opts);
2519
		print_summary(&source_line, dso->long_name);
2520 2521
	}

2522
	symbol__annotate_printf(sym, map, evsel, opts);
2523

2524
	annotated_source__purge(symbol__annotation(sym)->src);
2525

2526 2527
	return 0;
}
2528

2529 2530
bool ui__has_annotation(void)
{
2531
	return use_browser == 1 && perf_hpp_list.sym;
2532
}
2533

2534

2535
static double annotation_line__max_percent(struct annotation_line *al,
2536 2537
					   struct annotation *notes,
					   unsigned int percent_type)
2538 2539 2540 2541 2542
{
	double percent_max = 0.0;
	int i;

	for (i = 0; i < notes->nr_events; i++) {
2543 2544 2545
		double percent;

		percent = annotation_data__percent(&al->data[i],
2546
						   percent_type);
2547 2548 2549

		if (percent > percent_max)
			percent_max = percent;
2550 2551 2552 2553 2554
	}

	return percent_max;
}

2555 2556 2557 2558 2559 2560 2561
static void disasm_line__write(struct disasm_line *dl, struct annotation *notes,
			       void *obj, char *bf, size_t size,
			       void (*obj__printf)(void *obj, const char *fmt, ...),
			       void (*obj__write_graph)(void *obj, int graph))
{
	if (dl->ins.ops && dl->ins.ops->scnprintf) {
		if (ins__is_jump(&dl->ins)) {
2562
			bool fwd;
2563

2564 2565 2566
			if (dl->ops.target.outside)
				goto call_like;
			fwd = dl->ops.target.offset > dl->al.offset;
2567 2568 2569
			obj__write_graph(obj, fwd ? DARROW_CHAR : UARROW_CHAR);
			obj__printf(obj, " ");
		} else if (ins__is_call(&dl->ins)) {
2570
call_like:
2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585
			obj__write_graph(obj, RARROW_CHAR);
			obj__printf(obj, " ");
		} else if (ins__is_ret(&dl->ins)) {
			obj__write_graph(obj, LARROW_CHAR);
			obj__printf(obj, " ");
		} else {
			obj__printf(obj, "  ");
		}
	} else {
		obj__printf(obj, "  ");
	}

	disasm_line__scnprintf(dl, bf, size, !notes->options->use_offset);
}

2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601
static void ipc_coverage_string(char *bf, int size, struct annotation *notes)
{
	double ipc = 0.0, coverage = 0.0;

	if (notes->hit_cycles)
		ipc = notes->hit_insn / ((double)notes->hit_cycles);

	if (notes->total_insn) {
		coverage = notes->cover_insn * 100.0 /
			((double)notes->total_insn);
	}

	scnprintf(bf, size, "(Average IPC: %.2f, IPC Coverage: %.1f%%)",
		  ipc, coverage);
}

2602 2603
static void __annotation_line__write(struct annotation_line *al, struct annotation *notes,
				     bool first_line, bool current_entry, bool change_color, int width,
2604
				     void *obj, unsigned int percent_type,
2605 2606 2607 2608 2609 2610
				     int  (*obj__set_color)(void *obj, int color),
				     void (*obj__set_percent_color)(void *obj, double percent, bool current),
				     int  (*obj__set_jumps_percent_color)(void *obj, int nr, bool current),
				     void (*obj__printf)(void *obj, const char *fmt, ...),
				     void (*obj__write_graph)(void *obj, int graph))

2611
{
2612
	double percent_max = annotation_line__max_percent(al, notes, percent_type);
2613 2614
	int pcnt_width = annotation__pcnt_width(notes),
	    cycles_width = annotation__cycles_width(notes);
2615
	bool show_title = false;
2616 2617
	char bf[256];
	int printed;
2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630

	if (first_line && (al->offset == -1 || percent_max == 0.0)) {
		if (notes->have_cycles) {
			if (al->ipc == 0.0 && al->cycles == 0)
				show_title = true;
		} else
			show_title = true;
	}

	if (al->offset != -1 && percent_max != 0.0) {
		int i;

		for (i = 0; i < notes->nr_events; i++) {
2631 2632
			double percent;

2633
			percent = annotation_data__percent(&al->data[i], percent_type);
2634 2635

			obj__set_percent_color(obj, percent, current_entry);
2636
			if (notes->options->show_total_period) {
2637
				obj__printf(obj, "%11" PRIu64 " ", al->data[i].he.period);
2638 2639
			} else if (notes->options->show_nr_samples) {
				obj__printf(obj, "%6" PRIu64 " ",
2640
						   al->data[i].he.nr_samples);
2641
			} else {
2642
				obj__printf(obj, "%6.2f ", percent);
2643 2644 2645 2646 2647 2648
			}
		}
	} else {
		obj__set_percent_color(obj, 0, current_entry);

		if (!show_title)
2649
			obj__printf(obj, "%-*s", pcnt_width, " ");
2650
		else {
2651
			obj__printf(obj, "%-*s", pcnt_width,
2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664
					   notes->options->show_total_period ? "Period" :
					   notes->options->show_nr_samples ? "Samples" : "Percent");
		}
	}

	if (notes->have_cycles) {
		if (al->ipc)
			obj__printf(obj, "%*.2f ", ANNOTATION__IPC_WIDTH - 1, al->ipc);
		else if (!show_title)
			obj__printf(obj, "%*s", ANNOTATION__IPC_WIDTH, " ");
		else
			obj__printf(obj, "%*s ", ANNOTATION__IPC_WIDTH - 1, "IPC");

2665 2666 2667
		if (!notes->options->show_minmax_cycle) {
			if (al->cycles)
				obj__printf(obj, "%*" PRIu64 " ",
2668
					   ANNOTATION__CYCLES_WIDTH - 1, al->cycles);
2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696
			else if (!show_title)
				obj__printf(obj, "%*s",
					    ANNOTATION__CYCLES_WIDTH, " ");
			else
				obj__printf(obj, "%*s ",
					    ANNOTATION__CYCLES_WIDTH - 1,
					    "Cycle");
		} else {
			if (al->cycles) {
				char str[32];

				scnprintf(str, sizeof(str),
					"%" PRIu64 "(%" PRIu64 "/%" PRIu64 ")",
					al->cycles, al->cycles_min,
					al->cycles_max);

				obj__printf(obj, "%*s ",
					    ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
					    str);
			} else if (!show_title)
				obj__printf(obj, "%*s",
					    ANNOTATION__MINMAX_CYCLES_WIDTH,
					    " ");
			else
				obj__printf(obj, "%*s ",
					    ANNOTATION__MINMAX_CYCLES_WIDTH - 1,
					    "Cycle(min/max)");
		}
2697 2698 2699 2700 2701

		if (show_title && !*al->line) {
			ipc_coverage_string(bf, sizeof(bf), notes);
			obj__printf(obj, "%*s", ANNOTATION__AVG_IPC_WIDTH, bf);
		}
2702 2703 2704
	}

	obj__printf(obj, " ");
2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724

	if (!*al->line)
		obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, " ");
	else if (al->offset == -1) {
		if (al->line_nr && notes->options->show_linenr)
			printed = scnprintf(bf, sizeof(bf), "%-*d ", notes->widths.addr + 1, al->line_nr);
		else
			printed = scnprintf(bf, sizeof(bf), "%-*s  ", notes->widths.addr, " ");
		obj__printf(obj, bf);
		obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line);
	} else {
		u64 addr = al->offset;
		int color = -1;

		if (!notes->options->use_offset)
			addr += notes->start;

		if (!notes->options->use_offset) {
			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ": ", addr);
		} else {
2725 2726
			if (al->jump_sources &&
			    notes->options->offset_level >= ANNOTATION__OFFSET_JUMP_TARGETS) {
2727 2728 2729 2730 2731 2732 2733 2734 2735 2736
				if (notes->options->show_nr_jumps) {
					int prev;
					printed = scnprintf(bf, sizeof(bf), "%*d ",
							    notes->widths.jumps,
							    al->jump_sources);
					prev = obj__set_jumps_percent_color(obj, al->jump_sources,
									    current_entry);
					obj__printf(obj, bf);
					obj__set_color(obj, prev);
				}
2737
print_addr:
2738 2739
				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ": ",
						    notes->widths.target, addr);
2740 2741 2742 2743 2744
			} else if (ins__is_call(&disasm_line(al)->ins) &&
				   notes->options->offset_level >= ANNOTATION__OFFSET_CALL) {
				goto print_addr;
			} else if (notes->options->offset_level == ANNOTATION__MAX_OFFSET_LEVEL) {
				goto print_addr;
2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761
			} else {
				printed = scnprintf(bf, sizeof(bf), "%-*s  ",
						    notes->widths.addr, " ");
			}
		}

		if (change_color)
			color = obj__set_color(obj, HE_COLORSET_ADDR);
		obj__printf(obj, bf);
		if (change_color)
			obj__set_color(obj, color);

		disasm_line__write(disasm_line(al), notes, obj, bf, sizeof(bf), obj__printf, obj__write_graph);

		obj__printf(obj, "%-*s", width - pcnt_width - cycles_width - 3 - printed, bf);
	}

2762 2763
}

2764
void annotation_line__write(struct annotation_line *al, struct annotation *notes,
2765 2766
			    struct annotation_write_ops *wops,
			    struct annotation_options *opts)
2767
{
2768 2769 2770 2771 2772 2773
	__annotation_line__write(al, notes, wops->first_line, wops->current_entry,
				 wops->change_color, wops->width, wops->obj,
				 opts->percent_type,
				 wops->set_color, wops->set_percent_color,
				 wops->set_jumps_percent_color, wops->printf,
				 wops->write_graph);
2774 2775
}

2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789
int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel,
		      struct annotation_options *options, struct arch **parch)
{
	struct annotation *notes = symbol__annotation(sym);
	size_t size = symbol__size(sym);
	int nr_pcnt = 1, err;

	notes->offsets = zalloc(size * sizeof(struct annotation_line *));
	if (notes->offsets == NULL)
		return -1;

	if (perf_evsel__is_group_event(evsel))
		nr_pcnt = evsel->nr_members;

2790
	err = symbol__annotate(sym, map, evsel, 0, options, parch);
2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806
	if (err)
		goto out_free_offsets;

	notes->options = options;

	symbol__calc_percent(sym, evsel);

	notes->start = map__rip_2objdump(map, sym->start);

	annotation__set_offsets(notes, size);
	annotation__mark_jump_targets(notes, sym);
	annotation__compute_ipc(notes, size);
	annotation__init_column_widths(notes, sym);
	notes->nr_events = nr_pcnt;

	annotation__update_column_widths(notes);
2807
	sym->annotate2 = true;
2808 2809 2810 2811 2812 2813 2814

	return 0;

out_free_offsets:
	zfree(&notes->offsets);
	return -1;
}
2815 2816 2817 2818 2819 2820 2821 2822 2823

#define ANNOTATION__CFG(n) \
	{ .name = #n, .value = &annotation__default_options.n, }

/*
 * Keep the entries sorted, they are bsearch'ed
 */
static struct annotation_config {
	const char *name;
2824
	void *value;
2825 2826 2827
} annotation__configs[] = {
	ANNOTATION__CFG(hide_src_code),
	ANNOTATION__CFG(jump_arrows),
2828
	ANNOTATION__CFG(offset_level),
2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859
	ANNOTATION__CFG(show_linenr),
	ANNOTATION__CFG(show_nr_jumps),
	ANNOTATION__CFG(show_nr_samples),
	ANNOTATION__CFG(show_total_period),
	ANNOTATION__CFG(use_offset),
};

#undef ANNOTATION__CFG

static int annotation_config__cmp(const void *name, const void *cfgp)
{
	const struct annotation_config *cfg = cfgp;

	return strcmp(name, cfg->name);
}

static int annotation__config(const char *var, const char *value,
			    void *data __maybe_unused)
{
	struct annotation_config *cfg;
	const char *name;

	if (!strstarts(var, "annotate."))
		return 0;

	name = var + 9;
	cfg = bsearch(name, annotation__configs, ARRAY_SIZE(annotation__configs),
		      sizeof(struct annotation_config), annotation_config__cmp);

	if (cfg == NULL)
		pr_debug("%s variable unknown, ignoring...", var);
2860 2861 2862 2863 2864 2865 2866 2867 2868 2869
	else if (strcmp(var, "annotate.offset_level") == 0) {
		perf_config_int(cfg->value, name, value);

		if (*(int *)cfg->value > ANNOTATION__MAX_OFFSET_LEVEL)
			*(int *)cfg->value = ANNOTATION__MAX_OFFSET_LEVEL;
		else if (*(int *)cfg->value < ANNOTATION__MIN_OFFSET_LEVEL)
			*(int *)cfg->value = ANNOTATION__MIN_OFFSET_LEVEL;
	} else {
		*(bool *)cfg->value = perf_config_bool(name, value);
	}
2870 2871 2872 2873 2874 2875 2876 2877 2878 2879
	return 0;
}

void annotation_config__init(void)
{
	perf_config(annotation__config, NULL);

	annotation__default_options.show_total_period = symbol_conf.show_total_period;
	annotation__default_options.show_nr_samples   = symbol_conf.show_nr_samples;
}
2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931

static unsigned int parse_percent_type(char *str1, char *str2)
{
	unsigned int type = (unsigned int) -1;

	if (!strcmp("period", str1)) {
		if (!strcmp("local", str2))
			type = PERCENT_PERIOD_LOCAL;
		else if (!strcmp("global", str2))
			type = PERCENT_PERIOD_GLOBAL;
	}

	if (!strcmp("hits", str1)) {
		if (!strcmp("local", str2))
			type = PERCENT_HITS_LOCAL;
		else if (!strcmp("global", str2))
			type = PERCENT_HITS_GLOBAL;
	}

	return type;
}

int annotate_parse_percent_type(const struct option *opt, const char *_str,
				int unset __maybe_unused)
{
	struct annotation_options *opts = opt->value;
	unsigned int type;
	char *str1, *str2;
	int err = -1;

	str1 = strdup(_str);
	if (!str1)
		return -ENOMEM;

	str2 = strchr(str1, '-');
	if (!str2)
		goto out;

	*str2++ = 0;

	type = parse_percent_type(str1, str2);
	if (type == (unsigned int) -1)
		type = parse_percent_type(str2, str1);
	if (type != (unsigned int) -1) {
		opts->percent_type = type;
		err = 0;
	}

out:
	free(str1);
	return err;
}