annotate.c 17.3 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 22 23 24 25 26 27 28 29 30 31 32 33 34 35
static int call_ops__parse_target(const char *operands, u64 *target)
{
	*target = strtoull(operands, NULL, 16);
	return 0;
}

static struct ins_ops call_ops = {
	.parse_target = call_ops__parse_target,
};

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

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
static int jump_ops__parse_target(const char *operands, u64 *target)
{
	const char *s = strchr(operands, '+');

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

	*target = strtoll(s, NULL, 16);
	return 0;
}

static struct ins_ops jump_ops = {
	.parse_target = jump_ops__parse_target,
};

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

/*
 * Must be sorted by name!
 */
static struct ins instructions[] = {
60 61
	{ .name = "call",  .ops  = &call_ops, },
	{ .name = "callq", .ops  = &call_ops, },
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
	{ .name = "ja",	   .ops  = &jump_ops, },
	{ .name = "je",	   .ops  = &jump_ops, },
	{ .name = "jmp",   .ops  = &jump_ops, },
	{ .name = "jmpq",  .ops  = &jump_ops, },
	{ .name = "jne",   .ops  = &jump_ops, },
	{ .name = "js",	   .ops  = &jump_ops, },
};

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);
}

84
int symbol__annotate_init(struct map *map __used, struct symbol *sym)
85 86
{
	struct annotation *notes = symbol__annotation(sym);
87 88 89
	pthread_mutex_init(&notes->lock, NULL);
	return 0;
}
90

91
int symbol__alloc_hist(struct symbol *sym)
92 93
{
	struct annotation *notes = symbol__annotation(sym);
94 95
	const size_t size = sym->end - sym->start + 1;
	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
96

97
	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
98 99 100
	if (notes->src == NULL)
		return -1;
	notes->src->sizeof_sym_hist = sizeof_sym_hist;
101
	notes->src->nr_histograms   = symbol_conf.nr_events;
102 103
	INIT_LIST_HEAD(&notes->src->source);
	return 0;
104 105
}

106 107 108 109
void symbol__annotate_zero_histograms(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);

110 111 112 113 114
	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);
115 116
}

117 118
int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
			     int evidx, u64 addr)
119
{
120
	unsigned offset;
121 122 123 124
	struct annotation *notes;
	struct sym_hist *h;

	notes = symbol__annotation(sym);
125
	if (notes->src == NULL)
126 127 128 129
		return -ENOMEM;

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

130 131
	if (addr < sym->start || addr > sym->end)
		return -ERANGE;
132

133 134
	offset = addr - sym->start;
	h = annotation__histogram(notes, evidx);
135 136 137 138
	h->sum++;
	h->addr[offset]++;

	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
139 140
		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
		  addr, addr - sym->start, evidx, h->addr[offset]);
141 142 143
	return 0;
}

144 145 146 147 148 149 150 151 152 153 154 155 156 157
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;

	if (dl->ins->ops->parse_target)
		dl->ins->ops->parse_target(dl->operands, &dl->target);
}

158
static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
159
{
160
	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
161

162 163 164 165
	if (dl != NULL) {
		dl->offset = offset;
		dl->line = strdup(line);
		if (dl->line == NULL)
166
			goto out_delete;
167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196

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

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

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

			dl->operands = name + 1;

			while (dl->operands[0] != '\0' &&
			       !isspace(dl->operands[0]))
				++dl->operands;

			tmp = dl->operands[0];
			dl->operands[0] = '\0';
			dl->name = strdup(name);

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

			dl->operands[0] = tmp;

			if (dl->operands[0] != '\0') {
				dl->operands++;
				while (isspace(dl->operands[0]))
					++dl->operands;
			}
197 198

			disasm_line__init_ins(dl);
199
		}
200 201
	}

202
	return dl;
203 204 205

out_free_line:
	free(dl->line);
206
out_delete:
207
	free(dl);
208
	return NULL;
209 210
}

