annotate.c 15.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
int symbol__annotate_init(struct map *map __used, struct symbol *sym)
22 23
{
	struct annotation *notes = symbol__annotation(sym);
24 25 26
	pthread_mutex_init(&notes->lock, NULL);
	return 0;
}
27

28
int symbol__alloc_hist(struct symbol *sym)
29 30
{
	struct annotation *notes = symbol__annotation(sym);
31 32
	const size_t size = sym->end - sym->start + 1;
	size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64));
33

34
	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist);
35 36 37
	if (notes->src == NULL)
		return -1;
	notes->src->sizeof_sym_hist = sizeof_sym_hist;
38
	notes->src->nr_histograms   = symbol_conf.nr_events;
39 40
	INIT_LIST_HEAD(&notes->src->source);
	return 0;
41 42
}

43 44 45 46
void symbol__annotate_zero_histograms(struct symbol *sym)
{
	struct annotation *notes = symbol__annotation(sym);

47 48 49 50 51
	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);
52 53
}

54 55
int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
			     int evidx, u64 addr)
56
{
57
	unsigned offset;
58 59 60 61
	struct annotation *notes;
	struct sym_hist *h;

	notes = symbol__annotation(sym);
62
	if (notes->src == NULL)
63 64 65 66
		return -ENOMEM;

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

67 68
	if (addr < sym->start || addr > sym->end)
		return -ERANGE;
69

70 71
	offset = addr - sym->start;
	h = annotation__histogram(notes, evidx);
72 73 74 75
	h->sum++;
	h->addr[offset]++;

	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
76 77
		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
		  addr, addr - sym->start, evidx, h->addr[offset]);
78 79 80
	return 0;
}

81
static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
82
{
83
	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
84

85 86 87 88
	if (dl != NULL) {
		dl->offset = offset;
		dl->line = strdup(line);
		if (dl->line == NULL)
89
			goto out_delete;
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 118 119 120

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

123
	return dl;
124 125 126

out_free_line:
	free(dl->line);
127
out_delete:
128
	free(dl);
129
	return NULL;
130 131
}

132
void disasm_line__free(struct disasm_line *dl)
133
{
134
	free(dl->line);
135
	free(dl->name);
136
	free(dl);
137 138
}

139
static void disasm__add(struct list_head *head, struct disasm_line *line)
140 141 142 143
{
	list_add_tail(&line->node, head);
}

144
struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos)
145 146 147 148 149 150 151 152
{
	list_for_each_entry_continue(pos, head, node)
		if (pos->offset >= 0)
			return pos;

	return NULL;
}

153 154 155
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)
156 157 158 159
{
	static const char *prev_line;
	static const char *prev_color;

160
	if (dl->offset != -1) {
161 162 163 164 165
		const char *path = NULL;
		unsigned int hits = 0;
		double percent = 0.0;
		const char *color;
		struct annotation *notes = symbol__annotation(sym);
166
		struct source_line *src_line = notes->src->lines;
167
		struct sym_hist *h = annotation__histogram(notes, evidx);
168
		s64 offset = dl->offset;
169
		const u64 addr = start + offset;
170
		struct disasm_line *next;
171

172
		next = disasm__get_next_ip_line(&notes->src->source, dl);
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188

		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;

189
		if (percent < min_pcnt)
190 191
			return -1;

192
		if (max_lines && printed >= max_lines)
193
			return 1;
194

195 196
		if (queue != NULL) {
			list_for_each_entry_from(queue, &notes->src->source, node) {
197
				if (queue == dl)
198
					break;
199
				disasm_line__print(queue, sym, start, evidx, len,
200 201 202 203
						    0, 0, 1, NULL);
			}
		}

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221
		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(" :	");
222
		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr);
223
		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line);
224
	} else if (max_lines && printed >= max_lines)
225 226
		return 1;
	else {
227 228 229
		if (queue)
			return -1;

230
		if (!*dl->line)
231 232
			printf("         :\n");
		else
233
			printf("         :	%s\n", dl->line);
234
	}
235 236

	return 0;
237 238
}

239 240
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
				      FILE *file, size_t privsize)
