annotate.c 18.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/*
 * 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)
 */

#include "util.h"
#include "build-id.h"
#include "color.h"
#include "cache.h"
#include "symbol.h"
#include "debug.h"
#include "annotate.h"
17
#include <pthread.h>
18

19 20
const char 	*disassembler_style;

21
static int call__parse(struct ins_operands *ops)
22
{
23
	ops->target = strtoull(ops->raw, NULL, 16);
24 25 26 27
	return 0;
}

static struct ins_ops call_ops = {
28
	.parse = call__parse,
29 30 31 32 33 34 35
};

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

36
static int jump__parse(struct ins_operands *ops)
37
{
38
	const char *s = strchr(ops->raw, '+');
39 40 41 42

	if (s++ == NULL)
		return -1;

43
	ops->target = strtoll(s, NULL, 16);
44 45 46
	return 0;
}

47 48
static int jump__scnprintf(struct ins *ins, char *bf, size_t size,
			   struct ins_operands *ops, bool addrs)
49
{
50 51
	if (addrs)
		return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw);
52

53
	return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target);
54 55
}

56
static struct ins_ops jump_ops = {
57 58
	.parse	   = jump__parse,
	.scnprintf = jump__scnprintf,
59 60 61 62 63 64 65 66 67 68 69
};

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

/*
 * Must be sorted by name!
 */
static struct ins instructions[] = {
70 71
	{ .name = "call",  .ops  = &call_ops, },
	{ .name = "callq", .ops  = &call_ops, },
72
	{ .name = "ja",	   .ops  = &jump_ops, },
73 74 75 76 77
	{ .name = "jae",   .ops  = &jump_ops, },
	{ .name = "jb",	   .ops  = &jump_ops, },
	{ .name = "jbe",   .ops  = &jump_ops, },
	{ .name = "jc",	   .ops  = &jump_ops, },
	{ .name = "jcxz",  .ops  = &jump_ops, },
78
	{ .name = "je",	   .ops  = &jump_ops, },
79 80 81 82 83
	{ .name = "jecxz", .ops  = &jump_ops, },
	{ .name = "jg",	   .ops  = &jump_ops, },
	{ .name = "jge",   .ops  = &jump_ops, },
	{ .name = "jl",    .ops  = &jump_ops, },
	{ .name = "jle",   .ops  = &jump_ops, },
84 85
	{ .name = "jmp",   .ops  = &jump_ops, },
	{ .name = "jmpq",  .ops  = &jump_ops, },
86 87 88 89 90
	{ .name = "jna",   .ops  = &jump_ops, },
	{ .name = "jnae",  .ops  = &jump_ops, },
	{ .name = "jnb",   .ops  = &jump_ops, },
	{ .name = "jnbe",  .ops  = &jump_ops, },
	{ .name = "jnc",   .ops  = &jump_ops, },
91
	{ .name = "jne",   .ops  = &jump_ops, },
92 93 94 95 96 97 98 99 100 101 102 103 104
	{ .name = "jng",   .ops  = &jump_ops, },
	{ .name = "jnge",  .ops  = &jump_ops, },
	{ .name = "jnl",   .ops  = &jump_ops, },
	{ .name = "jnle",  .ops  = &jump_ops, },
	{ .name = "jno",   .ops  = &jump_ops, },
	{ .name = "jnp",   .ops  = &jump_ops, },
	{ .name = "jns",   .ops  = &jump_ops, },
	{ .name = "jnz",   .ops  = &jump_ops, },
	{ .name = "jo",	   .ops  = &jump_ops, },
	{ .name = "jp",	   .ops  = &jump_ops, },
	{ .name = "jpe",   .ops  = &jump_ops, },
	{ .name = "jpo",   .ops  = &jump_ops, },
	{ .name = "jrcxz", .ops  = &jump_ops, },
105
	{ .name = "js",	   .ops  = &jump_ops, },
106
	{ .name = "jz",	   .ops  = &jump_ops, },
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122
};