211
void disasm_line__free(struct disasm_line *dl)
212
{
213
	free(dl->line);
214
	free(dl->name);
215
	free(dl);
216 217
}

218
static void disasm__add(struct list_head *head, struct disasm_line *line)
219 220 221 222
{
	list_add_tail(&line->node, head);
}

223
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
224 225 226 227 228 229 230 231
{
	list_for_each_entry_continue(pos, head, node)
		if (pos->offset >= 0)
			return pos;

	return NULL;
}

232 233 234
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)
235 236 237 238
{
	static const char *prev_line;
	static const char *prev_color;

239
	if (dl->offset != -1) {
240 241 242 243 244
		const char *path = NULL;
		unsigned int hits = 0;
		double percent = 0.0;
		const char *color;
		struct annotation *notes = symbol__annotation(sym);
245
		struct source_line *src_line = notes->src->lines;
246
		struct sym_hist *h = annotation__histogram(notes, evidx);
247
		s64 offset = dl->offset;
248
		const u64 addr = start + offset;
249
		struct disasm_line *next;
250

251
		next = disasm__get_next_ip_line(&notes->src->source, dl);
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267

		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;

268
		if (percent < min_pcnt)
269 270
			return -1;

271
		if (max_lines && printed >= max_lines)
272
			return 1;
273

274 275
		if (queue != NULL) {
			list_for_each_entry_from(queue, &notes->src->source, node) {
276
				if (queue == dl)
277
					break;
278
				disasm_line__print(queue, sym, start, evidx, len,
279 280 281 282
						    0, 0, 1, NULL);
			}
		}

283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300
		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(" :	");
301
		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
302
		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
303
	} else if (max_lines && printed >= max_lines)
304 305
		return 1;
	else {
306 307 308
		if (queue)
			return -1;

309
		if (!*dl->line)
310 311
			printf("         :\n");
		else
312
			printf("         :	%s\n", dl->line);
313
	}
314 315

	return 0;
316 317
}

318 319
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
				      FILE *file, size_t privsize)
320
{
321
	struct annotation *notes = symbol__annotation(sym);
322
	struct disasm_line *dl;
323
	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340
	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 已提交
341
	parsed_line = line;
342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368

	/*
	 * 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;
369 370
		else
			parsed_line = tmp2 + 1;
N
Namhyung Kim 已提交
371
	}
372

373
	dl = disasm_line__new(offset, parsed_line, privsize);
374 375
	free(line);

376
	if (dl == NULL)
377
		return -1;
378

379
	disasm__add(&notes->src->source, dl);
380 381 382 383

	return 0;
}

384
int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421
{
	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;
	}

422
	if (dso->symtab_type == SYMTAB__KALLSYMS) {
423 424 425
		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
		char *build_id_msg = NULL;

426 427
		if (dso->annotate_warned)
			goto out_free_filename;
428 429 430 431 432 433

		if (dso->has_build_id) {
			build_id__sprintf(dso->build_id,
					  sizeof(dso->build_id), bf + 15);
			build_id_msg = bf;
		}
434 435
		err = -ENOENT;
		dso->annotate_warned = 1;
436 437 438 439 440
		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"
441
		       "  --vmlinux vmlinux\n",
442
		       sym->name, build_id_msg ?: "");
443 444 445 446 447 448 449 450 451 452 453
		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),
454
		 "objdump %s%s --start-address=0x%016" PRIx64
455 456
		 " --stop-address=0x%016" PRIx64
		 " -d %s %s -C %s|grep -v %s|expand",
457 458
		 disassembler_style ? "-M " : "",
		 disassembler_style ? disassembler_style : "",
459
		 map__rip_2objdump(map, sym->start),
I
Ingo Molnar 已提交
460
		 map__rip_2objdump(map, sym->end+1),
461 462
		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
		 symbol_conf.annotate_src ? "-S" : "",
463 464 465 466 467 468 469 470 471
		 symfs_filename, filename);

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

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

	while (!feof(file))
472
		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504
			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);
505
	struct source_line *src_line = notes->src->lines;
506 507 508 509 510 511
	int i;

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

	free(src_line);
512
	notes->src->lines = NULL;
513 514 515 516
}

/* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map,
517
				   int evidx, struct rb_root *root, int len,
518 519 520 521 522 523 524
				   const char *filename)
{
	u64 start;
	int i;
	char cmd[PATH_MAX * 2];
	struct source_line *src_line;
	struct annotation *notes = symbol__annotation(sym);
525
	struct sym_hist *h = annotation__histogram(notes, evidx);
526 527 528 529

	if (!h->sum)
		return 0;

530 531
	src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
	if (!notes->src->lines)
532 533
		return -1;

534
	start = map__rip_2objdump(map, sym->start);
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597

	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);
	}
}

598
static void symbol__annotate_hits(struct symbol *sym, int evidx)
599 600
{
	struct annotation *notes = symbol__annotation(sym);
601
	struct sym_hist *h = annotation__histogram(notes, evidx);
602 603 604 605 606 607 608 609 610
	u64 len = sym->end - sym->start, offset;

	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);
}

611
int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
612 613
			    bool full_paths, int min_pcnt, int max_lines,
			    int context)
614 615 616
{
	struct dso *dso = map->dso;
	const char *filename = dso->long_name, *d_filename;
617
	struct annotation *notes = symbol__annotation(sym);
618
	struct disasm_line *pos, *queue = NULL;
619
	u64 start = map__rip_2objdump(map, sym->start);
620
	int printed = 2, queue_len = 0;
621
	int more = 0;
622 623 624 625 626 627 628 629 630 631 632 633 634
	u64 len;

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

	len = sym->end - sym->start;

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

	if (verbose)
635
		symbol__annotate_hits(sym, evidx);
636

637
	list_for_each_entry(pos, &notes->src->source, node) {
638 639 640 641 642
		if (context && queue == NULL) {
			queue = pos;
			queue_len = 0;
		}

643
		switch (disasm_line__print(pos, sym, start, evidx, len,
644 645
					    min_pcnt, printed, max_lines,
					    queue)) {
646 647
		case 0:
			++printed;
648 649 650 651 652
			if (context) {
				printed += queue_len;
				queue = NULL;
				queue_len = 0;
			}
653 654 655 656
			break;
		case 1:
			/* filtered by max_lines */
			++more;
657
			break;
658 659
		case -1:
		default:
660 661 662 663 664 665 666 667 668 669
			/*
			 * 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;
670 671 672 673 674 675
			break;
		}
	}

	return more;
}
676

677 678 679 680 681
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);

682
	memset(h, 0, notes->src->sizeof_sym_hist);
683 684
}

685
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
686 687 688
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);
689
	int len = sym->end - sym->start, offset;
690 691

	h->sum = 0;
692 693 694
	for (offset = 0; offset < len; ++offset) {
		h->addr[offset] = h->addr[offset] * 7 / 8;
		h->sum += h->addr[offset];
695 696 697
	}
}

698
void disasm__purge(struct list_head *head)
699
{
700
	struct disasm_line *pos, *n;
701 702 703

	list_for_each_entry_safe(pos, n, head, node) {
		list_del(&pos->node);
704
		disasm_line__free(pos);
705 706 707
	}
}

708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
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);

	if (dl->operands[0] != '\0') {
		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
				   dl->operands);
	}

	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;
}

736 737 738 739 740 741 742 743 744
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;

745
	if (symbol__annotate(sym, map, 0) < 0)
746 747 748 749 750 751 752 753
		return -1;

	len = sym->end - sym->start;

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

756
	symbol__annotate_printf(sym, map, evidx, full_paths,
757
				min_pcnt, max_lines, 0);
758 759 760
	if (print_lines)
		symbol__free_source_line(sym, len);

761
	disasm__purge(&symbol__annotation(sym)->src->source);
762

763 764
	return 0;
}