241
{
242
	struct annotation *notes = symbol__annotation(sym);
243
	struct disasm_line *dl;
244
	char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
	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 已提交
262
	parsed_line = line;
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289

	/*
	 * 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;
290 291
		else
			parsed_line = tmp2 + 1;
N
Namhyung Kim 已提交
292
	}
293

294
	dl = disasm_line__new(offset, parsed_line, privsize);
295 296
	free(line);

297
	if (dl == NULL)
298
		return -1;
299

300
	disasm__add(&notes->src->source, dl);
301 302 303 304

	return 0;
}

305
int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
{
	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;
	}

343
	if (dso->symtab_type == SYMTAB__KALLSYMS) {
344 345 346
		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
		char *build_id_msg = NULL;

347 348
		if (dso->annotate_warned)
			goto out_free_filename;
349 350 351 352 353 354

		if (dso->has_build_id) {
			build_id__sprintf(dso->build_id,
					  sizeof(dso->build_id), bf + 15);
			build_id_msg = bf;
		}
355 356
		err = -ENOENT;
		dso->annotate_warned = 1;
357 358 359 360 361
		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"
362
		       "  --vmlinux vmlinux\n",
363
		       sym->name, build_id_msg ?: "");
364 365 366 367 368 369 370 371 372 373 374
		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),
375
		 "objdump %s%s --start-address=0x%016" PRIx64
376 377
		 " --stop-address=0x%016" PRIx64
		 " -d %s %s -C %s|grep -v %s|expand",
378 379
		 disassembler_style ? "-M " : "",
		 disassembler_style ? disassembler_style : "",
380
		 map__rip_2objdump(map, sym->start),
I
Ingo Molnar 已提交
381
		 map__rip_2objdump(map, sym->end+1),
382 383
		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw",
		 symbol_conf.annotate_src ? "-S" : "",
384 385 386 387 388 389 390 391 392
		 symfs_filename, filename);

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

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

	while (!feof(file))
393
		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
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 422 423 424 425
			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);
426
	struct source_line *src_line = notes->src->lines;
427 428 429 430 431 432
	int i;

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

	free(src_line);
433
	notes->src->lines = NULL;
434 435 436 437
}

/* Get the filename:line for the colored entries */
static int symbol__get_source_line(struct symbol *sym, struct map *map,
438
				   int evidx, struct rb_root *root, int len,
439 440 441 442 443 444 445
				   const char *filename)
{
	u64 start;
	int i;
	char cmd[PATH_MAX * 2];
	struct source_line *src_line;
	struct annotation *notes = symbol__annotation(sym);
446
	struct sym_hist *h = annotation__histogram(notes, evidx);
447 448 449 450

	if (!h->sum)
		return 0;

451 452
	src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
	if (!notes->src->lines)
453 454
		return -1;

455
	start = map__rip_2objdump(map, sym->start);
456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 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 505 506 507 508 509 510 511 512 513 514 515 516 517 518

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

519
static void symbol__annotate_hits(struct symbol *sym, int evidx)
520 521
{
	struct annotation *notes = symbol__annotation(sym);
522
	struct sym_hist *h = annotation__histogram(notes, evidx);
523 524 525 526 527 528 529 530 531
	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);
}

532
int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
533 534
			    bool full_paths, int min_pcnt, int max_lines,
			    int context)
535 536 537
{
	struct dso *dso = map->dso;
	const char *filename = dso->long_name, *d_filename;
538
	struct annotation *notes = symbol__annotation(sym);
539
	struct disasm_line *pos, *queue = NULL;
540
	u64 start = map__rip_2objdump(map, sym->start);
541
	int printed = 2, queue_len = 0;
542
	int more = 0;
543 544 545 546 547 548 549 550 551 552 553 554 555
	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)
556
		symbol__annotate_hits(sym, evidx);
557

558
	list_for_each_entry(pos, &notes->src->source, node) {
559 560 561 562 563
		if (context && queue == NULL) {
			queue = pos;
			queue_len = 0;
		}

564
		switch (disasm_line__print(pos, sym, start, evidx, len,
565 566
					    min_pcnt, printed, max_lines,
					    queue)) {
567 568
		case 0:
			++printed;
569 570 571 572 573
			if (context) {
				printed += queue_len;
				queue = NULL;
				queue_len = 0;
			}
574 575 576 577
			break;
		case 1:
			/* filtered by max_lines */
			++more;
578
			break;
579 580
		case -1:
		default:
581 582 583 584 585 586 587 588 589 590
			/*
			 * 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;
591 592 593 594 595 596
			break;
		}
	}

	return more;
}
597

598 599 600 601 602
void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);

603
	memset(h, 0, notes->src->sizeof_sym_hist);
604 605
}

606
void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
607 608 609
{
	struct annotation *notes = symbol__annotation(sym);
	struct sym_hist *h = annotation__histogram(notes, evidx);
610
	int len = sym->end - sym->start, offset;
611 612

	h->sum = 0;
613 614 615
	for (offset = 0; offset < len; ++offset) {
		h->addr[offset] = h->addr[offset] * 7 / 8;
		h->sum += h->addr[offset];
616 617 618
	}
}

619
void disasm__purge(struct list_head *head)
620
{
621
	struct disasm_line *pos, *n;
622 623 624

	list_for_each_entry_safe(pos, n, head, node) {
		list_del(&pos->node);
625
		disasm_line__free(pos);
626 627 628
	}
}

629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
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;
}

657 658 659 660 661 662 663 664 665
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;

666
	if (symbol__annotate(sym, map, 0) < 0)
667 668 669 670 671 672 673 674
		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);
675 676
	}

677
	symbol__annotate_printf(sym, map, evidx, full_paths,
678
				min_pcnt, max_lines, 0);
679 680 681
	if (print_lines)
		symbol__free_source_line(sym, len);

682
	disasm__purge(&symbol__annotation(sym)->src->source);
683

684 685
	return 0;
}