static int ins__cmp(const void *name, const void *insp)
{
	const struct ins *ins = insp;

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

static struct ins *ins__find(const char *name)
{
	const int nmemb = ARRAY_SIZE(instructions);

	return bsearch(name, instructions, nmemb, sizeof(struct ins), ins__cmp);
}

123
int symbol__annotate_init(struct map *map __used, struct symbol *sym)
124 125
{
	struct annotation *notes = symbol__annotation(sym);
126 127 128
	pthread_mutex_init(&notes->lock, NULL);
	return 0;
}
129

130
int symbol__alloc_hist(struct symbol *sym)
131 132
{
	struct annotation *notes = symbol__annotation(sym);
133
	const size_t size = symbol__size(sym);
134
	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
135

136
	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
137 138 139
	if (notes->src == NULL)
		return -1;
	notes->src->sizeof_sym_hist = sizeof_sym_hist;
140
	notes->src->nr_histograms   = symbol_conf.nr_events;
141 142
	INIT_LIST_HEAD(&notes->src->source);
	return 0;
143 144
}

145 146 147 148
void symbol__annotate_zero_histograms(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);

149 150 151 152 153
	pthread_mutex_lock(&notes->lock);
	if (notes->src != NULL)
		memset(notes->src->histograms, 0,
		       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
	pthread_mutex_unlock(&notes->lock);
154 155
}

156 157
int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
			     int evidx, u64 addr)
158
{
159
	unsigned offset;
160 161 162 163
	struct annotation *notes;
	struct sym_hist *h;

	notes = symbol__annotation(sym);
164
	if (notes->src == NULL)
165 166 167 168
		return -ENOMEM;

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

169 170
	if (addr < sym->start || addr > sym->end)
		return -ERANGE;
171

172 173
	offset = addr - sym->start;
	h = annotation__histogram(notes, evidx);
174 175 176 177
	h->sum++;
	h->addr[offset]++;

	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
178 179
		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
		  addr, addr - sym->start, evidx, h->addr[offset]);
180 181 182
	return 0;
}

183 184 185 186 187 188 189 190 191 192
static void disasm_line__init_ins(struct disasm_line *dl)
{
	dl->ins = ins__find(dl->name);

	if (dl->ins == NULL)
		return;

	if (!dl->ins->ops)
		return;

193 194
	if (dl->ins->ops->parse)
		dl->ins->ops->parse(&dl->ops);
195 196
}

197
static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
198
{
199
	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
200

201 202 203 204
	if (dl != NULL) {
		dl->offset = offset;
		dl->line = strdup(line);
		if (dl->line == NULL)
205
			goto out_delete;
206 207 208 209 210 211 212 213 214 215

		if (offset != -1) {
			char *name = dl->line, tmp;

			while (isspace(name[0]))
				++name;

			if (name[0] == '\0')
				goto out_delete;

216
			dl->ops.raw = name + 1;
217

218 219 220
			while (dl->ops.raw[0] != '\0' &&
			       !isspace(dl->ops.raw[0]))
				++dl->ops.raw;
221

222 223
			tmp = dl->ops.raw[0];
			dl->ops.raw[0] = '\0';
224 225 226 227 228
			dl->name = strdup(name);

			if (dl->name == NULL)
				goto out_free_line;

229
			dl->ops.raw[0] = tmp;
230

231 232 233 234
			if (dl->ops.raw[0] != '\0') {
				dl->ops.raw++;
				while (isspace(dl->ops.raw[0]))
					++dl->ops.raw;
235
			}
236 237

			disasm_line__init_ins(dl);
238
		}
239 240
	}

241
	return dl;
242 243 244

out_free_line:
	free(dl->line);
245
out_delete:
246
	free(dl);
247
	return NULL;
248 249
}

250
void disasm_line__free(struct disasm_line *dl)
251
{
252
	free(dl->line);
253
	free(dl->name);
254
	free(dl);
255 256
}

257
static void disasm__add(struct list_head *head, struct disasm_line *line)
258 259 260 261
{
	list_add_tail(&line->node, head);
}

262
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
263 264 265 266 267 268 269 270
{
	list_for_each_entry_continue(pos, head, node)
		if (pos->offset >= 0)
			return pos;

	return NULL;
}

271 272 273
static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 start,
		      int evidx, u64 len, int min_pcnt, int printed,
		      int max_lines, struct disasm_line *queue)
