| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * 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"
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | #include <pthread.h>
 | 
					
						
							| 
									
										
										
										
											2012-10-27 23:18:29 +02:00
										 |  |  | #include <linux/bitops.h>
 | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-15 14:31:41 -07:00
										 |  |  | const char 	*disassembler_style; | 
					
						
							| 
									
										
										
										
											2012-09-04 12:32:30 +02:00
										 |  |  | const char	*objdump_path; | 
					
						
							| 
									
										
										
										
											2011-09-15 14:31:41 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | static struct ins *ins__find(const char *name); | 
					
						
							|  |  |  | static int disasm_line__parse(char *line, char **namep, char **rawp); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-12 13:26:20 -03:00
										 |  |  | static void ins__delete(struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free(ops->source.raw); | 
					
						
							|  |  |  | 	free(ops->source.name); | 
					
						
							|  |  |  | 	free(ops->target.raw); | 
					
						
							|  |  |  | 	free(ops->target.name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-07 18:54:16 -03:00
										 |  |  | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 
					
						
							|  |  |  | 			      struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->raw); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | static int call__parse(struct ins_operands *ops) | 
					
						
							| 
									
										
										
										
											2012-04-18 16:07:38 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 	char *endptr, *tok, *name; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	ops->target.addr = strtoull(ops->raw, &endptr, 16); | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	name = strchr(endptr, '<'); | 
					
						
							|  |  |  | 	if (name == NULL) | 
					
						
							|  |  |  | 		goto indirect_call; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	name++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tok = strchr(name, '>'); | 
					
						
							|  |  |  | 	if (tok == NULL) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*tok = '\0'; | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	ops->target.name = strdup(name); | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 	*tok = '>'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	return ops->target.name == NULL ? -1 : 0; | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | indirect_call: | 
					
						
							| 
									
										
										
										
											2012-05-11 12:28:55 -03:00
										 |  |  | 	tok = strchr(endptr, '('); | 
					
						
							|  |  |  | 	if (tok != NULL) { | 
					
						
							|  |  |  | 		ops->target.addr = 0; | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 	tok = strchr(endptr, '*'); | 
					
						
							|  |  |  | 	if (tok == NULL) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	ops->target.addr = strtoull(tok + 1, NULL, 16); | 
					
						
							| 
									
										
										
										
											2012-04-18 16:07:38 -03:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | static int call__scnprintf(struct ins *ins, char *bf, size_t size, | 
					
						
							| 
									
										
										
										
											2012-05-07 18:54:16 -03:00
										 |  |  | 			   struct ins_operands *ops) | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	if (ops->target.name) | 
					
						
							|  |  |  | 		return scnprintf(bf, size, "%-6.6s %s", ins->name, ops->target.name); | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-11 12:28:55 -03:00
										 |  |  | 	if (ops->target.addr == 0) | 
					
						
							|  |  |  | 		return ins__raw_scnprintf(ins, bf, size, ops); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	return scnprintf(bf, size, "%-6.6s *%" PRIx64, ins->name, ops->target.addr); | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-18 16:07:38 -03:00
										 |  |  | static struct ins_ops call_ops = { | 
					
						
							| 
									
										
										
										
											2012-04-20 15:26:47 -03:00
										 |  |  | 	.parse	   = call__parse, | 
					
						
							|  |  |  | 	.scnprintf = call__scnprintf, | 
					
						
							| 
									
										
										
										
											2012-04-18 16:07:38 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ins__is_call(const struct ins *ins) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ins->ops == &call_ops; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | static int jump__parse(struct ins_operands *ops) | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | 	const char *s = strchr(ops->raw, '+'); | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-25 14:16:03 -03:00
										 |  |  | 	ops->target.addr = strtoll(ops->raw, NULL, 16); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s++ != NULL) | 
					
						
							|  |  |  | 		ops->target.offset = strtoll(s, NULL, 16); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ops->target.offset = UINT64_MAX; | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | static int jump__scnprintf(struct ins *ins, char *bf, size_t size, | 
					
						
							| 
									
										
										
										
											2012-05-07 18:54:16 -03:00
										 |  |  | 			   struct ins_operands *ops) | 
					
						
							| 
									
										
										
										
											2012-04-19 10:16:27 -03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-25 08:00:23 -03:00
										 |  |  | 	return scnprintf(bf, size, "%-6.6s %" PRIx64, ins->name, ops->target.offset); | 
					
						
							| 
									
										
										
										
											2012-04-19 10:16:27 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | static struct ins_ops jump_ops = { | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | 	.parse	   = jump__parse, | 
					
						
							|  |  |  | 	.scnprintf = jump__scnprintf, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | bool ins__is_jump(const struct ins *ins) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return ins->ops == &jump_ops; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 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); | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | static int lock__parse(struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); | 
					
						
							|  |  |  | 	if (ops->locked.ops == NULL) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) | 
					
						
							|  |  |  | 		goto out_free_ops; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-10 02:27:13 +09:00
										 |  |  | 	ops->locked.ins = ins__find(name); | 
					
						
							|  |  |  | 	if (ops->locked.ins == NULL) | 
					
						
							|  |  |  | 		goto out_free_ops; | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-10 02:27:13 +09:00
										 |  |  | 	if (!ops->locked.ins->ops) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-10 02:27:13 +09:00
										 |  |  | 	if (ops->locked.ins->ops->parse) | 
					
						
							|  |  |  | 		ops->locked.ins->ops->parse(ops->locked.ops); | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out_free_ops: | 
					
						
							|  |  |  | 	free(ops->locked.ops); | 
					
						
							|  |  |  | 	ops->locked.ops = NULL; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | 
					
						
							|  |  |  | 			   struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int printed; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ops->locked.ins == NULL) | 
					
						
							|  |  |  | 		return ins__raw_scnprintf(ins, bf, size, ops); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	printed = scnprintf(bf, size, "%-6.6s ", ins->name); | 
					
						
							|  |  |  | 	return printed + ins__scnprintf(ops->locked.ins, bf + printed, | 
					
						
							|  |  |  | 					size - printed, ops->locked.ops); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-12 13:26:20 -03:00
										 |  |  | static void lock__delete(struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	free(ops->locked.ops); | 
					
						
							|  |  |  | 	free(ops->target.raw); | 
					
						
							|  |  |  | 	free(ops->target.name); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | static struct ins_ops lock_ops = { | 
					
						
							| 
									
										
										
										
											2012-05-12 13:26:20 -03:00
										 |  |  | 	.free	   = lock__delete, | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 	.parse	   = lock__parse, | 
					
						
							|  |  |  | 	.scnprintf = lock__scnprintf, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | static int mov__parse(struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *s = strchr(ops->raw, ','), *target, *comment, prev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (s == NULL) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*s = '\0'; | 
					
						
							|  |  |  | 	ops->source.raw = strdup(ops->raw); | 
					
						
							|  |  |  | 	*s = ','; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if (ops->source.raw == NULL) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	target = ++s; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (s[0] != '\0' && !isspace(s[0])) | 
					
						
							|  |  |  | 		++s; | 
					
						
							|  |  |  | 	prev = *s; | 
					
						
							|  |  |  | 	*s = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ops->target.raw = strdup(target); | 
					
						
							|  |  |  | 	*s = prev; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (ops->target.raw == NULL) | 
					
						
							|  |  |  | 		goto out_free_source; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	comment = strchr(s, '#'); | 
					
						
							|  |  |  | 	if (comment == NULL) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (comment[0] != '\0' && isspace(comment[0])) | 
					
						
							|  |  |  | 		++comment; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	comment__symbol(ops->source.raw, comment, &ops->source.addr, &ops->source.name); | 
					
						
							|  |  |  | 	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out_free_source: | 
					
						
							|  |  |  | 	free(ops->source.raw); | 
					
						
							|  |  |  | 	ops->source.raw = NULL; | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int mov__scnprintf(struct ins *ins, char *bf, size_t size, | 
					
						
							|  |  |  | 			   struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return scnprintf(bf, size, "%-6.6s %s,%s", ins->name, | 
					
						
							|  |  |  | 			 ops->source.name ?: ops->source.raw, | 
					
						
							|  |  |  | 			 ops->target.name ?: ops->target.raw); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ins_ops mov_ops = { | 
					
						
							|  |  |  | 	.parse	   = mov__parse, | 
					
						
							|  |  |  | 	.scnprintf = mov__scnprintf, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-11 17:21:09 -03:00
										 |  |  | static int dec__parse(struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	comment = strchr(s, '#'); | 
					
						
							|  |  |  | 	if (comment == NULL) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (comment[0] != '\0' && isspace(comment[0])) | 
					
						
							|  |  |  | 		++comment; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	comment__symbol(ops->target.raw, comment, &ops->target.addr, &ops->target.name); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int dec__scnprintf(struct ins *ins, char *bf, size_t size, | 
					
						
							|  |  |  | 			   struct ins_operands *ops) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return scnprintf(bf, size, "%-6.6s %s", ins->name, | 
					
						
							|  |  |  | 			 ops->target.name ?: ops->target.raw); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ins_ops dec_ops = { | 
					
						
							|  |  |  | 	.parse	   = dec__parse, | 
					
						
							|  |  |  | 	.scnprintf = dec__scnprintf, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-11 01:15:03 +03:00
										 |  |  | static int nop__scnprintf(struct ins *ins __maybe_unused, char *bf, size_t size, | 
					
						
							|  |  |  | 			  struct ins_operands *ops __maybe_unused) | 
					
						
							| 
									
										
										
										
											2012-05-07 18:57:02 -03:00
										 |  |  | { | 
					
						
							|  |  |  | 	return scnprintf(bf, size, "%-6.6s", "nop"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static struct ins_ops nop_ops = { | 
					
						
							|  |  |  | 	.scnprintf = nop__scnprintf, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Must be sorted by name! | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static struct ins instructions[] = { | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 	{ .name = "add",   .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "addl",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "addq",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "addw",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "and",   .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 	{ .name = "bts",   .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 16:07:38 -03:00
										 |  |  | 	{ .name = "call",  .ops  = &call_ops, }, | 
					
						
							|  |  |  | 	{ .name = "callq", .ops  = &call_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 	{ .name = "cmp",   .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "cmpb",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "cmpl",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "cmpq",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "cmpw",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "cmpxch", .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 17:21:09 -03:00
										 |  |  | 	{ .name = "dec",   .ops  = &dec_ops, }, | 
					
						
							|  |  |  | 	{ .name = "decl",  .ops  = &dec_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 	{ .name = "imul",  .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 17:21:09 -03:00
										 |  |  | 	{ .name = "inc",   .ops  = &dec_ops, }, | 
					
						
							|  |  |  | 	{ .name = "incl",  .ops  = &dec_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 	{ .name = "ja",	   .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-19 17:10:12 -03:00
										 |  |  | 	{ .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, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 	{ .name = "je",	   .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-19 17:10:12 -03:00
										 |  |  | 	{ .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, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 	{ .name = "jmp",   .ops  = &jump_ops, }, | 
					
						
							|  |  |  | 	{ .name = "jmpq",  .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-19 17:10:12 -03:00
										 |  |  | 	{ .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, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 	{ .name = "jne",   .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-19 17:10:12 -03:00
										 |  |  | 	{ .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, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 	{ .name = "js",	   .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-19 17:10:12 -03:00
										 |  |  | 	{ .name = "jz",	   .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 	{ .name = "lea",   .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 	{ .name = "lock",  .ops  = &lock_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 	{ .name = "mov",   .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movb",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movdqa",.ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movl",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movq",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movslq", .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movzbl", .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "movzwl", .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-07 18:57:02 -03:00
										 |  |  | 	{ .name = "nop",   .ops  = &nop_ops, }, | 
					
						
							|  |  |  | 	{ .name = "nopl",  .ops  = &nop_ops, }, | 
					
						
							|  |  |  | 	{ .name = "nopw",  .ops  = &nop_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-11 16:48:49 -03:00
										 |  |  | 	{ .name = "or",    .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "orl",   .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "test",  .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "testb", .ops  = &mov_ops, }, | 
					
						
							|  |  |  | 	{ .name = "testl", .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 	{ .name = "xadd",  .ops  = &mov_ops, }, | 
					
						
							| 
									
										
										
										
											2012-10-30 17:34:08 -07:00
										 |  |  | 	{ .name = "xbeginl", .ops  = &jump_ops, }, | 
					
						
							|  |  |  | 	{ .name = "xbeginq", .ops  = &jump_ops, }, | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-11 01:15:03 +03:00
										 |  |  | int symbol__annotate_init(struct map *map __maybe_unused, struct symbol *sym) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	pthread_mutex_init(¬es->lock, NULL); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-11 22:17:32 -02:00
										 |  |  | int symbol__alloc_hist(struct symbol *sym) | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2012-04-19 10:57:06 -03:00
										 |  |  | 	const size_t size = symbol__size(sym); | 
					
						
							| 
									
										
										
										
											2012-07-19 20:05:25 -07:00
										 |  |  | 	size_t sizeof_sym_hist; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Check for overflow when calculating sizeof_sym_hist */ | 
					
						
							|  |  |  | 	if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* Check for overflow in zalloc argument */ | 
					
						
							|  |  |  | 	if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) | 
					
						
							|  |  |  | 				/ symbol_conf.nr_events) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-11 22:17:32 -02:00
										 |  |  | 	notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	if (notes->src == NULL) | 
					
						
							|  |  |  | 		return -1; | 
					
						
							|  |  |  | 	notes->src->sizeof_sym_hist = sizeof_sym_hist; | 
					
						
							| 
									
										
										
										
											2011-11-11 22:17:32 -02:00
										 |  |  | 	notes->src->nr_histograms   = symbol_conf.nr_events; | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	INIT_LIST_HEAD(¬es->src->source); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | void symbol__annotate_zero_histograms(struct symbol *sym) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	pthread_mutex_lock(¬es->lock); | 
					
						
							|  |  |  | 	if (notes->src != NULL) | 
					
						
							|  |  |  | 		memset(notes->src->histograms, 0, | 
					
						
							|  |  |  | 		       notes->src->nr_histograms * notes->src->sizeof_sym_hist); | 
					
						
							|  |  |  | 	pthread_mutex_unlock(¬es->lock); | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | int symbol__inc_addr_samples(struct symbol *sym, struct map *map, | 
					
						
							|  |  |  | 			     int evidx, u64 addr) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 	unsigned offset; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	struct annotation *notes; | 
					
						
							|  |  |  | 	struct sym_hist *h; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	if (notes->src == NULL) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug3("%s: addr=%#" PRIx64 "\n", __func__, map->unmap_ip(map, addr)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-27 12:55:57 -03:00
										 |  |  | 	if (addr < sym->start || addr > sym->end) | 
					
						
							|  |  |  | 		return -ERANGE; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 	offset = addr - sym->start; | 
					
						
							|  |  |  | 	h = annotation__histogram(notes, evidx); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	h->sum++; | 
					
						
							|  |  |  | 	h->addr[offset]++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug3("%#" PRIx64 " %s: period++ [addr: %#" PRIx64 ", %#" PRIx64 | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 		  ", evidx=%d] => %" PRIu64 "\n", sym->start, sym->name, | 
					
						
							|  |  |  | 		  addr, addr - sym->start, evidx, h->addr[offset]); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | 	if (dl->ins->ops->parse) | 
					
						
							|  |  |  | 		dl->ins->ops->parse(&dl->ops); | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | static int disasm_line__parse(char *line, char **namep, char **rawp) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char *name = line, tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (isspace(name[0])) | 
					
						
							|  |  |  | 		++name; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if ((*rawp)[0] != '\0') { | 
					
						
							|  |  |  | 		(*rawp)++; | 
					
						
							|  |  |  | 		while (isspace((*rawp)[0])) | 
					
						
							|  |  |  | 			++(*rawp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | out_free_name: | 
					
						
							|  |  |  | 	free(*namep); | 
					
						
							|  |  |  | 	*namep = NULL; | 
					
						
							|  |  |  | 	return -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 	struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	if (dl != NULL) { | 
					
						
							|  |  |  | 		dl->offset = offset; | 
					
						
							|  |  |  | 		dl->line = strdup(line); | 
					
						
							|  |  |  | 		if (dl->line == NULL) | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 			goto out_delete; | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (offset != -1) { | 
					
						
							| 
									
										
										
										
											2012-05-12 13:15:34 -03:00
										 |  |  | 			if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 				goto out_free_line; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-18 13:58:34 -03:00
										 |  |  | 			disasm_line__init_ins(dl); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	return dl; | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | out_free_line: | 
					
						
							|  |  |  | 	free(dl->line); | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | out_delete: | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	free(dl); | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 	return NULL; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | void disasm_line__free(struct disasm_line *dl) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	free(dl->line); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 	free(dl->name); | 
					
						
							| 
									
										
										
										
											2012-05-12 13:26:20 -03:00
										 |  |  | 	if (dl->ins && dl->ins->ops->free) | 
					
						
							|  |  |  | 		dl->ins->ops->free(&dl->ops); | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		ins__delete(&dl->ops); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	free(dl); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-05-07 18:54:16 -03:00
										 |  |  | int disasm_line__scnprintf(struct disasm_line *dl, char *bf, size_t size, bool raw) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (raw || !dl->ins) | 
					
						
							|  |  |  | 		return scnprintf(bf, size, "%-6.6s %s", dl->name, dl->ops.raw); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ins__scnprintf(dl->ins, bf, size, &dl->ops); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | static void disasm__add(struct list_head *head, struct disasm_line *line) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	list_add_tail(&line->node, head); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | struct disasm_line *disasm__get_next_ip_line(struct list_head *head, struct disasm_line *pos) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	list_for_each_entry_continue(pos, head, node) | 
					
						
							|  |  |  | 		if (pos->offset >= 0) | 
					
						
							|  |  |  | 			return pos; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 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) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	static const char *prev_line; | 
					
						
							|  |  |  | 	static const char *prev_color; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	if (dl->offset != -1) { | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		const char *path = NULL; | 
					
						
							|  |  |  | 		unsigned int hits = 0; | 
					
						
							|  |  |  | 		double percent = 0.0; | 
					
						
							|  |  |  | 		const char *color; | 
					
						
							|  |  |  | 		struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 		struct source_line *src_line = notes->src->lines; | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 		struct sym_hist *h = annotation__histogram(notes, evidx); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		s64 offset = dl->offset; | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 		const u64 addr = start + offset; | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		struct disasm_line *next; | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		next = disasm__get_next_ip_line(¬es->src->source, dl); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-05 15:37:31 -02:00
										 |  |  | 		if (percent < min_pcnt) | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 			return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 15:01:39 -02:00
										 |  |  | 		if (max_lines && printed >= max_lines) | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 			return 1; | 
					
						
							| 
									
										
										
										
											2011-02-05 15:37:31 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 		if (queue != NULL) { | 
					
						
							|  |  |  | 			list_for_each_entry_from(queue, ¬es->src->source, node) { | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 				if (queue == dl) | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 				disasm_line__print(queue, sym, start, evidx, len, | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 						    0, 0, 1, NULL); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		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(" :	"); | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 		color_fprintf(stdout, PERF_COLOR_MAGENTA, "  %" PRIx64 ":", addr); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", dl->line); | 
					
						
							| 
									
										
										
										
											2011-02-08 15:01:39 -02:00
										 |  |  | 	} else if (max_lines && printed >= max_lines) | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 		return 1; | 
					
						
							|  |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 		if (queue) | 
					
						
							|  |  |  | 			return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		if (!*dl->line) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 			printf("         :\n"); | 
					
						
							|  |  |  | 		else | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 			printf("         :	%s\n", dl->line); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | static int symbol__parse_objdump_line(struct symbol *sym, struct map *map, | 
					
						
							|  |  |  | 				      FILE *file, size_t privsize) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	struct disasm_line *dl; | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 	char *line = NULL, *parsed_line, *tmp, *tmp2, *c; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2012-04-11 17:04:59 -03:00
										 |  |  | 	parsed_line = line; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	/*
 | 
					
						
							|  |  |  | 	 * 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; | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 		else | 
					
						
							|  |  |  | 			parsed_line = tmp2 + 1; | 
					
						
							| 
									
										
										
										
											2012-04-11 17:04:59 -03:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	dl = disasm_line__new(offset, parsed_line, privsize); | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 	free(line); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	if (dl == NULL) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		return -1; | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	disasm__add(¬es->src->source, dl); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-22 14:14:32 +02:00
										 |  |  | 	if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { | 
					
						
							| 
									
										
										
										
											2011-02-23 11:08:59 -03:00
										 |  |  | 		char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; | 
					
						
							|  |  |  | 		char *build_id_msg = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		if (dso->annotate_warned) | 
					
						
							|  |  |  | 			goto out_free_filename; | 
					
						
							| 
									
										
										
										
											2011-02-23 11:08:59 -03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (dso->has_build_id) { | 
					
						
							|  |  |  | 			build_id__sprintf(dso->build_id, | 
					
						
							|  |  |  | 					  sizeof(dso->build_id), bf + 15); | 
					
						
							|  |  |  | 			build_id_msg = bf; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		err = -ENOENT; | 
					
						
							|  |  |  | 		dso->annotate_warned = 1; | 
					
						
							| 
									
										
										
										
											2011-10-26 08:00:55 -02:00
										 |  |  | 		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" | 
					
						
							| 
									
										
										
										
											2012-02-23 17:46:24 +09:00
										 |  |  | 		       "  --vmlinux vmlinux\n", | 
					
						
							| 
									
										
										
										
											2011-02-23 11:08:59 -03:00
										 |  |  | 		       sym->name, build_id_msg ?: ""); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		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), | 
					
						
							| 
									
										
										
										
											2012-09-04 12:32:30 +02:00
										 |  |  | 		 "%s %s%s --start-address=0x%016" PRIx64 | 
					
						
							| 
									
										
										
										
											2011-05-17 17:32:07 +02:00
										 |  |  | 		 " --stop-address=0x%016" PRIx64 | 
					
						
							|  |  |  | 		 " -d %s %s -C %s|grep -v %s|expand", | 
					
						
							| 
									
										
										
										
											2012-09-04 12:32:30 +02:00
										 |  |  | 		 objdump_path ? objdump_path : "objdump", | 
					
						
							| 
									
										
										
										
											2011-09-15 14:31:41 -07:00
										 |  |  | 		 disassembler_style ? "-M " : "", | 
					
						
							|  |  |  | 		 disassembler_style ? disassembler_style : "", | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		 map__rip_2objdump(map, sym->start), | 
					
						
							| 
									
										
											  
											
												perf tools: Fix truncated annotation
I get such truncated annotation results in 'perf top':
         :        Disassembly of section .text:                                                   ▒
         :                                                                                        ▒
         :        ffffffff810966a8 <nr_iowait_cpu>:                                               ▒
    4.94 :        ffffffff810966a8:       movslq %edi,%rdi                                        ▒
    3.70 :        ffffffff810966ab:       mov    $0x13700,%rax                                    ▒
    0.00 :        ffffffff810966b2:       add    -0x7e32cb00(,%rdi,8),%rax                        ▒
    8.64 :        ffffffff810966ba:       mov    0x7e0(%rax),%eax                                 ▒
   82.72 :        ffffffff810966c0:       cltq                                                    ▒
Note the missing 'retq' which is there in the original function:
ffffffff810966a8 <nr_iowait_cpu>:
ffffffff810966a8:       48 63 ff                movslq %edi,%rdi
ffffffff810966ab:       48 c7 c0 00 37 01 00    mov    $0x13700,%rax
ffffffff810966b2:       48 03 04 fd 00 35 cd    add    -0x7e32cb00(,%rdi,8),%rax
ffffffff810966b9:       81
ffffffff810966ba:       8b 80 e0 07 00 00       mov    0x7e0(%rax),%eax
ffffffff810966c0:       48 98                   cltq
ffffffff810966c2:       c3                      retq
ffffffff810966c3 <this_cpu_load>:
I'm using a fairly recent binutils:
  GNU objdump version 2.21.51.0.6-2.fc16 20110118
AFAICS the bug is simply that sym->end points to the last byte
of the symbol in question - while objdump's --stop-address
expects the last byte plus 1 to disassemble the full range.
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20111223130804.GA24305@elte.hu
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
											
										 
											2011-12-23 14:08:04 +01:00
										 |  |  | 		 map__rip_2objdump(map, sym->end+1), | 
					
						
							| 
									
										
										
										
											2011-05-17 17:32:07 +02:00
										 |  |  | 		 symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", | 
					
						
							|  |  |  | 		 symbol_conf.annotate_src ? "-S" : "", | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		 symfs_filename, filename); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pr_debug("Executing: %s\n", command); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	file = popen(command, "r"); | 
					
						
							|  |  |  | 	if (!file) | 
					
						
							|  |  |  | 		goto out_free_filename; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while (!feof(file)) | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 		if (symbol__parse_objdump_line(sym, map, file, privsize) < 0) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | 	int ret; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while (*p != NULL) { | 
					
						
							|  |  |  | 		parent = *p; | 
					
						
							|  |  |  | 		iter = rb_entry(parent, struct source_line, node); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | 		ret = strcmp(iter->path, src_line->path); | 
					
						
							|  |  |  | 		if (ret == 0) { | 
					
						
							|  |  |  | 			iter->percent_sum += src_line->percent; | 
					
						
							|  |  |  | 			return; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (ret < 0) | 
					
						
							|  |  |  | 			p = &(*p)->rb_left; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			p = &(*p)->rb_right; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	src_line->percent_sum = src_line->percent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rb_link_node(&src_line->node, parent, p); | 
					
						
							|  |  |  | 	rb_insert_color(&src_line->node, root); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void __resort_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_sum > iter->percent_sum) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 			p = &(*p)->rb_left; | 
					
						
							|  |  |  | 		else | 
					
						
							|  |  |  | 			p = &(*p)->rb_right; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	rb_link_node(&src_line->node, parent, p); | 
					
						
							|  |  |  | 	rb_insert_color(&src_line->node, root); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct source_line *src_line; | 
					
						
							|  |  |  | 	struct rb_node *node; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	node = rb_first(src_root); | 
					
						
							|  |  |  | 	while (node) { | 
					
						
							|  |  |  | 		struct rb_node *next; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		src_line = rb_entry(node, struct source_line, node); | 
					
						
							|  |  |  | 		next = rb_next(node); | 
					
						
							|  |  |  | 		rb_erase(node, src_root); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		__resort_source_line(dest_root, src_line); | 
					
						
							|  |  |  | 		node = next; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | static void symbol__free_source_line(struct symbol *sym, int len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	struct source_line *src_line = notes->src->lines; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for (i = 0; i < len; i++) | 
					
						
							|  |  |  | 		free(src_line[i].path); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	free(src_line); | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	notes->src->lines = NULL; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Get the filename:line for the colored entries */ | 
					
						
							|  |  |  | static int symbol__get_source_line(struct symbol *sym, struct map *map, | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 				   int evidx, struct rb_root *root, int len, | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 				   const char *filename) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	u64 start; | 
					
						
							|  |  |  | 	int i; | 
					
						
							|  |  |  | 	char cmd[PATH_MAX * 2]; | 
					
						
							|  |  |  | 	struct source_line *src_line; | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 	struct sym_hist *h = annotation__histogram(notes, evidx); | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | 	struct rb_root tmp_root = RB_ROOT; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!h->sum) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	src_line = notes->src->lines = calloc(len, sizeof(struct source_line)); | 
					
						
							|  |  |  | 	if (!notes->src->lines) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-25 16:28:12 -04:00
										 |  |  | 	start = map__rip_2objdump(map, sym->start); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | 		insert_source_line(&tmp_root, &src_line[i]); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	next: | 
					
						
							|  |  |  | 		pclose(fp); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | 	resort_source_line(root, &tmp_root); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2012-11-09 14:58:49 +09:00
										 |  |  | 		percent = src_line->percent_sum; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 		color = get_percent_color(percent); | 
					
						
							|  |  |  | 		path = src_line->path; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		color_fprintf(stdout, color, " %7.2f %s", percent, path); | 
					
						
							|  |  |  | 		node = rb_next(node); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | static void symbol__annotate_hits(struct symbol *sym, int evidx) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 	struct sym_hist *h = annotation__histogram(notes, evidx); | 
					
						
							| 
									
										
										
										
											2012-04-19 10:57:06 -03:00
										 |  |  | 	u64 len = symbol__size(sym), offset; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | int symbol__annotate_printf(struct symbol *sym, struct map *map, int evidx, | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 			    bool full_paths, int min_pcnt, int max_lines, | 
					
						
							|  |  |  | 			    int context) | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct dso *dso = map->dso; | 
					
						
							| 
									
										
										
										
											2012-09-08 09:06:50 -06:00
										 |  |  | 	char *filename; | 
					
						
							|  |  |  | 	const char *d_filename; | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	struct disasm_line *pos, *queue = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 	u64 start = map__rip_2objdump(map, sym->start); | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 	int printed = 2, queue_len = 0; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 	int more = 0; | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	u64 len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 09:06:50 -06:00
										 |  |  | 	filename = strdup(dso->long_name); | 
					
						
							|  |  |  | 	if (!filename) | 
					
						
							|  |  |  | 		return -ENOMEM; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	if (full_paths) | 
					
						
							|  |  |  | 		d_filename = filename; | 
					
						
							|  |  |  | 	else | 
					
						
							|  |  |  | 		d_filename = basename(filename); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 10:57:06 -03:00
										 |  |  | 	len = symbol__size(sym); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	printf(" Percent |	Source code & Disassembly of %s\n", d_filename); | 
					
						
							|  |  |  | 	printf("------------------------------------------------\n"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (verbose) | 
					
						
							| 
									
										
										
										
											2011-02-04 13:43:24 -02:00
										 |  |  | 		symbol__annotate_hits(sym, evidx); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	list_for_each_entry(pos, ¬es->src->source, node) { | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 		if (context && queue == NULL) { | 
					
						
							|  |  |  | 			queue = pos; | 
					
						
							|  |  |  | 			queue_len = 0; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		switch (disasm_line__print(pos, sym, start, evidx, len, | 
					
						
							| 
									
										
										
										
											2012-04-02 12:59:01 -03:00
										 |  |  | 					    min_pcnt, printed, max_lines, | 
					
						
							|  |  |  | 					    queue)) { | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 		case 0: | 
					
						
							|  |  |  | 			++printed; | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 			if (context) { | 
					
						
							|  |  |  | 				printed += queue_len; | 
					
						
							|  |  |  | 				queue = NULL; | 
					
						
							|  |  |  | 				queue_len = 0; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		case 1: | 
					
						
							|  |  |  | 			/* filtered by max_lines */ | 
					
						
							|  |  |  | 			++more; | 
					
						
							| 
									
										
										
										
											2011-02-05 15:37:31 -02:00
										 |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 		case -1: | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 			/*
 | 
					
						
							|  |  |  | 			 * 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; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 09:06:50 -06:00
										 |  |  | 	free(filename); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 	return more; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | void symbol__annotate_zero_histogram(struct symbol *sym, int evidx) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							|  |  |  | 	struct sym_hist *h = annotation__histogram(notes, evidx); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	memset(h, 0, notes->src->sizeof_sym_hist); | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | void symbol__annotate_decay_histogram(struct symbol *sym, int evidx) | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct annotation *notes = symbol__annotation(sym); | 
					
						
							|  |  |  | 	struct sym_hist *h = annotation__histogram(notes, evidx); | 
					
						
							| 
									
										
										
										
											2012-04-19 10:57:06 -03:00
										 |  |  | 	int len = symbol__size(sym), offset; | 
					
						
							| 
									
										
										
										
											2011-02-06 14:54:44 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	h->sum = 0; | 
					
						
							| 
									
										
										
										
											2012-04-05 16:15:59 -03:00
										 |  |  | 	for (offset = 0; offset < len; ++offset) { | 
					
						
							|  |  |  | 		h->addr[offset] = h->addr[offset] * 7 / 8; | 
					
						
							|  |  |  | 		h->sum += h->addr[offset]; | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | void disasm__purge(struct list_head *head) | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	struct disasm_line *pos, *n; | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	list_for_each_entry_safe(pos, n, head, node) { | 
					
						
							|  |  |  | 		list_del(&pos->node); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 		disasm_line__free(pos); | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | 	if (dl->ops.raw[0] != '\0') { | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ", | 
					
						
							| 
									
										
										
										
											2012-04-20 14:38:46 -03:00
										 |  |  | 				   dl->ops.raw); | 
					
						
							| 
									
										
										
										
											2012-04-15 15:52:18 -03:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	if (symbol__annotate(sym, map, 0) < 0) | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 		return -1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 10:57:06 -03:00
										 |  |  | 	len = symbol__size(sym); | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (print_lines) { | 
					
						
							|  |  |  | 		symbol__get_source_line(sym, map, evidx, &source_line, | 
					
						
							|  |  |  | 					len, filename); | 
					
						
							|  |  |  | 		print_summary(&source_line, filename); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-08 13:27:39 -02:00
										 |  |  | 	symbol__annotate_printf(sym, map, evidx, full_paths, | 
					
						
							| 
									
										
										
										
											2011-02-08 15:29:25 -02:00
										 |  |  | 				min_pcnt, max_lines, 0); | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	if (print_lines) | 
					
						
							|  |  |  | 		symbol__free_source_line(sym, len); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-15 15:24:39 -03:00
										 |  |  | 	disasm__purge(&symbol__annotation(sym)->src->source); | 
					
						
							| 
									
										
										
										
											2011-02-05 18:51:38 -02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-02-04 09:45:46 -02:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | } |