blob: a9b42273675da16aad4b3122160ba91c2f6455c5 [file] [log] [blame]
Frederic Weisbecker66e274f2009-08-12 11:07:25 +02001#include "symbol.h"
2#include <stdlib.h>
3#include <string.h>
4#include <stdio.h>
Arnaldo Carvalho de Meloe4204992009-10-20 14:25:40 -02005#include "debug.h"
Frederic Weisbecker66e274f2009-08-12 11:07:25 +02006
Arnaldo Carvalho de Melo3846df22010-02-22 16:15:39 -03007const char *map_type__name[MAP__NR_TYPES] = {
8 [MAP__FUNCTION] = "Functions",
9 [MAP__VARIABLE] = "Variables",
10};
11
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020012static inline int is_anon_memory(const char *filename)
13{
14 return strcmp(filename, "//anon") == 0;
15}
16
17static int strcommon(const char *pathname, char *cwd, int cwdlen)
18{
19 int n = 0;
20
21 while (n < cwdlen && pathname[n] == cwd[n])
22 ++n;
23
24 return n;
25}
26
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020027void map__init(struct map *self, enum map_type type,
28 u64 start, u64 end, u64 pgoff, struct dso *dso)
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020029{
Arnaldo Carvalho de Melo36105832009-11-27 16:29:16 -020030 self->type = type;
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020031 self->start = start;
32 self->end = end;
33 self->pgoff = pgoff;
34 self->dso = dso;
35 self->map_ip = map__map_ip;
36 self->unmap_ip = map__unmap_ip;
37 RB_CLEAR_NODE(&self->rb_node);
38}
39
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030040struct map *map__new(u64 start, u64 len, u64 pgoff, u32 pid, char *filename,
41 enum map_type type, char *cwd, int cwdlen)
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020042{
43 struct map *self = malloc(sizeof(*self));
44
45 if (self != NULL) {
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020046 char newfilename[PATH_MAX];
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020047 struct dso *dso;
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020048 int anon;
49
50 if (cwd) {
51 int n = strcommon(filename, cwd, cwdlen);
52
53 if (n == cwdlen) {
54 snprintf(newfilename, sizeof(newfilename),
55 ".%s", filename + n);
56 filename = newfilename;
57 }
58 }
59
60 anon = is_anon_memory(filename);
61
62 if (anon) {
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030063 snprintf(newfilename, sizeof(newfilename), "/tmp/perf-%d.map", pid);
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020064 filename = newfilename;
65 }
66
Arnaldo Carvalho de Melo00a192b2009-10-30 16:28:24 -020067 dso = dsos__findnew(filename);
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020068 if (dso == NULL)
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020069 goto out_delete;
70
Arnaldo Carvalho de Melob177f632010-03-25 19:58:57 -030071 map__init(self, type, start, start + len, pgoff, dso);
Arnaldo Carvalho de Meloafb7b4f2009-10-30 16:28:23 -020072
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -020073 if (anon) {
74set_identity:
Arnaldo Carvalho de Meloed52ce22009-10-19 17:17:57 -020075 self->map_ip = self->unmap_ip = identity__map_ip;
Arnaldo Carvalho de Melo8d92c022010-02-03 16:52:02 -020076 } else if (strcmp(filename, "[vdso]") == 0) {
77 dso__set_loaded(dso, self->type);
78 goto set_identity;
79 }
Frederic Weisbecker66e274f2009-08-12 11:07:25 +020080 }
81 return self;
82out_delete:
83 free(self);
84 return NULL;
85}
86
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020087void map__delete(struct map *self)
88{
89 free(self);
90}
91
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -020092void map__fixup_start(struct map *self)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020093{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -020094 struct rb_root *symbols = &self->dso->symbols[self->type];
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -020095 struct rb_node *nd = rb_first(symbols);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -020096 if (nd != NULL) {
97 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
98 self->start = sym->start;
99 }
100}
101
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200102void map__fixup_end(struct map *self)
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200103{
Arnaldo Carvalho de Melo6a4694a2009-11-27 16:29:17 -0200104 struct rb_root *symbols = &self->dso->symbols[self->type];
Arnaldo Carvalho de Melofcf12032009-11-24 13:01:52 -0200105 struct rb_node *nd = rb_last(symbols);
Arnaldo Carvalho de Meloc338aee2009-11-20 20:51:27 -0200106 if (nd != NULL) {
107 struct symbol *sym = rb_entry(nd, struct symbol, rb_node);
108 self->end = sym->end;
109 }
110}
111
Arnaldo Carvalho de Melod70a5402009-10-30 16:28:25 -0200112#define DSO__DELETED "(deleted)"
113
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200114int map__load(struct map *self, symbol_filter_t filter)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200115{
116 const char *name = self->dso->long_name;
Masami Hiramatsua1281682009-12-15 10:32:33 -0500117 int nr;
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200118
Masami Hiramatsua1281682009-12-15 10:32:33 -0500119 if (dso__loaded(self->dso, self->type))
120 return 0;
121
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200122 nr = dso__load(self->dso, self, filter);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200123 if (nr < 0) {
124 if (self->dso->has_build_id) {
125 char sbuild_id[BUILD_ID_SIZE * 2 + 1];
126
127 build_id__sprintf(self->dso->build_id,
128 sizeof(self->dso->build_id),
129 sbuild_id);
130 pr_warning("%s with build id %s not found",
131 name, sbuild_id);
132 } else
133 pr_warning("Failed to open %s", name);
134
135 pr_warning(", continuing without symbols\n");
136 return -1;
137 } else if (nr == 0) {
138 const size_t len = strlen(name);
139 const size_t real_len = len - sizeof(DSO__DELETED);
140
141 if (len > sizeof(DSO__DELETED) &&
142 strcmp(name + real_len + 1, DSO__DELETED) == 0) {
143 pr_warning("%.*s was updated, restart the long "
144 "running apps that use it!\n",
145 (int)real_len, name);
146 } else {
147 pr_warning("no symbols found in %s, maybe install "
148 "a debug package?\n", name);
149 }
150
151 return -1;
152 }
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200153 /*
154 * Only applies to the kernel, as its symtabs aren't relative like the
155 * module ones.
156 */
157 if (self->dso->kernel)
158 map__reloc_vmlinux(self);
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200159
160 return 0;
161}
162
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200163struct symbol *map__find_symbol(struct map *self, u64 addr,
164 symbol_filter_t filter)
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200165{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200166 if (map__load(self, filter) < 0)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200167 return NULL;
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200168
Arnaldo Carvalho de Meloea08d8c2009-12-11 18:56:39 -0200169 return dso__find_symbol(self->dso, self->type, addr);
Arnaldo Carvalho de Melo66bd8422009-10-28 21:51:21 -0200170}
171
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200172struct symbol *map__find_symbol_by_name(struct map *self, const char *name,
173 symbol_filter_t filter)
174{
Arnaldo Carvalho de Melo9de89fe2010-02-03 16:52:00 -0200175 if (map__load(self, filter) < 0)
Arnaldo Carvalho de Melo79406cd2009-12-11 18:50:22 -0200176 return NULL;
177
178 if (!dso__sorted_by_name(self->dso, self->type))
179 dso__sort_by_name(self->dso, self->type);
180
181 return dso__find_symbol_by_name(self->dso, self->type, name);
182}
183
Frederic Weisbecker66e274f2009-08-12 11:07:25 +0200184struct map *map__clone(struct map *self)
185{
186 struct map *map = malloc(sizeof(*self));
187
188 if (!map)
189 return NULL;
190
191 memcpy(map, self, sizeof(*self));
192
193 return map;
194}
195
196int map__overlap(struct map *l, struct map *r)
197{
198 if (l->start > r->start) {
199 struct map *t = l;
200 l = r;
201 r = t;
202 }
203
204 if (l->end > r->start)
205 return 1;
206
207 return 0;
208}
209
210size_t map__fprintf(struct map *self, FILE *fp)
211{
212 return fprintf(fp, " %Lx-%Lx %Lx %s\n",
213 self->start, self->end, self->pgoff, self->dso->name);
214}
Kirill Smelkov7a2b6202010-02-03 16:52:07 -0200215
216/*
217 * objdump wants/reports absolute IPs for ET_EXEC, and RIPs for ET_DYN.
218 * map->dso->adjust_symbols==1 for ET_EXEC-like cases.
219 */
220u64 map__rip_2objdump(struct map *map, u64 rip)
221{
222 u64 addr = map->dso->adjust_symbols ?
223 map->unmap_ip(map, rip) : /* RIP -> IP */
224 rip;
225 return addr;
226}
Kirill Smelkovee11b902010-02-07 11:46:15 -0200227
228u64 map__objdump_2ip(struct map *map, u64 addr)
229{
230 u64 ip = map->dso->adjust_symbols ?
231 addr :
232 map->unmap_ip(map, addr); /* RIP -> IP */
233 return ip;
234}