274 275 276 277
{
	static const char *prev_line;
	static const char *prev_color;

278
	if (dl->offset != -1) {
279 280 281 282 283
		const char *path = NULL;
		unsigned int hits = 0;
		double percent = 0.0;
		const char *color;
		struct annotation *notes = symbol__annotation(sym);
284
		struct source_line *src_line = notes->src->lines;
285
		struct sym_hist *h = annotation__histogram(notes, evidx);
286
		s64 offset = dl->offset;
287
		const u64 addr = start + offset;
288
		struct disasm_line *next;
289

290
		next = disasm__get_next_ip_line(&notes->src->source, dl);
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306

		while (offset < (s64)len &&
		       (next == NULL || offset < next->offset)) {
			if (src_line) {
				if (path == NULL)
					path = src_line[offset].path;
				percent += src_line[offset].percent;
			} else
				hits += h->addr[offset];

			++offset;
		}

		if (src_line == NULL && h->sum)
			percent = 100.0 * hits / h->sum;

307
		if (percent < min_pcnt)
308 309
			return -1;

310
		if (max_lines && printed >= max_lines)
311
			return 1;
312

313 314
		if (queue != NULL) {
			list_for_each_entry_from(queue, &notes->src->source, node) {
315
				if (queue == dl)
316
					break;
317
				disasm_line__print(queue, sym, start, evidx, len,
318 319 320 321
						    0, 0, 1, NULL);
			}
		}

322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
		color = get_percent_color(percent);

		/*
		 * 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
		 */
		if (path) {
			if (!prev_line || strcmp(prev_line, path)
				       || color != prev_color) {
				color_fprintf(stdout, color, " %s", path);
				prev_line = path;
				prev_color = color;
			}
		}

		color_fprintf(stdout, color, " %7.2f", percent);
		printf(" :	");
340
		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
341
		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
342
	} else if (max_lines && printed >= max_lines)
343 344
		return 1;
	else {
345 346 347
		if (queue)
			return -1;

348
		if (!*dl->line)
349 350
			printf("         :\n");
		else
351
			printf("         :	%s\n", dl->line);
352
	}
353 354

	return 0;
355 356
}

357 358
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
				      FILE *file, size_t privsize)
359
{
360
	struct annotation *notes = symbol__annotation(sym);
361
	struct disasm_line *dl;
362
	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379
	size_t line_len;
	s64 line_ip, offset = -1;

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

	if (!line)
		return -1;

	while (line_len != 0 && isspace(line[line_len - 1]))
		line[--line_len] = '\0';

	c = strchr(line, '\n');
	if (c)
		*c = 0;

	line_ip = -1;
N
Namhyung Kim 已提交
380
	parsed_line = line;
381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407

	/*
	 * Strip leading spaces:
	 */
	tmp = line;
	while (*tmp) {
		if (*tmp != ' ')
			break;
		tmp++;
	}

	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;
		if (offset < 0 || (u64)line_ip > end)
			offset = -1;
408 409
		else
			parsed_line = tmp2 + 1;
N
Namhyung Kim 已提交
410
	}
411

412
	dl = disasm_line__new(offset, parsed_line, privsize);
413 414
	free(line);

415
	if (dl == NULL)
416
		return -1;
417

418
	disasm__add(&notes->src->source, dl);
419 420 421 422

	return 0;
}

423
int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460
{
	struct dso *dso = map->dso;
	char *filename = dso__build_id_filename(dso, NULL, 0);
	bool free_filename = true;
	char command[PATH_MAX * 2];
	FILE *file;
	int err = 0;
	char symfs_filename[PATH_MAX];

	if (filename) {
		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
			 symbol_conf.symfs, filename);
	}

	if (filename == NULL) {
		if (dso->has_build_id) {
			pr_err("Can't annotate %s: not enough memory\n",
			       sym->name);
			return -ENOMEM;
		}
		goto fallback;
	} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
		   strstr(command, "[kernel.kallsyms]") ||
		   access(symfs_filename, R_OK)) {
		free(filename);
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.
		 */
		filename = dso->long_name;
		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
			 symbol_conf.symfs, filename);
		free_filename = false;
	}

