1 /*
2  * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com>
3  *
4  * Parts came from builtin-annotate.c, see those files for further
5  * copyright notes.
6  *
7  * Released under the GPL v2. (and only v2, not any later version)
8  */
9 
10 #include "util.h"
11 #include "build-id.h"
12 #include "color.h"
13 #include "cache.h"
14 #include "symbol.h"
15 #include "debug.h"
16 #include "annotate.h"
17 #include <pthread.h>
18 
symbol__annotate_init(struct map * map __used,struct symbol * sym)19 int symbol__annotate_init(struct map *map __used, struct symbol *sym)
20 {
21 	struct annotation *notes = symbol__annotation(sym);
22 	pthread_mutex_init(&notes->lock, NULL);
23 	return 0;
24 }
25 
symbol__alloc_hist(struct symbol * sym,int nevents)26 int symbol__alloc_hist(struct symbol *sym, int nevents)
27 {
28 	struct annotation *notes = symbol__annotation(sym);
29 	size_t sizeof_sym_hist = (sizeof(struct sym_hist) +
30 				  (sym->end - sym->start) * sizeof(u64));
31 
32 	notes->src = zalloc(sizeof(*notes->src) + nevents * sizeof_sym_hist);
33 	if (notes->src == NULL)
34 		return -1;
35 	notes->src->sizeof_sym_hist = sizeof_sym_hist;
36 	notes->src->nr_histograms   = nevents;
37 	INIT_LIST_HEAD(&notes->src->source);
38 	return 0;
39 }
40 
symbol__annotate_zero_histograms(struct symbol * sym)41 void symbol__annotate_zero_histograms(struct symbol *sym)
42 {
43 	struct annotation *notes = symbol__annotation(sym);
44 
45 	pthread_mutex_lock(&notes->lock);
46 	if (notes->src != NULL)
47 		memset(notes->src->histograms, 0,
48 		       notes->src->nr_histograms * notes->src->sizeof_sym_hist);
49 	pthread_mutex_unlock(&notes->lock);
50 }
51 
symbol__inc_addr_samples(struct symbol * sym,struct map * map,int evidx,u64 addr)52 int symbol__inc_addr_samples(struct symbol *sym, struct map *map,
53 			     int evidx, u64 addr)
54 {
55 	unsigned offset;
56 	struct annotation *notes;
57 	struct sym_hist *h;
58 
59 	notes = symbol__annotation(sym);
60 	if (notes->src == NULL)
61 		return -ENOMEM;
62 
63 	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr));
64 
65 	if (addr >= sym->end)
66 		return 0;
67 
68 	offset = addr - sym->start;
69 	h = annotation__histogram(notes, evidx);
70 	h->sum++;
71 	h->addr[offset]++;
72 
73 	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64
74 		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name,
75 		  addr, addr - sym->start, evidx, h->addr[offset]);
76 	return 0;
77 }
78 
objdump_line__new(s64 offset,char * line,size_t privsize)79 static struct objdump_line *objdump_line__new(s64 offset, char *line, size_t privsize)
80 {
81 	struct objdump_line *self = malloc(sizeof(*self) + privsize);
82 
83 	if (self != NULL) {
84 		self->offset = offset;
85 		self->line = line;
86 	}
87 
88 	return self;
89 }
90 
objdump_line__free(struct objdump_line * self)91 void objdump_line__free(struct objdump_line *self)
92 {
93 	free(self->line);
94 	free(self);
95 }
96 
objdump__add_line(struct list_head * head,struct objdump_line * line)97 static void objdump__add_line(struct list_head *head, struct objdump_line *line)
98 {
99 	list_add_tail(&line->node, head);
100 }
101 
objdump__get_next_ip_line(struct list_head * head,struct objdump_line * pos)102 struct objdump_line *objdump__get_next_ip_line(struct list_head *head,
103 					       struct objdump_line *pos)
104 {
105 	list_for_each_entry_continue(pos, head, node)
106 		if (pos->offset >= 0)
107 			return pos;
108 
109 	return NULL;
110 }
111 
objdump_line__print(struct objdump_line * oline,struct symbol * sym,int evidx,u64 len,int min_pcnt,int printed,int max_lines,struct objdump_line * queue)112 static int objdump_line__print(struct objdump_line *oline, struct symbol *sym,
113 			       int evidx, u64 len, int min_pcnt,
114 			       int printed, int max_lines,
115 			       struct objdump_line *queue)
116 {
117 	static const char *prev_line;
118 	static const char *prev_color;
119 
120 	if (oline->offset != -1) {
121 		const char *path = NULL;
122 		unsigned int hits = 0;
123 		double percent = 0.0;
124 		const char *color;
125 		struct annotation *notes = symbol__annotation(sym);
126 		struct source_line *src_line = notes->src->lines;
127 		struct sym_hist *h = annotation__histogram(notes, evidx);
128 		s64 offset = oline->offset;
129 		struct objdump_line *next;
130 
131 		next = objdump__get_next_ip_line(&notes->src->source, oline);
132 
133 		while (offset < (s64)len &&
134 		       (next == NULL || offset < next->offset)) {
135 			if (src_line) {
136 				if (path == NULL)
137 					path = src_line[offset].path;
138 				percent += src_line[offset].percent;
139 			} else
140 				hits += h->addr[offset];
141 
142 			++offset;
143 		}
144 
145 		if (src_line == NULL && h->sum)
146 			percent = 100.0 * hits / h->sum;
147 
148 		if (percent < min_pcnt)
149 			return -1;
150 
151 		if (max_lines && printed >= max_lines)
152 			return 1;
153 
154 		if (queue != NULL) {
155 			list_for_each_entry_from(queue, &notes->src->source, node) {
156 				if (queue == oline)
157 					break;
158 				objdump_line__print(queue, sym, evidx, len,
159 						    0, 0, 1, NULL);
160 			}
161 		}
162 
163 		color = get_percent_color(percent);
164 
165 		/*
166 		 * Also color the filename and line if needed, with
167 		 * the same color than the percentage. Don't print it
168 		 * twice for close colored addr with the same filename:line
169 		 */
170 		if (path) {
171 			if (!prev_line || strcmp(prev_line, path)
172 				       || color != prev_color) {
173 				color_fprintf(stdout, color, " %s", path);
174 				prev_line = path;
175 				prev_color = color;
176 			}
177 		}
178 
179 		color_fprintf(stdout, color, " %7.2f", percent);
180 		printf(" :	");
181 		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", oline->line);
182 	} else if (max_lines && printed >= max_lines)
183 		return 1;
184 	else {
185 		if (queue)
186 			return -1;
187 
188 		if (!*oline->line)
189 			printf("         :\n");
190 		else
191 			printf("         :	%s\n", oline->line);
192 	}
193 
194 	return 0;
195 }
196 
symbol__parse_objdump_line(struct symbol * sym,struct map * map,FILE * file,size_t privsize)197 static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
198 				      FILE *file, size_t privsize)
199 {
200 	struct annotation *notes = symbol__annotation(sym);
201 	struct objdump_line *objdump_line;
202 	char *line = NULL, *tmp, *tmp2, *c;
203 	size_t line_len;
204 	s64 line_ip, offset = -1;
205 
206 	if (getline(&line, &line_len, file) < 0)
207 		return -1;
208 
209 	if (!line)
210 		return -1;
211 
212 	while (line_len != 0 && isspace(line[line_len - 1]))
213 		line[--line_len] = '\0';
214 
215 	c = strchr(line, '\n');
216 	if (c)
217 		*c = 0;
218 
219 	line_ip = -1;
220 
221 	/*
222 	 * Strip leading spaces:
223 	 */
224 	tmp = line;
225 	while (*tmp) {
226 		if (*tmp != ' ')
227 			break;
228 		tmp++;
229 	}
230 
231 	if (*tmp) {
232 		/*
233 		 * Parse hexa addresses followed by ':'
234 		 */
235 		line_ip = strtoull(tmp, &tmp2, 16);
236 		if (*tmp2 != ':' || tmp == tmp2 || tmp2[1] == '\0')
237 			line_ip = -1;
238 	}
239 
240 	if (line_ip != -1) {
241 		u64 start = map__rip_2objdump(map, sym->start),
242 		    end = map__rip_2objdump(map, sym->end);
243 
244 		offset = line_ip - start;
245 		if (offset < 0 || (u64)line_ip > end)
246 			offset = -1;
247 	}
248 
249 	objdump_line = objdump_line__new(offset, line, privsize);
250 	if (objdump_line == NULL) {
251 		free(line);
252 		return -1;
253 	}
254 	objdump__add_line(&notes->src->source, objdump_line);
255 
256 	return 0;
257 }
258 
symbol__annotate(struct symbol * sym,struct map * map,size_t privsize)259 int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
260 {
261 	struct dso *dso = map->dso;
262 	char *filename = dso__build_id_filename(dso, NULL, 0);
263 	bool free_filename = true;
264 	char command[PATH_MAX * 2];
265 	FILE *file;
266 	int err = 0;
267 	char symfs_filename[PATH_MAX];
268 
269 	if (filename) {
270 		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
271 			 symbol_conf.symfs, filename);
272 	}
273 
274 	if (filename == NULL) {
275 		if (dso->has_build_id) {
276 			pr_err("Can't annotate %s: not enough memory\n",
277 			       sym->name);
278 			return -ENOMEM;
279 		}
280 		goto fallback;
281 	} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
282 		   strstr(command, "[kernel.kallsyms]") ||
283 		   access(symfs_filename, R_OK)) {
284 		free(filename);
285 fallback:
286 		/*
287 		 * If we don't have build-ids or the build-id file isn't in the
288 		 * cache, or is just a kallsyms file, well, lets hope that this
289 		 * DSO is the same as when 'perf record' ran.
290 		 */
291 		filename = dso->long_name;
292 		snprintf(symfs_filename, sizeof(symfs_filename), "%s%s",
293 			 symbol_conf.symfs, filename);
294 		free_filename = false;
295 	}
296 
297 	if (dso->symtab_type == SYMTAB__KALLSYMS) {
298 		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id ";
299 		char *build_id_msg = NULL;
300 
301 		if (dso->annotate_warned)
302 			goto out_free_filename;
303 
304 		if (dso->has_build_id) {
305 			build_id__sprintf(dso->build_id,
306 					  sizeof(dso->build_id), bf + 15);
307 			build_id_msg = bf;
308 		}
309 		err = -ENOENT;
310 		dso->annotate_warned = 1;
311 		pr_err("Can't annotate %s: No vmlinux file%s was found in the "
312 		       "path.\nPlease use 'perf buildid-cache -av vmlinux' or "
313 		       "--vmlinux vmlinux.\n",
314 		       sym->name, build_id_msg ?: "");
315 		goto out_free_filename;
316 	}
317 
318 	pr_debug("%s: filename=%s, sym=%s, start=%#" PRIx64 ", end=%#" PRIx64 "\n", __func__,
319 		 filename, sym->name, map->unmap_ip(map, sym->start),
320 		 map->unmap_ip(map, sym->end));
321 
322 	pr_debug("annotating [%p] %30s : [%p] %30s\n",
323 		 dso, dso->long_name, sym, sym->name);
324 
325 	snprintf(command, sizeof(command),
326 		 "objdump --start-address=0x%016" PRIx64
327 		 " --stop-address=0x%016" PRIx64 " -dS -C %s|grep -v %s|expand",
328 		 map__rip_2objdump(map, sym->start),
329 		 map__rip_2objdump(map, sym->end),
330 		 symfs_filename, filename);
331 
332 	pr_debug("Executing: %s\n", command);
333 
334 	file = popen(command, "r");
335 	if (!file)
336 		goto out_free_filename;
337 
338 	while (!feof(file))
339 		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
340 			break;
341 
342 	pclose(file);
343 out_free_filename:
344 	if (free_filename)
345 		free(filename);
346 	return err;
347 }
348 
insert_source_line(struct rb_root * root,struct source_line * src_line)349 static void insert_source_line(struct rb_root *root, struct source_line *src_line)
350 {
351 	struct source_line *iter;
352 	struct rb_node **p = &root->rb_node;
353 	struct rb_node *parent = NULL;
354 
355 	while (*p != NULL) {
356 		parent = *p;
357 		iter = rb_entry(parent, struct source_line, node);
358 
359 		if (src_line->percent > iter->percent)
360 			p = &(*p)->rb_left;
361 		else
362 			p = &(*p)->rb_right;
363 	}
364 
365 	rb_link_node(&src_line->node, parent, p);
366 	rb_insert_color(&src_line->node, root);
367 }
368 
symbol__free_source_line(struct symbol * sym,int len)369 static void symbol__free_source_line(struct symbol *sym, int len)
370 {
371 	struct annotation *notes = symbol__annotation(sym);
372 	struct source_line *src_line = notes->src->lines;
373 	int i;
374 
375 	for (i = 0; i < len; i++)
376 		free(src_line[i].path);
377 
378 	free(src_line);
379 	notes->src->lines = NULL;
380 }
381 
382 /* Get the filename:line for the colored entries */
symbol__get_source_line(struct symbol * sym,struct map * map,int evidx,struct rb_root * root,int len,const char * filename)383 static int symbol__get_source_line(struct symbol *sym, struct map *map,
384 				   int evidx, struct rb_root *root, int len,
385 				   const char *filename)
386 {
387 	u64 start;
388 	int i;
389 	char cmd[PATH_MAX * 2];
390 	struct source_line *src_line;
391 	struct annotation *notes = symbol__annotation(sym);
392 	struct sym_hist *h = annotation__histogram(notes, evidx);
393 
394 	if (!h->sum)
395 		return 0;
396 
397 	src_line = notes->src->lines = calloc(len, sizeof(struct source_line));
398 	if (!notes->src->lines)
399 		return -1;
400 
401 	start = map->unmap_ip(map, sym->start);
402 
403 	for (i = 0; i < len; i++) {
404 		char *path = NULL;
405 		size_t line_len;
406 		u64 offset;
407 		FILE *fp;
408 
409 		src_line[i].percent = 100.0 * h->addr[i] / h->sum;
410 		if (src_line[i].percent <= 0.5)
411 			continue;
412 
413 		offset = start + i;
414 		sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
415 		fp = popen(cmd, "r");
416 		if (!fp)
417 			continue;
418 
419 		if (getline(&path, &line_len, fp) < 0 || !line_len)
420 			goto next;
421 
422 		src_line[i].path = malloc(sizeof(char) * line_len + 1);
423 		if (!src_line[i].path)
424 			goto next;
425 
426 		strcpy(src_line[i].path, path);
427 		insert_source_line(root, &src_line[i]);
428 
429 	next:
430 		pclose(fp);
431 	}
432 
433 	return 0;
434 }
435 
print_summary(struct rb_root * root,const char * filename)436 static void print_summary(struct rb_root *root, const char *filename)
437 {
438 	struct source_line *src_line;
439 	struct rb_node *node;
440 
441 	printf("\nSorted summary for file %s\n", filename);
442 	printf("----------------------------------------------\n\n");
443 
444 	if (RB_EMPTY_ROOT(root)) {
445 		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
446 		return;
447 	}
448 
449 	node = rb_first(root);
450 	while (node) {
451 		double percent;
452 		const char *color;
453 		char *path;
454 
455 		src_line = rb_entry(node, struct source_line, node);
456 		percent = src_line->percent;
457 		color = get_percent_color(percent);
458 		path = src_line->path;
459 
460 		color_fprintf(stdout, color, " %7.2f %s", percent, path);
461 		node = rb_next(node);
462 	}
463 }
464 
symbol__annotate_hits(struct symbol * sym,int evidx)465 static void symbol__annotate_hits(struct symbol *sym, int evidx)
466 {
467 	struct annotation *notes = symbol__annotation(sym);
468 	struct sym_hist *h = annotation__histogram(notes, evidx);
469 	u64 len = sym->end - sym->start, offset;
470 
471 	for (offset = 0; offset < len; ++offset)
472 		if (h->addr[offset] != 0)
473 			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
474 			       sym->start + offset, h->addr[offset]);
475 	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
476 }
477 
symbol__annotate_printf(struct symbol * sym,struct map * map,int evidx,bool full_paths,int min_pcnt,int max_lines,int context)478 int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx,
479 			    bool full_paths, int min_pcnt, int max_lines,
480 			    int context)
481 {
482 	struct dso *dso = map->dso;
483 	const char *filename = dso->long_name, *d_filename;
484 	struct annotation *notes = symbol__annotation(sym);
485 	struct objdump_line *pos, *queue = NULL;
486 	int printed = 2, queue_len = 0;
487 	int more = 0;
488 	u64 len;
489 
490 	if (full_paths)
491 		d_filename = filename;
492 	else
493 		d_filename = basename(filename);
494 
495 	len = sym->end - sym->start;
496 
497 	printf(" Percent |	Source code & Disassembly of %s\n", d_filename);
498 	printf("------------------------------------------------\n");
499 
500 	if (verbose)
501 		symbol__annotate_hits(sym, evidx);
502 
503 	list_for_each_entry(pos, &notes->src->source, node) {
504 		if (context && queue == NULL) {
505 			queue = pos;
506 			queue_len = 0;
507 		}
508 
509 		switch (objdump_line__print(pos, sym, evidx, len, min_pcnt,
510 					    printed, max_lines, queue)) {
511 		case 0:
512 			++printed;
513 			if (context) {
514 				printed += queue_len;
515 				queue = NULL;
516 				queue_len = 0;
517 			}
518 			break;
519 		case 1:
520 			/* filtered by max_lines */
521 			++more;
522 			break;
523 		case -1:
524 		default:
525 			/*
526 			 * Filtered by min_pcnt or non IP lines when
527 			 * context != 0
528 			 */
529 			if (!context)
530 				break;
531 			if (queue_len == context)
532 				queue = list_entry(queue->node.next, typeof(*queue), node);
533 			else
534 				++queue_len;
535 			break;
536 		}
537 	}
538 
539 	return more;
540 }
541 
symbol__annotate_zero_histogram(struct symbol * sym,int evidx)542 void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
543 {
544 	struct annotation *notes = symbol__annotation(sym);
545 	struct sym_hist *h = annotation__histogram(notes, evidx);
546 
547 	memset(h, 0, notes->src->sizeof_sym_hist);
548 }
549 
symbol__annotate_decay_histogram(struct symbol * sym,int evidx)550 void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
551 {
552 	struct annotation *notes = symbol__annotation(sym);
553 	struct sym_hist *h = annotation__histogram(notes, evidx);
554 	struct objdump_line *pos;
555 	int len = sym->end - sym->start;
556 
557 	h->sum = 0;
558 
559 	list_for_each_entry(pos, &notes->src->source, node) {
560 		if (pos->offset != -1 && pos->offset < len) {
561 			h->addr[pos->offset] = h->addr[pos->offset] * 7 / 8;
562 			h->sum += h->addr[pos->offset];
563 		}
564 	}
565 }
566 
objdump_line_list__purge(struct list_head * head)567 void objdump_line_list__purge(struct list_head *head)
568 {
569 	struct objdump_line *pos, *n;
570 
571 	list_for_each_entry_safe(pos, n, head, node) {
572 		list_del(&pos->node);
573 		objdump_line__free(pos);
574 	}
575 }
576 
symbol__tty_annotate(struct symbol * sym,struct map * map,int evidx,bool print_lines,bool full_paths,int min_pcnt,int max_lines)577 int symbol__tty_annotate(struct symbol *sym, struct map *map, int evidx,
578 			 bool print_lines, bool full_paths, int min_pcnt,
579 			 int max_lines)
580 {
581 	struct dso *dso = map->dso;
582 	const char *filename = dso->long_name;
583 	struct rb_root source_line = RB_ROOT;
584 	u64 len;
585 
586 	if (symbol__annotate(sym, map, 0) < 0)
587 		return -1;
588 
589 	len = sym->end - sym->start;
590 
591 	if (print_lines) {
592 		symbol__get_source_line(sym, map, evidx, &source_line,
593 					len, filename);
594 		print_summary(&source_line, filename);
595 	}
596 
597 	symbol__annotate_printf(sym, map, evidx, full_paths,
598 				min_pcnt, max_lines, 0);
599 	if (print_lines)
600 		symbol__free_source_line(sym, len);
601 
602 	objdump_line_list__purge(&symbol__annotation(sym)->src->source);
603 
604 	return 0;
605 }
606