461
	if (dso->symtab_type == SYMTAB__KALLSYMS) {
462 463 464
		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
		char *build_id_msg = NULL;

465 466
		if (dso->annotate_warned)
			goto out_free_filename;
467 468 469 470 471 472

		if (dso->has_build_id) {
			build_id__sprintf(dso->build_id,
					  sizeof(dso->build_id), bf + 15);
			build_id_msg = bf;
		}
473 474
		err = -ENOENT;
		dso->annotate_warned = 1;
475 476 477 478 479
		pr_err("Can't annotate %s:\n\n"
		       "No vmlinux file%s\nwas found in the path.\n\n"
		       "Please use:\n\n"
		       "  perf buildid-cache -av vmlinux\n\n"
		       "or:\n\n"
480
		       "  --vmlinux vmlinux\n",
481
		       sym->name, build_id_msg ?: "");
482 483 484 485 486 487 488 489 490 491 492
		goto out_free_filename;
	}

	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
		 filename, sym->name, map->unmap_ip(map, sym->start),
		 map->unmap_ip(map, sym->end));

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

	snprintf(command, sizeof(command),
493
		 "objdump %s%s --start-address=0x%016" PRIx64
494 495
		 " --stop-address=0x%016" PRIx64
		 " -d %s %s -C %s|grep -v %s|expand",
496 497
		 disassembler_style ? "-M " : "",
		 disassembler_style ? disassembler_style : "",
498
		 map__rip_2objdump(map, sym->start),
I
Ingo Molnar 已提交
499
		 map__rip_2objdump(map, sym->end+1),
500 501
		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
		 symbol_conf.annotate_src ? "-S" : "",
502 503 504 505 506 507 508 509 510
		 symfs_filename, filename);

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

	file = popen(command, "r");
	if (!file)
		goto out_free_filename;

	while (!feof(file))
511
		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543
			break;

	pclose(file);
out_free_filename:
	if (free_filename)
		free(filename);
	return err;
}

static void insert_source_line(struct rb_root *root, struct source_line *src_line)
{
	struct source_line *iter;
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct source_line, node);

		if (src_line->percent > iter->percent)
			p = &(*p)->rb_left;
		else
			p = &(*p)->rb_right;
	}

	rb_link_node(&src_line->node, parent, p);
	rb_insert_color(&src_line->node, root);
}

static void symbol__free_source_line(struct symbol *sym, int len)
{
	struct annotation *notes = symbol__annotation(sym);
544
	struct source_line *src_line = notes->src->lines;
545 546 547 548 549 550
	int i;

	for (i = 0; i < len; i++)
		free(src_line[i].path);

	free(src_line);
551
	notes->src->lines = NULL;
552 553 554 555
}

/* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map,
556
				   int evidx, struct rb_root *root, int len,
557 558 559 560 561 562 563
				   const char *filename)
{
	u64 start;
	int i;
	char cmd[PATH_MAX * 2];
	struct source_line *src_line;
	struct annotation *notes = symbol__annotation(sym);
564
	struct sym_hist *h = annotation__histogram(notes, evidx);
565 566 567 568

	if (!h->sum)
		return 0;

569 570
	src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
	if (!notes->src->lines)
571 572
		return -1;

573
	start = map__rip_2objdump(map, sym->start);
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636

	for (i = 0; i < len; i++) {
		char *path = NULL;
		size_t line_len;
		u64 offset;
		FILE *fp;

		src_line[i].percent = 100.0 * h->addr[i] / h->sum;
		if (src_line[i].percent <= 0.5)
			continue;

		offset = start + i;
		sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
		fp = popen(cmd, "r");
		if (!fp)
			continue;

		if (getline(&path, &line_len, fp) < 0 || !line_len)
			goto next;

		src_line[i].path = malloc(sizeof(char) * line_len + 1);
		if (!src_line[i].path)
			goto next;

		strcpy(src_line[i].path, path);
		insert_source_line(root, &src_line[i]);

	next:
		pclose(fp);
	}

	return 0;
}

static void print_summary(struct rb_root *root, const char *filename)
{
	struct source_line *src_line;
	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) {
		double percent;
		const char *color;
		char *path;

		src_line = rb_entry(node, struct source_line, node);
		percent = src_line->percent;
		color = get_percent_color(percent);
		path = src_line->path;

		color_fprintf(stdout, color, " %7.2f %s", percent, path);
		node = rb_next(node);
	}
}

637
static void symbol__annotate_hits(struct symbol *sym, int evidx)
638 639
{
	struct annotation *notes = symbol__annotation(sym);
640
	struct sym_hist *h = annotation__histogram(notes, evidx);
641
	u64 len = symbol__size(sym), offset;
642 643 644 645 646 647 648 649

	for (offset = 0; offset < len; ++offset)
		if (h->addr[offset] != 0)
			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
			       sym->start + offset, h->addr[offset]);
	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
}

650
int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
651 652
			    bool full_paths, int min_pcnt, int max_lines,
			    int context)
653 654 655
{
	struct dso *dso = map->dso;
	const char *filename = dso->long_name, *d_filename;
656
	struct annotation *notes = symbol__annotation(sym);
657
	struct disasm_line *pos, *queue = NULL;
658
	u64 start = map__rip_2objdump(map, sym->start);
659
	int printed = 2, queue_len = 0;
660
	int more = 0;
661 662 663 664 665 666 667
	u64 len;

	if (full_paths)
		d_filename = filename;
	else
		d_filename = basename(filename);

668
	len = symbol__size(sym);
669 670 671 672 673

	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
	printf("------------------------------------------------\n");

	if (verbose)
674
		symbol__annotate_hits(sym, evidx);
675

676
	list_for_each_entry(pos, &notes->src->source, node) {
677 678 679 680 681
		if (context && queue == NULL) {
			queue = pos;
			queue_len = 0;
		}

682
		switch (disasm_line__print(pos, sym, start, evidx, len,
683 684
					    min_pcnt, printed, max_lines,
					    queue)) {
685 686
		case 0:
			++printed;
687 688 689 690 691
			if (context) {
				printed += queue_len;
				queue = NULL;
				queue_len = 0;
			}
692 693 694 695
			break;
		case 1:
			/* filtered by max_lines */
			++more;
696
			break;
697 698
		case -1:
		default:
699 700 701 702 703 704 705 706 707 708
			/*
			 * Filtered by min_pcnt or non IP lines when
			 * context != 0
			 */
			if (!context)
				break;
			if (queue_len == context)
				queue = list_entry(queue->node.next, typeof(*queue), node);
			else
				++queue_len;
709 710 711 712 713 714
			break;
		}
	}

	return more;
}
715

716 717 718 719 720
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);

721
	memset(h, 0, notes->src->sizeof_sym_hist);
722 723
}

724
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
725 726 727
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);
728
	int len = symbol__size(sym), offset;
729 730

	h->sum = 0;
731 732 733
	for (offset = 0; offset < len; ++offset) {
		h->addr[offset] = h->addr[offset] * 7 / 8;
		h->sum += h->addr[offset];
734 735 736
	}
}

737
void disasm__purge(struct list_head *head)
738
{
739
	struct disasm_line *pos, *n;
740 741 742

	list_for_each_entry_safe(pos, n, head, node) {
		list_del(&pos->node);
743
		disasm_line__free(pos);
744 745 746
	}
}

747 748 749 750 751 752 753 754 755
static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
{
	size_t printed;

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

	printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);

756
	if (dl->ops.raw[0] != '\0') {
757
		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
758
				   dl->ops.raw);
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	}

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

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

	list_for_each_entry(pos, head, node)
		printed += disasm_line__fprintf(pos, fp);

	return printed;
}

775 776 777 778 779 780 781 782 783
int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
			 bool print_lines, bool full_paths, int min_pcnt,
			 int max_lines)
{
	struct dso *dso = map->dso;
	const char *filename = dso->long_name;
	struct rb_root source_line = RB_ROOT;
	u64 len;

784
	if (symbol__annotate(sym, map, 0) < 0)
785 786
		return -1;

787
	len = symbol__size(sym);
788 789 790 791 792

	if (print_lines) {
		symbol__get_source_line(sym, map, evidx, &source_line,
					len, filename);
		print_summary(&source_line, filename);
793 794
	}

795
	symbol__annotate_printf(sym, map, evidx, full_paths,
796
				min_pcnt, max_lines, 0);
797 798 799
	if (print_lines)
		symbol__free_source_line(sym, len);

800
	disasm__purge(&symbol__annotation(sym)->src->source);
801

802 803
	return 0;
}