diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /tools/perf/util/symbol.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 946 |
1 files changed, 577 insertions, 369 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index b2f5ae97f33d..eec196329fd9 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -11,6 +11,7 @@ | |||
11 | #include <sys/param.h> | 11 | #include <sys/param.h> |
12 | #include <fcntl.h> | 12 | #include <fcntl.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <inttypes.h> | ||
14 | #include "build-id.h" | 15 | #include "build-id.h" |
15 | #include "debug.h" | 16 | #include "debug.h" |
16 | #include "symbol.h" | 17 | #include "symbol.h" |
@@ -22,17 +23,21 @@ | |||
22 | #include <limits.h> | 23 | #include <limits.h> |
23 | #include <sys/utsname.h> | 24 | #include <sys/utsname.h> |
24 | 25 | ||
26 | #ifndef KSYM_NAME_LEN | ||
27 | #define KSYM_NAME_LEN 128 | ||
28 | #endif | ||
29 | |||
25 | #ifndef NT_GNU_BUILD_ID | 30 | #ifndef NT_GNU_BUILD_ID |
26 | #define NT_GNU_BUILD_ID 3 | 31 | #define NT_GNU_BUILD_ID 3 |
27 | #endif | 32 | #endif |
28 | 33 | ||
29 | static bool dso__build_id_equal(const struct dso *self, u8 *build_id); | 34 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); |
30 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); | 35 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); |
31 | static void dsos__add(struct list_head *head, struct dso *dso); | 36 | static void dsos__add(struct list_head *head, struct dso *dso); |
32 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 37 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
33 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 38 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
34 | symbol_filter_t filter); | 39 | symbol_filter_t filter); |
35 | static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, | 40 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
36 | symbol_filter_t filter); | 41 | symbol_filter_t filter); |
37 | static int vmlinux_path__nr_entries; | 42 | static int vmlinux_path__nr_entries; |
38 | static char **vmlinux_path; | 43 | static char **vmlinux_path; |
@@ -41,29 +46,30 @@ struct symbol_conf symbol_conf = { | |||
41 | .exclude_other = true, | 46 | .exclude_other = true, |
42 | .use_modules = true, | 47 | .use_modules = true, |
43 | .try_vmlinux_path = true, | 48 | .try_vmlinux_path = true, |
49 | .symfs = "", | ||
44 | }; | 50 | }; |
45 | 51 | ||
46 | int dso__name_len(const struct dso *self) | 52 | int dso__name_len(const struct dso *dso) |
47 | { | 53 | { |
48 | if (verbose) | 54 | if (verbose) |
49 | return self->long_name_len; | 55 | return dso->long_name_len; |
50 | 56 | ||
51 | return self->short_name_len; | 57 | return dso->short_name_len; |
52 | } | 58 | } |
53 | 59 | ||
54 | bool dso__loaded(const struct dso *self, enum map_type type) | 60 | bool dso__loaded(const struct dso *dso, enum map_type type) |
55 | { | 61 | { |
56 | return self->loaded & (1 << type); | 62 | return dso->loaded & (1 << type); |
57 | } | 63 | } |
58 | 64 | ||
59 | bool dso__sorted_by_name(const struct dso *self, enum map_type type) | 65 | bool dso__sorted_by_name(const struct dso *dso, enum map_type type) |
60 | { | 66 | { |
61 | return self->sorted_by_name & (1 << type); | 67 | return dso->sorted_by_name & (1 << type); |
62 | } | 68 | } |
63 | 69 | ||
64 | static void dso__set_sorted_by_name(struct dso *self, enum map_type type) | 70 | static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) |
65 | { | 71 | { |
66 | self->sorted_by_name |= (1 << type); | 72 | dso->sorted_by_name |= (1 << type); |
67 | } | 73 | } |
68 | 74 | ||
69 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 75 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
@@ -78,9 +84,9 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type) | |||
78 | } | 84 | } |
79 | } | 85 | } |
80 | 86 | ||
81 | static void symbols__fixup_end(struct rb_root *self) | 87 | static void symbols__fixup_end(struct rb_root *symbols) |
82 | { | 88 | { |
83 | struct rb_node *nd, *prevnd = rb_first(self); | 89 | struct rb_node *nd, *prevnd = rb_first(symbols); |
84 | struct symbol *curr, *prev; | 90 | struct symbol *curr, *prev; |
85 | 91 | ||
86 | if (prevnd == NULL) | 92 | if (prevnd == NULL) |
@@ -92,7 +98,7 @@ static void symbols__fixup_end(struct rb_root *self) | |||
92 | prev = curr; | 98 | prev = curr; |
93 | curr = rb_entry(nd, struct symbol, rb_node); | 99 | curr = rb_entry(nd, struct symbol, rb_node); |
94 | 100 | ||
95 | if (prev->end == prev->start) | 101 | if (prev->end == prev->start && prev->end != curr->start) |
96 | prev->end = curr->start - 1; | 102 | prev->end = curr->start - 1; |
97 | } | 103 | } |
98 | 104 | ||
@@ -101,10 +107,10 @@ static void symbols__fixup_end(struct rb_root *self) | |||
101 | curr->end = roundup(curr->start, 4096); | 107 | curr->end = roundup(curr->start, 4096); |
102 | } | 108 | } |
103 | 109 | ||
104 | static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) | 110 | static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) |
105 | { | 111 | { |
106 | struct map *prev, *curr; | 112 | struct map *prev, *curr; |
107 | struct rb_node *nd, *prevnd = rb_first(&self->maps[type]); | 113 | struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); |
108 | 114 | ||
109 | if (prevnd == NULL) | 115 | if (prevnd == NULL) |
110 | return; | 116 | return; |
@@ -121,132 +127,131 @@ static void __map_groups__fixup_end(struct map_groups *self, enum map_type type) | |||
121 | * We still haven't the actual symbols, so guess the | 127 | * We still haven't the actual symbols, so guess the |
122 | * last map final address. | 128 | * last map final address. |
123 | */ | 129 | */ |
124 | curr->end = ~0UL; | 130 | curr->end = ~0ULL; |
125 | } | 131 | } |
126 | 132 | ||
127 | static void map_groups__fixup_end(struct map_groups *self) | 133 | static void map_groups__fixup_end(struct map_groups *mg) |
128 | { | 134 | { |
129 | int i; | 135 | int i; |
130 | for (i = 0; i < MAP__NR_TYPES; ++i) | 136 | for (i = 0; i < MAP__NR_TYPES; ++i) |
131 | __map_groups__fixup_end(self, i); | 137 | __map_groups__fixup_end(mg, i); |
132 | } | 138 | } |
133 | 139 | ||
134 | static struct symbol *symbol__new(u64 start, u64 len, u8 binding, | 140 | static struct symbol *symbol__new(u64 start, u64 len, u8 binding, |
135 | const char *name) | 141 | const char *name) |
136 | { | 142 | { |
137 | size_t namelen = strlen(name) + 1; | 143 | size_t namelen = strlen(name) + 1; |
138 | struct symbol *self = calloc(1, (symbol_conf.priv_size + | 144 | struct symbol *sym = calloc(1, (symbol_conf.priv_size + |
139 | sizeof(*self) + namelen)); | 145 | sizeof(*sym) + namelen)); |
140 | if (self == NULL) | 146 | if (sym == NULL) |
141 | return NULL; | 147 | return NULL; |
142 | 148 | ||
143 | if (symbol_conf.priv_size) | 149 | if (symbol_conf.priv_size) |
144 | self = ((void *)self) + symbol_conf.priv_size; | 150 | sym = ((void *)sym) + symbol_conf.priv_size; |
145 | |||
146 | self->start = start; | ||
147 | self->end = len ? start + len - 1 : start; | ||
148 | self->binding = binding; | ||
149 | self->namelen = namelen - 1; | ||
150 | 151 | ||
151 | pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); | 152 | sym->start = start; |
153 | sym->end = len ? start + len - 1 : start; | ||
154 | sym->binding = binding; | ||
155 | sym->namelen = namelen - 1; | ||
152 | 156 | ||
153 | memcpy(self->name, name, namelen); | 157 | pr_debug4("%s: %s %#" PRIx64 "-%#" PRIx64 "\n", |
158 | __func__, name, start, sym->end); | ||
159 | memcpy(sym->name, name, namelen); | ||
154 | 160 | ||
155 | return self; | 161 | return sym; |
156 | } | 162 | } |
157 | 163 | ||
158 | void symbol__delete(struct symbol *self) | 164 | void symbol__delete(struct symbol *sym) |
159 | { | 165 | { |
160 | free(((void *)self) - symbol_conf.priv_size); | 166 | free(((void *)sym) - symbol_conf.priv_size); |
161 | } | 167 | } |
162 | 168 | ||
163 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 169 | static size_t symbol__fprintf(struct symbol *sym, FILE *fp) |
164 | { | 170 | { |
165 | return fprintf(fp, " %llx-%llx %c %s\n", | 171 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", |
166 | self->start, self->end, | 172 | sym->start, sym->end, |
167 | self->binding == STB_GLOBAL ? 'g' : | 173 | sym->binding == STB_GLOBAL ? 'g' : |
168 | self->binding == STB_LOCAL ? 'l' : 'w', | 174 | sym->binding == STB_LOCAL ? 'l' : 'w', |
169 | self->name); | 175 | sym->name); |
170 | } | 176 | } |
171 | 177 | ||
172 | void dso__set_long_name(struct dso *self, char *name) | 178 | void dso__set_long_name(struct dso *dso, char *name) |
173 | { | 179 | { |
174 | if (name == NULL) | 180 | if (name == NULL) |
175 | return; | 181 | return; |
176 | self->long_name = name; | 182 | dso->long_name = name; |
177 | self->long_name_len = strlen(name); | 183 | dso->long_name_len = strlen(name); |
178 | } | 184 | } |
179 | 185 | ||
180 | static void dso__set_short_name(struct dso *self, const char *name) | 186 | static void dso__set_short_name(struct dso *dso, const char *name) |
181 | { | 187 | { |
182 | if (name == NULL) | 188 | if (name == NULL) |
183 | return; | 189 | return; |
184 | self->short_name = name; | 190 | dso->short_name = name; |
185 | self->short_name_len = strlen(name); | 191 | dso->short_name_len = strlen(name); |
186 | } | 192 | } |
187 | 193 | ||
188 | static void dso__set_basename(struct dso *self) | 194 | static void dso__set_basename(struct dso *dso) |
189 | { | 195 | { |
190 | dso__set_short_name(self, basename(self->long_name)); | 196 | dso__set_short_name(dso, basename(dso->long_name)); |
191 | } | 197 | } |
192 | 198 | ||
193 | struct dso *dso__new(const char *name) | 199 | struct dso *dso__new(const char *name) |
194 | { | 200 | { |
195 | struct dso *self = calloc(1, sizeof(*self) + strlen(name) + 1); | 201 | struct dso *dso = calloc(1, sizeof(*dso) + strlen(name) + 1); |
196 | 202 | ||
197 | if (self != NULL) { | 203 | if (dso != NULL) { |
198 | int i; | 204 | int i; |
199 | strcpy(self->name, name); | 205 | strcpy(dso->name, name); |
200 | dso__set_long_name(self, self->name); | 206 | dso__set_long_name(dso, dso->name); |
201 | dso__set_short_name(self, self->name); | 207 | dso__set_short_name(dso, dso->name); |
202 | for (i = 0; i < MAP__NR_TYPES; ++i) | 208 | for (i = 0; i < MAP__NR_TYPES; ++i) |
203 | self->symbols[i] = self->symbol_names[i] = RB_ROOT; | 209 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; |
204 | self->slen_calculated = 0; | 210 | dso->symtab_type = SYMTAB__NOT_FOUND; |
205 | self->origin = DSO__ORIG_NOT_FOUND; | 211 | dso->loaded = 0; |
206 | self->loaded = 0; | 212 | dso->sorted_by_name = 0; |
207 | self->sorted_by_name = 0; | 213 | dso->has_build_id = 0; |
208 | self->has_build_id = 0; | 214 | dso->kernel = DSO_TYPE_USER; |
209 | self->kernel = DSO_TYPE_USER; | 215 | INIT_LIST_HEAD(&dso->node); |
210 | INIT_LIST_HEAD(&self->node); | ||
211 | } | 216 | } |
212 | 217 | ||
213 | return self; | 218 | return dso; |
214 | } | 219 | } |
215 | 220 | ||
216 | static void symbols__delete(struct rb_root *self) | 221 | static void symbols__delete(struct rb_root *symbols) |
217 | { | 222 | { |
218 | struct symbol *pos; | 223 | struct symbol *pos; |
219 | struct rb_node *next = rb_first(self); | 224 | struct rb_node *next = rb_first(symbols); |
220 | 225 | ||
221 | while (next) { | 226 | while (next) { |
222 | pos = rb_entry(next, struct symbol, rb_node); | 227 | pos = rb_entry(next, struct symbol, rb_node); |
223 | next = rb_next(&pos->rb_node); | 228 | next = rb_next(&pos->rb_node); |
224 | rb_erase(&pos->rb_node, self); | 229 | rb_erase(&pos->rb_node, symbols); |
225 | symbol__delete(pos); | 230 | symbol__delete(pos); |
226 | } | 231 | } |
227 | } | 232 | } |
228 | 233 | ||
229 | void dso__delete(struct dso *self) | 234 | void dso__delete(struct dso *dso) |
230 | { | 235 | { |
231 | int i; | 236 | int i; |
232 | for (i = 0; i < MAP__NR_TYPES; ++i) | 237 | for (i = 0; i < MAP__NR_TYPES; ++i) |
233 | symbols__delete(&self->symbols[i]); | 238 | symbols__delete(&dso->symbols[i]); |
234 | if (self->sname_alloc) | 239 | if (dso->sname_alloc) |
235 | free((char *)self->short_name); | 240 | free((char *)dso->short_name); |
236 | if (self->lname_alloc) | 241 | if (dso->lname_alloc) |
237 | free(self->long_name); | 242 | free(dso->long_name); |
238 | free(self); | 243 | free(dso); |
239 | } | 244 | } |
240 | 245 | ||
241 | void dso__set_build_id(struct dso *self, void *build_id) | 246 | void dso__set_build_id(struct dso *dso, void *build_id) |
242 | { | 247 | { |
243 | memcpy(self->build_id, build_id, sizeof(self->build_id)); | 248 | memcpy(dso->build_id, build_id, sizeof(dso->build_id)); |
244 | self->has_build_id = 1; | 249 | dso->has_build_id = 1; |
245 | } | 250 | } |
246 | 251 | ||
247 | static void symbols__insert(struct rb_root *self, struct symbol *sym) | 252 | static void symbols__insert(struct rb_root *symbols, struct symbol *sym) |
248 | { | 253 | { |
249 | struct rb_node **p = &self->rb_node; | 254 | struct rb_node **p = &symbols->rb_node; |
250 | struct rb_node *parent = NULL; | 255 | struct rb_node *parent = NULL; |
251 | const u64 ip = sym->start; | 256 | const u64 ip = sym->start; |
252 | struct symbol *s; | 257 | struct symbol *s; |
@@ -260,17 +265,17 @@ static void symbols__insert(struct rb_root *self, struct symbol *sym) | |||
260 | p = &(*p)->rb_right; | 265 | p = &(*p)->rb_right; |
261 | } | 266 | } |
262 | rb_link_node(&sym->rb_node, parent, p); | 267 | rb_link_node(&sym->rb_node, parent, p); |
263 | rb_insert_color(&sym->rb_node, self); | 268 | rb_insert_color(&sym->rb_node, symbols); |
264 | } | 269 | } |
265 | 270 | ||
266 | static struct symbol *symbols__find(struct rb_root *self, u64 ip) | 271 | static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) |
267 | { | 272 | { |
268 | struct rb_node *n; | 273 | struct rb_node *n; |
269 | 274 | ||
270 | if (self == NULL) | 275 | if (symbols == NULL) |
271 | return NULL; | 276 | return NULL; |
272 | 277 | ||
273 | n = self->rb_node; | 278 | n = symbols->rb_node; |
274 | 279 | ||
275 | while (n) { | 280 | while (n) { |
276 | struct symbol *s = rb_entry(n, struct symbol, rb_node); | 281 | struct symbol *s = rb_entry(n, struct symbol, rb_node); |
@@ -291,11 +296,13 @@ struct symbol_name_rb_node { | |||
291 | struct symbol sym; | 296 | struct symbol sym; |
292 | }; | 297 | }; |
293 | 298 | ||
294 | static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) | 299 | static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) |
295 | { | 300 | { |
296 | struct rb_node **p = &self->rb_node; | 301 | struct rb_node **p = &symbols->rb_node; |
297 | struct rb_node *parent = NULL; | 302 | struct rb_node *parent = NULL; |
298 | struct symbol_name_rb_node *symn = ((void *)sym) - sizeof(*parent), *s; | 303 | struct symbol_name_rb_node *symn, *s; |
304 | |||
305 | symn = container_of(sym, struct symbol_name_rb_node, sym); | ||
299 | 306 | ||
300 | while (*p != NULL) { | 307 | while (*p != NULL) { |
301 | parent = *p; | 308 | parent = *p; |
@@ -306,27 +313,29 @@ static void symbols__insert_by_name(struct rb_root *self, struct symbol *sym) | |||
306 | p = &(*p)->rb_right; | 313 | p = &(*p)->rb_right; |
307 | } | 314 | } |
308 | rb_link_node(&symn->rb_node, parent, p); | 315 | rb_link_node(&symn->rb_node, parent, p); |
309 | rb_insert_color(&symn->rb_node, self); | 316 | rb_insert_color(&symn->rb_node, symbols); |
310 | } | 317 | } |
311 | 318 | ||
312 | static void symbols__sort_by_name(struct rb_root *self, struct rb_root *source) | 319 | static void symbols__sort_by_name(struct rb_root *symbols, |
320 | struct rb_root *source) | ||
313 | { | 321 | { |
314 | struct rb_node *nd; | 322 | struct rb_node *nd; |
315 | 323 | ||
316 | for (nd = rb_first(source); nd; nd = rb_next(nd)) { | 324 | for (nd = rb_first(source); nd; nd = rb_next(nd)) { |
317 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | 325 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); |
318 | symbols__insert_by_name(self, pos); | 326 | symbols__insert_by_name(symbols, pos); |
319 | } | 327 | } |
320 | } | 328 | } |
321 | 329 | ||
322 | static struct symbol *symbols__find_by_name(struct rb_root *self, const char *name) | 330 | static struct symbol *symbols__find_by_name(struct rb_root *symbols, |
331 | const char *name) | ||
323 | { | 332 | { |
324 | struct rb_node *n; | 333 | struct rb_node *n; |
325 | 334 | ||
326 | if (self == NULL) | 335 | if (symbols == NULL) |
327 | return NULL; | 336 | return NULL; |
328 | 337 | ||
329 | n = self->rb_node; | 338 | n = symbols->rb_node; |
330 | 339 | ||
331 | while (n) { | 340 | while (n) { |
332 | struct symbol_name_rb_node *s; | 341 | struct symbol_name_rb_node *s; |
@@ -346,29 +355,29 @@ static struct symbol *symbols__find_by_name(struct rb_root *self, const char *na | |||
346 | return NULL; | 355 | return NULL; |
347 | } | 356 | } |
348 | 357 | ||
349 | struct symbol *dso__find_symbol(struct dso *self, | 358 | struct symbol *dso__find_symbol(struct dso *dso, |
350 | enum map_type type, u64 addr) | 359 | enum map_type type, u64 addr) |
351 | { | 360 | { |
352 | return symbols__find(&self->symbols[type], addr); | 361 | return symbols__find(&dso->symbols[type], addr); |
353 | } | 362 | } |
354 | 363 | ||
355 | struct symbol *dso__find_symbol_by_name(struct dso *self, enum map_type type, | 364 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
356 | const char *name) | 365 | const char *name) |
357 | { | 366 | { |
358 | return symbols__find_by_name(&self->symbol_names[type], name); | 367 | return symbols__find_by_name(&dso->symbol_names[type], name); |
359 | } | 368 | } |
360 | 369 | ||
361 | void dso__sort_by_name(struct dso *self, enum map_type type) | 370 | void dso__sort_by_name(struct dso *dso, enum map_type type) |
362 | { | 371 | { |
363 | dso__set_sorted_by_name(self, type); | 372 | dso__set_sorted_by_name(dso, type); |
364 | return symbols__sort_by_name(&self->symbol_names[type], | 373 | return symbols__sort_by_name(&dso->symbol_names[type], |
365 | &self->symbols[type]); | 374 | &dso->symbols[type]); |
366 | } | 375 | } |
367 | 376 | ||
368 | int build_id__sprintf(const u8 *self, int len, char *bf) | 377 | int build_id__sprintf(const u8 *build_id, int len, char *bf) |
369 | { | 378 | { |
370 | char *bid = bf; | 379 | char *bid = bf; |
371 | const u8 *raw = self; | 380 | const u8 *raw = build_id; |
372 | int i; | 381 | int i; |
373 | 382 | ||
374 | for (i = 0; i < len; ++i) { | 383 | for (i = 0; i < len; ++i) { |
@@ -377,29 +386,44 @@ int build_id__sprintf(const u8 *self, int len, char *bf) | |||
377 | bid += 2; | 386 | bid += 2; |
378 | } | 387 | } |
379 | 388 | ||
380 | return raw - self; | 389 | return raw - build_id; |
381 | } | 390 | } |
382 | 391 | ||
383 | size_t dso__fprintf_buildid(struct dso *self, FILE *fp) | 392 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) |
384 | { | 393 | { |
385 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 394 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
386 | 395 | ||
387 | build_id__sprintf(self->build_id, sizeof(self->build_id), sbuild_id); | 396 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
388 | return fprintf(fp, "%s", sbuild_id); | 397 | return fprintf(fp, "%s", sbuild_id); |
389 | } | 398 | } |
390 | 399 | ||
391 | size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) | 400 | size_t dso__fprintf_symbols_by_name(struct dso *dso, |
401 | enum map_type type, FILE *fp) | ||
402 | { | ||
403 | size_t ret = 0; | ||
404 | struct rb_node *nd; | ||
405 | struct symbol_name_rb_node *pos; | ||
406 | |||
407 | for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { | ||
408 | pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); | ||
409 | fprintf(fp, "%s\n", pos->sym.name); | ||
410 | } | ||
411 | |||
412 | return ret; | ||
413 | } | ||
414 | |||
415 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp) | ||
392 | { | 416 | { |
393 | struct rb_node *nd; | 417 | struct rb_node *nd; |
394 | size_t ret = fprintf(fp, "dso: %s (", self->short_name); | 418 | size_t ret = fprintf(fp, "dso: %s (", dso->short_name); |
395 | 419 | ||
396 | if (self->short_name != self->long_name) | 420 | if (dso->short_name != dso->long_name) |
397 | ret += fprintf(fp, "%s, ", self->long_name); | 421 | ret += fprintf(fp, "%s, ", dso->long_name); |
398 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], | 422 | ret += fprintf(fp, "%s, %sloaded, ", map_type__name[type], |
399 | self->loaded ? "" : "NOT "); | 423 | dso->loaded ? "" : "NOT "); |
400 | ret += dso__fprintf_buildid(self, fp); | 424 | ret += dso__fprintf_buildid(dso, fp); |
401 | ret += fprintf(fp, ")\n"); | 425 | ret += fprintf(fp, ")\n"); |
402 | for (nd = rb_first(&self->symbols[type]); nd; nd = rb_next(nd)) { | 426 | for (nd = rb_first(&dso->symbols[type]); nd; nd = rb_next(nd)) { |
403 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); | 427 | struct symbol *pos = rb_entry(nd, struct symbol, rb_node); |
404 | ret += symbol__fprintf(pos, fp); | 428 | ret += symbol__fprintf(pos, fp); |
405 | } | 429 | } |
@@ -409,16 +433,25 @@ size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp) | |||
409 | 433 | ||
410 | int kallsyms__parse(const char *filename, void *arg, | 434 | int kallsyms__parse(const char *filename, void *arg, |
411 | int (*process_symbol)(void *arg, const char *name, | 435 | int (*process_symbol)(void *arg, const char *name, |
412 | char type, u64 start)) | 436 | char type, u64 start, u64 end)) |
413 | { | 437 | { |
414 | char *line = NULL; | 438 | char *line = NULL; |
415 | size_t n; | 439 | size_t n; |
416 | int err = 0; | 440 | int err = -1; |
441 | u64 prev_start = 0; | ||
442 | char prev_symbol_type = 0; | ||
443 | char *prev_symbol_name; | ||
417 | FILE *file = fopen(filename, "r"); | 444 | FILE *file = fopen(filename, "r"); |
418 | 445 | ||
419 | if (file == NULL) | 446 | if (file == NULL) |
420 | goto out_failure; | 447 | goto out_failure; |
421 | 448 | ||
449 | prev_symbol_name = malloc(KSYM_NAME_LEN); | ||
450 | if (prev_symbol_name == NULL) | ||
451 | goto out_close; | ||
452 | |||
453 | err = 0; | ||
454 | |||
422 | while (!feof(file)) { | 455 | while (!feof(file)) { |
423 | u64 start; | 456 | u64 start; |
424 | int line_len, len; | 457 | int line_len, len; |
@@ -438,14 +471,33 @@ int kallsyms__parse(const char *filename, void *arg, | |||
438 | continue; | 471 | continue; |
439 | 472 | ||
440 | symbol_type = toupper(line[len]); | 473 | symbol_type = toupper(line[len]); |
441 | symbol_name = line + len + 2; | 474 | len += 2; |
475 | symbol_name = line + len; | ||
476 | len = line_len - len; | ||
442 | 477 | ||
443 | err = process_symbol(arg, symbol_name, symbol_type, start); | 478 | if (len >= KSYM_NAME_LEN) { |
444 | if (err) | 479 | err = -1; |
445 | break; | 480 | break; |
481 | } | ||
482 | |||
483 | if (prev_symbol_type) { | ||
484 | u64 end = start; | ||
485 | if (end != prev_start) | ||
486 | --end; | ||
487 | err = process_symbol(arg, prev_symbol_name, | ||
488 | prev_symbol_type, prev_start, end); | ||
489 | if (err) | ||
490 | break; | ||
491 | } | ||
492 | |||
493 | memcpy(prev_symbol_name, symbol_name, len + 1); | ||
494 | prev_symbol_type = symbol_type; | ||
495 | prev_start = start; | ||
446 | } | 496 | } |
447 | 497 | ||
498 | free(prev_symbol_name); | ||
448 | free(line); | 499 | free(line); |
500 | out_close: | ||
449 | fclose(file); | 501 | fclose(file); |
450 | return err; | 502 | return err; |
451 | 503 | ||
@@ -467,7 +519,7 @@ static u8 kallsyms2elf_type(char type) | |||
467 | } | 519 | } |
468 | 520 | ||
469 | static int map__process_kallsym_symbol(void *arg, const char *name, | 521 | static int map__process_kallsym_symbol(void *arg, const char *name, |
470 | char type, u64 start) | 522 | char type, u64 start, u64 end) |
471 | { | 523 | { |
472 | struct symbol *sym; | 524 | struct symbol *sym; |
473 | struct process_kallsyms_args *a = arg; | 525 | struct process_kallsyms_args *a = arg; |
@@ -476,11 +528,8 @@ static int map__process_kallsym_symbol(void *arg, const char *name, | |||
476 | if (!symbol_type__is_a(type, a->map->type)) | 528 | if (!symbol_type__is_a(type, a->map->type)) |
477 | return 0; | 529 | return 0; |
478 | 530 | ||
479 | /* | 531 | sym = symbol__new(start, end - start + 1, |
480 | * Will fix up the end later, when we have all symbols sorted. | 532 | kallsyms2elf_type(type), name); |
481 | */ | ||
482 | sym = symbol__new(start, 0, kallsyms2elf_type(type), name); | ||
483 | |||
484 | if (sym == NULL) | 533 | if (sym == NULL) |
485 | return -ENOMEM; | 534 | return -ENOMEM; |
486 | /* | 535 | /* |
@@ -497,10 +546,10 @@ static int map__process_kallsym_symbol(void *arg, const char *name, | |||
497 | * so that we can in the next step set the symbol ->end address and then | 546 | * so that we can in the next step set the symbol ->end address and then |
498 | * call kernel_maps__split_kallsyms. | 547 | * call kernel_maps__split_kallsyms. |
499 | */ | 548 | */ |
500 | static int dso__load_all_kallsyms(struct dso *self, const char *filename, | 549 | static int dso__load_all_kallsyms(struct dso *dso, const char *filename, |
501 | struct map *map) | 550 | struct map *map) |
502 | { | 551 | { |
503 | struct process_kallsyms_args args = { .map = map, .dso = self, }; | 552 | struct process_kallsyms_args args = { .map = map, .dso = dso, }; |
504 | return kallsyms__parse(filename, &args, map__process_kallsym_symbol); | 553 | return kallsyms__parse(filename, &args, map__process_kallsym_symbol); |
505 | } | 554 | } |
506 | 555 | ||
@@ -509,15 +558,15 @@ static int dso__load_all_kallsyms(struct dso *self, const char *filename, | |||
509 | * kernel range is broken in several maps, named [kernel].N, as we don't have | 558 | * kernel range is broken in several maps, named [kernel].N, as we don't have |
510 | * the original ELF section names vmlinux have. | 559 | * the original ELF section names vmlinux have. |
511 | */ | 560 | */ |
512 | static int dso__split_kallsyms(struct dso *self, struct map *map, | 561 | static int dso__split_kallsyms(struct dso *dso, struct map *map, |
513 | symbol_filter_t filter) | 562 | symbol_filter_t filter) |
514 | { | 563 | { |
515 | struct map_groups *kmaps = map__kmap(map)->kmaps; | 564 | struct map_groups *kmaps = map__kmap(map)->kmaps; |
516 | struct machine *machine = kmaps->machine; | 565 | struct machine *machine = kmaps->machine; |
517 | struct map *curr_map = map; | 566 | struct map *curr_map = map; |
518 | struct symbol *pos; | 567 | struct symbol *pos; |
519 | int count = 0; | 568 | int count = 0, moved = 0; |
520 | struct rb_root *root = &self->symbols[map->type]; | 569 | struct rb_root *root = &dso->symbols[map->type]; |
521 | struct rb_node *next = rb_first(root); | 570 | struct rb_node *next = rb_first(root); |
522 | int kernel_range = 0; | 571 | int kernel_range = 0; |
523 | 572 | ||
@@ -536,7 +585,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
536 | 585 | ||
537 | if (strcmp(curr_map->dso->short_name, module)) { | 586 | if (strcmp(curr_map->dso->short_name, module)) { |
538 | if (curr_map != map && | 587 | if (curr_map != map && |
539 | self->kernel == DSO_TYPE_GUEST_KERNEL && | 588 | dso->kernel == DSO_TYPE_GUEST_KERNEL && |
540 | machine__is_default_guest(machine)) { | 589 | machine__is_default_guest(machine)) { |
541 | /* | 590 | /* |
542 | * We assume all symbols of a module are | 591 | * We assume all symbols of a module are |
@@ -572,9 +621,14 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
572 | pos->end = curr_map->map_ip(curr_map, pos->end); | 621 | pos->end = curr_map->map_ip(curr_map, pos->end); |
573 | } else if (curr_map != map) { | 622 | } else if (curr_map != map) { |
574 | char dso_name[PATH_MAX]; | 623 | char dso_name[PATH_MAX]; |
575 | struct dso *dso; | 624 | struct dso *ndso; |
576 | 625 | ||
577 | if (self->kernel == DSO_TYPE_GUEST_KERNEL) | 626 | if (count == 0) { |
627 | curr_map = map; | ||
628 | goto filter_symbol; | ||
629 | } | ||
630 | |||
631 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | ||
578 | snprintf(dso_name, sizeof(dso_name), | 632 | snprintf(dso_name, sizeof(dso_name), |
579 | "[guest.kernel].%d", | 633 | "[guest.kernel].%d", |
580 | kernel_range++); | 634 | kernel_range++); |
@@ -583,15 +637,15 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
583 | "[kernel].%d", | 637 | "[kernel].%d", |
584 | kernel_range++); | 638 | kernel_range++); |
585 | 639 | ||
586 | dso = dso__new(dso_name); | 640 | ndso = dso__new(dso_name); |
587 | if (dso == NULL) | 641 | if (ndso == NULL) |
588 | return -1; | 642 | return -1; |
589 | 643 | ||
590 | dso->kernel = self->kernel; | 644 | ndso->kernel = dso->kernel; |
591 | 645 | ||
592 | curr_map = map__new2(pos->start, dso, map->type); | 646 | curr_map = map__new2(pos->start, ndso, map->type); |
593 | if (curr_map == NULL) { | 647 | if (curr_map == NULL) { |
594 | dso__delete(dso); | 648 | dso__delete(ndso); |
595 | return -1; | 649 | return -1; |
596 | } | 650 | } |
597 | 651 | ||
@@ -599,7 +653,7 @@ static int dso__split_kallsyms(struct dso *self, struct map *map, | |||
599 | map_groups__insert(kmaps, curr_map); | 653 | map_groups__insert(kmaps, curr_map); |
600 | ++kernel_range; | 654 | ++kernel_range; |
601 | } | 655 | } |
602 | 656 | filter_symbol: | |
603 | if (filter && filter(curr_map, pos)) { | 657 | if (filter && filter(curr_map, pos)) { |
604 | discard_symbol: rb_erase(&pos->rb_node, root); | 658 | discard_symbol: rb_erase(&pos->rb_node, root); |
605 | symbol__delete(pos); | 659 | symbol__delete(pos); |
@@ -607,36 +661,57 @@ discard_symbol: rb_erase(&pos->rb_node, root); | |||
607 | if (curr_map != map) { | 661 | if (curr_map != map) { |
608 | rb_erase(&pos->rb_node, root); | 662 | rb_erase(&pos->rb_node, root); |
609 | symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); | 663 | symbols__insert(&curr_map->dso->symbols[curr_map->type], pos); |
610 | } | 664 | ++moved; |
611 | count++; | 665 | } else |
666 | ++count; | ||
612 | } | 667 | } |
613 | } | 668 | } |
614 | 669 | ||
615 | if (curr_map != map && | 670 | if (curr_map != map && |
616 | self->kernel == DSO_TYPE_GUEST_KERNEL && | 671 | dso->kernel == DSO_TYPE_GUEST_KERNEL && |
617 | machine__is_default_guest(kmaps->machine)) { | 672 | machine__is_default_guest(kmaps->machine)) { |
618 | dso__set_loaded(curr_map->dso, curr_map->type); | 673 | dso__set_loaded(curr_map->dso, curr_map->type); |
619 | } | 674 | } |
620 | 675 | ||
621 | return count; | 676 | return count + moved; |
622 | } | 677 | } |
623 | 678 | ||
624 | int dso__load_kallsyms(struct dso *self, const char *filename, | 679 | static bool symbol__restricted_filename(const char *filename, |
680 | const char *restricted_filename) | ||
681 | { | ||
682 | bool restricted = false; | ||
683 | |||
684 | if (symbol_conf.kptr_restrict) { | ||
685 | char *r = realpath(filename, NULL); | ||
686 | |||
687 | if (r != NULL) { | ||
688 | restricted = strcmp(r, restricted_filename) == 0; | ||
689 | free(r); | ||
690 | return restricted; | ||
691 | } | ||
692 | } | ||
693 | |||
694 | return restricted; | ||
695 | } | ||
696 | |||
697 | int dso__load_kallsyms(struct dso *dso, const char *filename, | ||
625 | struct map *map, symbol_filter_t filter) | 698 | struct map *map, symbol_filter_t filter) |
626 | { | 699 | { |
627 | if (dso__load_all_kallsyms(self, filename, map) < 0) | 700 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) |
701 | return -1; | ||
702 | |||
703 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | ||
628 | return -1; | 704 | return -1; |
629 | 705 | ||
630 | symbols__fixup_end(&self->symbols[map->type]); | 706 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
631 | if (self->kernel == DSO_TYPE_GUEST_KERNEL) | 707 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; |
632 | self->origin = DSO__ORIG_GUEST_KERNEL; | ||
633 | else | 708 | else |
634 | self->origin = DSO__ORIG_KERNEL; | 709 | dso->symtab_type = SYMTAB__KALLSYMS; |
635 | 710 | ||
636 | return dso__split_kallsyms(self, map, filter); | 711 | return dso__split_kallsyms(dso, map, filter); |
637 | } | 712 | } |
638 | 713 | ||
639 | static int dso__load_perf_map(struct dso *self, struct map *map, | 714 | static int dso__load_perf_map(struct dso *dso, struct map *map, |
640 | symbol_filter_t filter) | 715 | symbol_filter_t filter) |
641 | { | 716 | { |
642 | char *line = NULL; | 717 | char *line = NULL; |
@@ -644,7 +719,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, | |||
644 | FILE *file; | 719 | FILE *file; |
645 | int nr_syms = 0; | 720 | int nr_syms = 0; |
646 | 721 | ||
647 | file = fopen(self->long_name, "r"); | 722 | file = fopen(dso->long_name, "r"); |
648 | if (file == NULL) | 723 | if (file == NULL) |
649 | goto out_failure; | 724 | goto out_failure; |
650 | 725 | ||
@@ -682,7 +757,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, | |||
682 | if (filter && filter(map, sym)) | 757 | if (filter && filter(map, sym)) |
683 | symbol__delete(sym); | 758 | symbol__delete(sym); |
684 | else { | 759 | else { |
685 | symbols__insert(&self->symbols[map->type], sym); | 760 | symbols__insert(&dso->symbols[map->type], sym); |
686 | nr_syms++; | 761 | nr_syms++; |
687 | } | 762 | } |
688 | } | 763 | } |
@@ -701,7 +776,7 @@ out_failure: | |||
701 | /** | 776 | /** |
702 | * elf_symtab__for_each_symbol - iterate thru all the symbols | 777 | * elf_symtab__for_each_symbol - iterate thru all the symbols |
703 | * | 778 | * |
704 | * @self: struct elf_symtab instance to iterate | 779 | * @syms: struct elf_symtab instance to iterate |
705 | * @idx: uint32_t idx | 780 | * @idx: uint32_t idx |
706 | * @sym: GElf_Sym iterator | 781 | * @sym: GElf_Sym iterator |
707 | */ | 782 | */ |
@@ -801,7 +876,7 @@ static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | |||
801 | * And always look at the original dso, not at debuginfo packages, that | 876 | * And always look at the original dso, not at debuginfo packages, that |
802 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). | 877 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). |
803 | */ | 878 | */ |
804 | static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | 879 | static int dso__synthesize_plt_symbols(struct dso *dso, struct map *map, |
805 | symbol_filter_t filter) | 880 | symbol_filter_t filter) |
806 | { | 881 | { |
807 | uint32_t nr_rel_entries, idx; | 882 | uint32_t nr_rel_entries, idx; |
@@ -817,8 +892,11 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
817 | char sympltname[1024]; | 892 | char sympltname[1024]; |
818 | Elf *elf; | 893 | Elf *elf; |
819 | int nr = 0, symidx, fd, err = 0; | 894 | int nr = 0, symidx, fd, err = 0; |
895 | char name[PATH_MAX]; | ||
820 | 896 | ||
821 | fd = open(self->long_name, O_RDONLY); | 897 | snprintf(name, sizeof(name), "%s%s", |
898 | symbol_conf.symfs, dso->long_name); | ||
899 | fd = open(name, O_RDONLY); | ||
822 | if (fd < 0) | 900 | if (fd < 0) |
823 | goto out; | 901 | goto out; |
824 | 902 | ||
@@ -893,7 +971,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
893 | if (filter && filter(map, f)) | 971 | if (filter && filter(map, f)) |
894 | symbol__delete(f); | 972 | symbol__delete(f); |
895 | else { | 973 | else { |
896 | symbols__insert(&self->symbols[map->type], f); | 974 | symbols__insert(&dso->symbols[map->type], f); |
897 | ++nr; | 975 | ++nr; |
898 | } | 976 | } |
899 | } | 977 | } |
@@ -915,7 +993,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
915 | if (filter && filter(map, f)) | 993 | if (filter && filter(map, f)) |
916 | symbol__delete(f); | 994 | symbol__delete(f); |
917 | else { | 995 | else { |
918 | symbols__insert(&self->symbols[map->type], f); | 996 | symbols__insert(&dso->symbols[map->type], f); |
919 | ++nr; | 997 | ++nr; |
920 | } | 998 | } |
921 | } | 999 | } |
@@ -931,29 +1009,30 @@ out_close: | |||
931 | return nr; | 1009 | return nr; |
932 | out: | 1010 | out: |
933 | pr_debug("%s: problems reading %s PLT info.\n", | 1011 | pr_debug("%s: problems reading %s PLT info.\n", |
934 | __func__, self->long_name); | 1012 | __func__, dso->long_name); |
935 | return 0; | 1013 | return 0; |
936 | } | 1014 | } |
937 | 1015 | ||
938 | static bool elf_sym__is_a(GElf_Sym *self, enum map_type type) | 1016 | static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) |
939 | { | 1017 | { |
940 | switch (type) { | 1018 | switch (type) { |
941 | case MAP__FUNCTION: | 1019 | case MAP__FUNCTION: |
942 | return elf_sym__is_function(self); | 1020 | return elf_sym__is_function(sym); |
943 | case MAP__VARIABLE: | 1021 | case MAP__VARIABLE: |
944 | return elf_sym__is_object(self); | 1022 | return elf_sym__is_object(sym); |
945 | default: | 1023 | default: |
946 | return false; | 1024 | return false; |
947 | } | 1025 | } |
948 | } | 1026 | } |
949 | 1027 | ||
950 | static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type) | 1028 | static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, |
1029 | enum map_type type) | ||
951 | { | 1030 | { |
952 | switch (type) { | 1031 | switch (type) { |
953 | case MAP__FUNCTION: | 1032 | case MAP__FUNCTION: |
954 | return elf_sec__is_text(self, secstrs); | 1033 | return elf_sec__is_text(shdr, secstrs); |
955 | case MAP__VARIABLE: | 1034 | case MAP__VARIABLE: |
956 | return elf_sec__is_data(self, secstrs); | 1035 | return elf_sec__is_data(shdr, secstrs); |
957 | default: | 1036 | default: |
958 | return false; | 1037 | return false; |
959 | } | 1038 | } |
@@ -978,13 +1057,13 @@ static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | |||
978 | return -1; | 1057 | return -1; |
979 | } | 1058 | } |
980 | 1059 | ||
981 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, | 1060 | static int dso__load_sym(struct dso *dso, struct map *map, const char *name, |
982 | int fd, symbol_filter_t filter, int kmodule, | 1061 | int fd, symbol_filter_t filter, int kmodule, |
983 | int want_symtab) | 1062 | int want_symtab) |
984 | { | 1063 | { |
985 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; | 1064 | struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; |
986 | struct map *curr_map = map; | 1065 | struct map *curr_map = map; |
987 | struct dso *curr_dso = self; | 1066 | struct dso *curr_dso = dso; |
988 | Elf_Data *symstrs, *secstrs; | 1067 | Elf_Data *symstrs, *secstrs; |
989 | uint32_t nr_syms; | 1068 | uint32_t nr_syms; |
990 | int err = -1; | 1069 | int err = -1; |
@@ -1010,14 +1089,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1010 | } | 1089 | } |
1011 | 1090 | ||
1012 | /* Always reject images with a mismatched build-id: */ | 1091 | /* Always reject images with a mismatched build-id: */ |
1013 | if (self->has_build_id) { | 1092 | if (dso->has_build_id) { |
1014 | u8 build_id[BUILD_ID_SIZE]; | 1093 | u8 build_id[BUILD_ID_SIZE]; |
1015 | 1094 | ||
1016 | if (elf_read_build_id(elf, build_id, | 1095 | if (elf_read_build_id(elf, build_id, |
1017 | BUILD_ID_SIZE) != BUILD_ID_SIZE) | 1096 | BUILD_ID_SIZE) != BUILD_ID_SIZE) |
1018 | goto out_elf_end; | 1097 | goto out_elf_end; |
1019 | 1098 | ||
1020 | if (!dso__build_id_equal(self, build_id)) | 1099 | if (!dso__build_id_equal(dso, build_id)) |
1021 | goto out_elf_end; | 1100 | goto out_elf_end; |
1022 | } | 1101 | } |
1023 | 1102 | ||
@@ -1058,13 +1137,14 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1058 | nr_syms = shdr.sh_size / shdr.sh_entsize; | 1137 | nr_syms = shdr.sh_size / shdr.sh_entsize; |
1059 | 1138 | ||
1060 | memset(&sym, 0, sizeof(sym)); | 1139 | memset(&sym, 0, sizeof(sym)); |
1061 | if (self->kernel == DSO_TYPE_USER) { | 1140 | if (dso->kernel == DSO_TYPE_USER) { |
1062 | self->adjust_symbols = (ehdr.e_type == ET_EXEC || | 1141 | dso->adjust_symbols = (ehdr.e_type == ET_EXEC || |
1063 | elf_section_by_name(elf, &ehdr, &shdr, | 1142 | elf_section_by_name(elf, &ehdr, &shdr, |
1064 | ".gnu.prelink_undo", | 1143 | ".gnu.prelink_undo", |
1065 | NULL) != NULL); | 1144 | NULL) != NULL); |
1066 | } else self->adjust_symbols = 0; | 1145 | } else { |
1067 | 1146 | dso->adjust_symbols = 0; | |
1147 | } | ||
1068 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { | 1148 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { |
1069 | struct symbol *f; | 1149 | struct symbol *f; |
1070 | const char *elf_name = elf_sym__name(&sym, symstrs); | 1150 | const char *elf_name = elf_sym__name(&sym, symstrs); |
@@ -1107,22 +1187,29 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1107 | 1187 | ||
1108 | section_name = elf_sec__name(&shdr, secstrs); | 1188 | section_name = elf_sec__name(&shdr, secstrs); |
1109 | 1189 | ||
1110 | if (self->kernel != DSO_TYPE_USER || kmodule) { | 1190 | /* On ARM, symbols for thumb functions have 1 added to |
1191 | * the symbol address as a flag - remove it */ | ||
1192 | if ((ehdr.e_machine == EM_ARM) && | ||
1193 | (map->type == MAP__FUNCTION) && | ||
1194 | (sym.st_value & 1)) | ||
1195 | --sym.st_value; | ||
1196 | |||
1197 | if (dso->kernel != DSO_TYPE_USER || kmodule) { | ||
1111 | char dso_name[PATH_MAX]; | 1198 | char dso_name[PATH_MAX]; |
1112 | 1199 | ||
1113 | if (strcmp(section_name, | 1200 | if (strcmp(section_name, |
1114 | (curr_dso->short_name + | 1201 | (curr_dso->short_name + |
1115 | self->short_name_len)) == 0) | 1202 | dso->short_name_len)) == 0) |
1116 | goto new_symbol; | 1203 | goto new_symbol; |
1117 | 1204 | ||
1118 | if (strcmp(section_name, ".text") == 0) { | 1205 | if (strcmp(section_name, ".text") == 0) { |
1119 | curr_map = map; | 1206 | curr_map = map; |
1120 | curr_dso = self; | 1207 | curr_dso = dso; |
1121 | goto new_symbol; | 1208 | goto new_symbol; |
1122 | } | 1209 | } |
1123 | 1210 | ||
1124 | snprintf(dso_name, sizeof(dso_name), | 1211 | snprintf(dso_name, sizeof(dso_name), |
1125 | "%s%s", self->short_name, section_name); | 1212 | "%s%s", dso->short_name, section_name); |
1126 | 1213 | ||
1127 | curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); | 1214 | curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); |
1128 | if (curr_map == NULL) { | 1215 | if (curr_map == NULL) { |
@@ -1134,7 +1221,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1134 | curr_dso = dso__new(dso_name); | 1221 | curr_dso = dso__new(dso_name); |
1135 | if (curr_dso == NULL) | 1222 | if (curr_dso == NULL) |
1136 | goto out_elf_end; | 1223 | goto out_elf_end; |
1137 | curr_dso->kernel = self->kernel; | 1224 | curr_dso->kernel = dso->kernel; |
1225 | curr_dso->long_name = dso->long_name; | ||
1226 | curr_dso->long_name_len = dso->long_name_len; | ||
1138 | curr_map = map__new2(start, curr_dso, | 1227 | curr_map = map__new2(start, curr_dso, |
1139 | map->type); | 1228 | map->type); |
1140 | if (curr_map == NULL) { | 1229 | if (curr_map == NULL) { |
@@ -1143,9 +1232,9 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1143 | } | 1232 | } |
1144 | curr_map->map_ip = identity__map_ip; | 1233 | curr_map->map_ip = identity__map_ip; |
1145 | curr_map->unmap_ip = identity__map_ip; | 1234 | curr_map->unmap_ip = identity__map_ip; |
1146 | curr_dso->origin = self->origin; | 1235 | curr_dso->symtab_type = dso->symtab_type; |
1147 | map_groups__insert(kmap->kmaps, curr_map); | 1236 | map_groups__insert(kmap->kmaps, curr_map); |
1148 | dsos__add(&self->node, curr_dso); | 1237 | dsos__add(&dso->node, curr_dso); |
1149 | dso__set_loaded(curr_dso, map->type); | 1238 | dso__set_loaded(curr_dso, map->type); |
1150 | } else | 1239 | } else |
1151 | curr_dso = curr_map->dso; | 1240 | curr_dso = curr_map->dso; |
@@ -1154,8 +1243,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1154 | } | 1243 | } |
1155 | 1244 | ||
1156 | if (curr_dso->adjust_symbols) { | 1245 | if (curr_dso->adjust_symbols) { |
1157 | pr_debug4("%s: adjusting symbol: st_value: %#Lx " | 1246 | pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " |
1158 | "sh_addr: %#Lx sh_offset: %#Lx\n", __func__, | 1247 | "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, |
1159 | (u64)sym.st_value, (u64)shdr.sh_addr, | 1248 | (u64)sym.st_value, (u64)shdr.sh_addr, |
1160 | (u64)shdr.sh_offset); | 1249 | (u64)shdr.sh_offset); |
1161 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 1250 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
@@ -1187,7 +1276,7 @@ new_symbol: | |||
1187 | * For misannotated, zeroed, ASM function sizes. | 1276 | * For misannotated, zeroed, ASM function sizes. |
1188 | */ | 1277 | */ |
1189 | if (nr > 0) { | 1278 | if (nr > 0) { |
1190 | symbols__fixup_end(&self->symbols[map->type]); | 1279 | symbols__fixup_end(&dso->symbols[map->type]); |
1191 | if (kmap) { | 1280 | if (kmap) { |
1192 | /* | 1281 | /* |
1193 | * We need to fixup this here too because we create new | 1282 | * We need to fixup this here too because we create new |
@@ -1203,9 +1292,9 @@ out_close: | |||
1203 | return err; | 1292 | return err; |
1204 | } | 1293 | } |
1205 | 1294 | ||
1206 | static bool dso__build_id_equal(const struct dso *self, u8 *build_id) | 1295 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) |
1207 | { | 1296 | { |
1208 | return memcmp(self->build_id, build_id, sizeof(self->build_id)) == 0; | 1297 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; |
1209 | } | 1298 | } |
1210 | 1299 | ||
1211 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | 1300 | bool __dsos__read_build_ids(struct list_head *head, bool with_hits) |
@@ -1366,27 +1455,27 @@ out: | |||
1366 | return err; | 1455 | return err; |
1367 | } | 1456 | } |
1368 | 1457 | ||
1369 | char dso__symtab_origin(const struct dso *self) | 1458 | char dso__symtab_origin(const struct dso *dso) |
1370 | { | 1459 | { |
1371 | static const char origin[] = { | 1460 | static const char origin[] = { |
1372 | [DSO__ORIG_KERNEL] = 'k', | 1461 | [SYMTAB__KALLSYMS] = 'k', |
1373 | [DSO__ORIG_JAVA_JIT] = 'j', | 1462 | [SYMTAB__JAVA_JIT] = 'j', |
1374 | [DSO__ORIG_BUILD_ID_CACHE] = 'B', | 1463 | [SYMTAB__BUILD_ID_CACHE] = 'B', |
1375 | [DSO__ORIG_FEDORA] = 'f', | 1464 | [SYMTAB__FEDORA_DEBUGINFO] = 'f', |
1376 | [DSO__ORIG_UBUNTU] = 'u', | 1465 | [SYMTAB__UBUNTU_DEBUGINFO] = 'u', |
1377 | [DSO__ORIG_BUILDID] = 'b', | 1466 | [SYMTAB__BUILDID_DEBUGINFO] = 'b', |
1378 | [DSO__ORIG_DSO] = 'd', | 1467 | [SYMTAB__SYSTEM_PATH_DSO] = 'd', |
1379 | [DSO__ORIG_KMODULE] = 'K', | 1468 | [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', |
1380 | [DSO__ORIG_GUEST_KERNEL] = 'g', | 1469 | [SYMTAB__GUEST_KALLSYMS] = 'g', |
1381 | [DSO__ORIG_GUEST_KMODULE] = 'G', | 1470 | [SYMTAB__GUEST_KMODULE] = 'G', |
1382 | }; | 1471 | }; |
1383 | 1472 | ||
1384 | if (self == NULL || self->origin == DSO__ORIG_NOT_FOUND) | 1473 | if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) |
1385 | return '!'; | 1474 | return '!'; |
1386 | return origin[self->origin]; | 1475 | return origin[dso->symtab_type]; |
1387 | } | 1476 | } |
1388 | 1477 | ||
1389 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | 1478 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) |
1390 | { | 1479 | { |
1391 | int size = PATH_MAX; | 1480 | int size = PATH_MAX; |
1392 | char *name; | 1481 | char *name; |
@@ -1396,12 +1485,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1396 | const char *root_dir; | 1485 | const char *root_dir; |
1397 | int want_symtab; | 1486 | int want_symtab; |
1398 | 1487 | ||
1399 | dso__set_loaded(self, map->type); | 1488 | dso__set_loaded(dso, map->type); |
1400 | 1489 | ||
1401 | if (self->kernel == DSO_TYPE_KERNEL) | 1490 | if (dso->kernel == DSO_TYPE_KERNEL) |
1402 | return dso__load_kernel_sym(self, map, filter); | 1491 | return dso__load_kernel_sym(dso, map, filter); |
1403 | else if (self->kernel == DSO_TYPE_GUEST_KERNEL) | 1492 | else if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
1404 | return dso__load_guest_kernel_sym(self, map, filter); | 1493 | return dso__load_guest_kernel_sym(dso, map, filter); |
1405 | 1494 | ||
1406 | if (map->groups && map->groups->machine) | 1495 | if (map->groups && map->groups->machine) |
1407 | machine = map->groups->machine; | 1496 | machine = map->groups->machine; |
@@ -1412,12 +1501,12 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1412 | if (!name) | 1501 | if (!name) |
1413 | return -1; | 1502 | return -1; |
1414 | 1503 | ||
1415 | self->adjust_symbols = 0; | 1504 | dso->adjust_symbols = 0; |
1416 | 1505 | ||
1417 | if (strncmp(self->name, "/tmp/perf-", 10) == 0) { | 1506 | if (strncmp(dso->name, "/tmp/perf-", 10) == 0) { |
1418 | ret = dso__load_perf_map(self, map, filter); | 1507 | ret = dso__load_perf_map(dso, map, filter); |
1419 | self->origin = ret > 0 ? DSO__ORIG_JAVA_JIT : | 1508 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : |
1420 | DSO__ORIG_NOT_FOUND; | 1509 | SYMTAB__NOT_FOUND; |
1421 | return ret; | 1510 | return ret; |
1422 | } | 1511 | } |
1423 | 1512 | ||
@@ -1425,57 +1514,59 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1425 | * On the first pass, only load images if they have a full symtab. | 1514 | * On the first pass, only load images if they have a full symtab. |
1426 | * Failing that, do a second pass where we accept .dynsym also | 1515 | * Failing that, do a second pass where we accept .dynsym also |
1427 | */ | 1516 | */ |
1428 | for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; | 1517 | want_symtab = 1; |
1429 | self->origin != DSO__ORIG_NOT_FOUND; | 1518 | restart: |
1430 | self->origin++) { | 1519 | for (dso->symtab_type = SYMTAB__BUILD_ID_CACHE; |
1431 | switch (self->origin) { | 1520 | dso->symtab_type != SYMTAB__NOT_FOUND; |
1432 | case DSO__ORIG_BUILD_ID_CACHE: | 1521 | dso->symtab_type++) { |
1433 | if (dso__build_id_filename(self, name, size) == NULL) | 1522 | switch (dso->symtab_type) { |
1523 | case SYMTAB__BUILD_ID_CACHE: | ||
1524 | /* skip the locally configured cache if a symfs is given */ | ||
1525 | if (symbol_conf.symfs[0] || | ||
1526 | (dso__build_id_filename(dso, name, size) == NULL)) { | ||
1434 | continue; | 1527 | continue; |
1528 | } | ||
1435 | break; | 1529 | break; |
1436 | case DSO__ORIG_FEDORA: | 1530 | case SYMTAB__FEDORA_DEBUGINFO: |
1437 | snprintf(name, size, "/usr/lib/debug%s.debug", | 1531 | snprintf(name, size, "%s/usr/lib/debug%s.debug", |
1438 | self->long_name); | 1532 | symbol_conf.symfs, dso->long_name); |
1439 | break; | 1533 | break; |
1440 | case DSO__ORIG_UBUNTU: | 1534 | case SYMTAB__UBUNTU_DEBUGINFO: |
1441 | snprintf(name, size, "/usr/lib/debug%s", | 1535 | snprintf(name, size, "%s/usr/lib/debug%s", |
1442 | self->long_name); | 1536 | symbol_conf.symfs, dso->long_name); |
1443 | break; | 1537 | break; |
1444 | case DSO__ORIG_BUILDID: { | 1538 | case SYMTAB__BUILDID_DEBUGINFO: { |
1445 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 1539 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
1446 | 1540 | ||
1447 | if (!self->has_build_id) | 1541 | if (!dso->has_build_id) |
1448 | continue; | 1542 | continue; |
1449 | 1543 | ||
1450 | build_id__sprintf(self->build_id, | 1544 | build_id__sprintf(dso->build_id, |
1451 | sizeof(self->build_id), | 1545 | sizeof(dso->build_id), |
1452 | build_id_hex); | 1546 | build_id_hex); |
1453 | snprintf(name, size, | 1547 | snprintf(name, size, |
1454 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | 1548 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", |
1455 | build_id_hex, build_id_hex + 2); | 1549 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); |
1456 | } | 1550 | } |
1457 | break; | 1551 | break; |
1458 | case DSO__ORIG_DSO: | 1552 | case SYMTAB__SYSTEM_PATH_DSO: |
1459 | snprintf(name, size, "%s", self->long_name); | 1553 | snprintf(name, size, "%s%s", |
1554 | symbol_conf.symfs, dso->long_name); | ||
1460 | break; | 1555 | break; |
1461 | case DSO__ORIG_GUEST_KMODULE: | 1556 | case SYMTAB__GUEST_KMODULE: |
1462 | if (map->groups && map->groups->machine) | 1557 | if (map->groups && machine) |
1463 | root_dir = map->groups->machine->root_dir; | 1558 | root_dir = machine->root_dir; |
1464 | else | 1559 | else |
1465 | root_dir = ""; | 1560 | root_dir = ""; |
1466 | snprintf(name, size, "%s%s", root_dir, self->long_name); | 1561 | snprintf(name, size, "%s%s%s", symbol_conf.symfs, |
1562 | root_dir, dso->long_name); | ||
1467 | break; | 1563 | break; |
1468 | 1564 | ||
1469 | default: | 1565 | case SYMTAB__SYSTEM_PATH_KMODULE: |
1470 | /* | 1566 | snprintf(name, size, "%s%s", symbol_conf.symfs, |
1471 | * If we wanted a full symtab but no image had one, | 1567 | dso->long_name); |
1472 | * relax our requirements and repeat the search. | 1568 | break; |
1473 | */ | 1569 | default:; |
1474 | if (want_symtab) { | ||
1475 | want_symtab = 0; | ||
1476 | self->origin = DSO__ORIG_BUILD_ID_CACHE; | ||
1477 | } else | ||
1478 | continue; | ||
1479 | } | 1570 | } |
1480 | 1571 | ||
1481 | /* Name is now the name of the next image to try */ | 1572 | /* Name is now the name of the next image to try */ |
@@ -1483,7 +1574,7 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1483 | if (fd < 0) | 1574 | if (fd < 0) |
1484 | continue; | 1575 | continue; |
1485 | 1576 | ||
1486 | ret = dso__load_sym(self, map, name, fd, filter, 0, | 1577 | ret = dso__load_sym(dso, map, name, fd, filter, 0, |
1487 | want_symtab); | 1578 | want_symtab); |
1488 | close(fd); | 1579 | close(fd); |
1489 | 1580 | ||
@@ -1495,25 +1586,35 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1495 | continue; | 1586 | continue; |
1496 | 1587 | ||
1497 | if (ret > 0) { | 1588 | if (ret > 0) { |
1498 | int nr_plt = dso__synthesize_plt_symbols(self, map, filter); | 1589 | int nr_plt = dso__synthesize_plt_symbols(dso, map, |
1590 | filter); | ||
1499 | if (nr_plt > 0) | 1591 | if (nr_plt > 0) |
1500 | ret += nr_plt; | 1592 | ret += nr_plt; |
1501 | break; | 1593 | break; |
1502 | } | 1594 | } |
1503 | } | 1595 | } |
1504 | 1596 | ||
1597 | /* | ||
1598 | * If we wanted a full symtab but no image had one, | ||
1599 | * relax our requirements and repeat the search. | ||
1600 | */ | ||
1601 | if (ret <= 0 && want_symtab) { | ||
1602 | want_symtab = 0; | ||
1603 | goto restart; | ||
1604 | } | ||
1605 | |||
1505 | free(name); | 1606 | free(name); |
1506 | if (ret < 0 && strstr(self->name, " (deleted)") != NULL) | 1607 | if (ret < 0 && strstr(dso->name, " (deleted)") != NULL) |
1507 | return 0; | 1608 | return 0; |
1508 | return ret; | 1609 | return ret; |
1509 | } | 1610 | } |
1510 | 1611 | ||
1511 | struct map *map_groups__find_by_name(struct map_groups *self, | 1612 | struct map *map_groups__find_by_name(struct map_groups *mg, |
1512 | enum map_type type, const char *name) | 1613 | enum map_type type, const char *name) |
1513 | { | 1614 | { |
1514 | struct rb_node *nd; | 1615 | struct rb_node *nd; |
1515 | 1616 | ||
1516 | for (nd = rb_first(&self->maps[type]); nd; nd = rb_next(nd)) { | 1617 | for (nd = rb_first(&mg->maps[type]); nd; nd = rb_next(nd)) { |
1517 | struct map *map = rb_entry(nd, struct map, rb_node); | 1618 | struct map *map = rb_entry(nd, struct map, rb_node); |
1518 | 1619 | ||
1519 | if (map->dso && strcmp(map->dso->short_name, name) == 0) | 1620 | if (map->dso && strcmp(map->dso->short_name, name) == 0) |
@@ -1523,28 +1624,28 @@ struct map *map_groups__find_by_name(struct map_groups *self, | |||
1523 | return NULL; | 1624 | return NULL; |
1524 | } | 1625 | } |
1525 | 1626 | ||
1526 | static int dso__kernel_module_get_build_id(struct dso *self, | 1627 | static int dso__kernel_module_get_build_id(struct dso *dso, |
1527 | const char *root_dir) | 1628 | const char *root_dir) |
1528 | { | 1629 | { |
1529 | char filename[PATH_MAX]; | 1630 | char filename[PATH_MAX]; |
1530 | /* | 1631 | /* |
1531 | * kernel module short names are of the form "[module]" and | 1632 | * kernel module short names are of the form "[module]" and |
1532 | * we need just "module" here. | 1633 | * we need just "module" here. |
1533 | */ | 1634 | */ |
1534 | const char *name = self->short_name + 1; | 1635 | const char *name = dso->short_name + 1; |
1535 | 1636 | ||
1536 | snprintf(filename, sizeof(filename), | 1637 | snprintf(filename, sizeof(filename), |
1537 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", | 1638 | "%s/sys/module/%.*s/notes/.note.gnu.build-id", |
1538 | root_dir, (int)strlen(name) - 1, name); | 1639 | root_dir, (int)strlen(name) - 1, name); |
1539 | 1640 | ||
1540 | if (sysfs__read_build_id(filename, self->build_id, | 1641 | if (sysfs__read_build_id(filename, dso->build_id, |
1541 | sizeof(self->build_id)) == 0) | 1642 | sizeof(dso->build_id)) == 0) |
1542 | self->has_build_id = true; | 1643 | dso->has_build_id = true; |
1543 | 1644 | ||
1544 | return 0; | 1645 | return 0; |
1545 | } | 1646 | } |
1546 | 1647 | ||
1547 | static int map_groups__set_modules_path_dir(struct map_groups *self, | 1648 | static int map_groups__set_modules_path_dir(struct map_groups *mg, |
1548 | const char *dir_name) | 1649 | const char *dir_name) |
1549 | { | 1650 | { |
1550 | struct dirent *dent; | 1651 | struct dirent *dent; |
@@ -1572,7 +1673,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, | |||
1572 | 1673 | ||
1573 | snprintf(path, sizeof(path), "%s/%s", | 1674 | snprintf(path, sizeof(path), "%s/%s", |
1574 | dir_name, dent->d_name); | 1675 | dir_name, dent->d_name); |
1575 | ret = map_groups__set_modules_path_dir(self, path); | 1676 | ret = map_groups__set_modules_path_dir(mg, path); |
1576 | if (ret < 0) | 1677 | if (ret < 0) |
1577 | goto out; | 1678 | goto out; |
1578 | } else { | 1679 | } else { |
@@ -1587,7 +1688,8 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, | |||
1587 | (int)(dot - dent->d_name), dent->d_name); | 1688 | (int)(dot - dent->d_name), dent->d_name); |
1588 | 1689 | ||
1589 | strxfrchar(dso_name, '-', '_'); | 1690 | strxfrchar(dso_name, '-', '_'); |
1590 | map = map_groups__find_by_name(self, MAP__FUNCTION, dso_name); | 1691 | map = map_groups__find_by_name(mg, MAP__FUNCTION, |
1692 | dso_name); | ||
1591 | if (map == NULL) | 1693 | if (map == NULL) |
1592 | continue; | 1694 | continue; |
1593 | 1695 | ||
@@ -1637,20 +1739,20 @@ static char *get_kernel_version(const char *root_dir) | |||
1637 | return strdup(name); | 1739 | return strdup(name); |
1638 | } | 1740 | } |
1639 | 1741 | ||
1640 | static int machine__set_modules_path(struct machine *self) | 1742 | static int machine__set_modules_path(struct machine *machine) |
1641 | { | 1743 | { |
1642 | char *version; | 1744 | char *version; |
1643 | char modules_path[PATH_MAX]; | 1745 | char modules_path[PATH_MAX]; |
1644 | 1746 | ||
1645 | version = get_kernel_version(self->root_dir); | 1747 | version = get_kernel_version(machine->root_dir); |
1646 | if (!version) | 1748 | if (!version) |
1647 | return -1; | 1749 | return -1; |
1648 | 1750 | ||
1649 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", | 1751 | snprintf(modules_path, sizeof(modules_path), "%s/lib/modules/%s/kernel", |
1650 | self->root_dir, version); | 1752 | machine->root_dir, version); |
1651 | free(version); | 1753 | free(version); |
1652 | 1754 | ||
1653 | return map_groups__set_modules_path_dir(&self->kmaps, modules_path); | 1755 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); |
1654 | } | 1756 | } |
1655 | 1757 | ||
1656 | /* | 1758 | /* |
@@ -1660,23 +1762,23 @@ static int machine__set_modules_path(struct machine *self) | |||
1660 | */ | 1762 | */ |
1661 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | 1763 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) |
1662 | { | 1764 | { |
1663 | struct map *self = calloc(1, (sizeof(*self) + | 1765 | struct map *map = calloc(1, (sizeof(*map) + |
1664 | (dso->kernel ? sizeof(struct kmap) : 0))); | 1766 | (dso->kernel ? sizeof(struct kmap) : 0))); |
1665 | if (self != NULL) { | 1767 | if (map != NULL) { |
1666 | /* | 1768 | /* |
1667 | * ->end will be filled after we load all the symbols | 1769 | * ->end will be filled after we load all the symbols |
1668 | */ | 1770 | */ |
1669 | map__init(self, type, start, 0, 0, dso); | 1771 | map__init(map, type, start, 0, 0, dso); |
1670 | } | 1772 | } |
1671 | 1773 | ||
1672 | return self; | 1774 | return map; |
1673 | } | 1775 | } |
1674 | 1776 | ||
1675 | struct map *machine__new_module(struct machine *self, u64 start, | 1777 | struct map *machine__new_module(struct machine *machine, u64 start, |
1676 | const char *filename) | 1778 | const char *filename) |
1677 | { | 1779 | { |
1678 | struct map *map; | 1780 | struct map *map; |
1679 | struct dso *dso = __dsos__findnew(&self->kernel_dsos, filename); | 1781 | struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename); |
1680 | 1782 | ||
1681 | if (dso == NULL) | 1783 | if (dso == NULL) |
1682 | return NULL; | 1784 | return NULL; |
@@ -1685,15 +1787,15 @@ struct map *machine__new_module(struct machine *self, u64 start, | |||
1685 | if (map == NULL) | 1787 | if (map == NULL) |
1686 | return NULL; | 1788 | return NULL; |
1687 | 1789 | ||
1688 | if (machine__is_host(self)) | 1790 | if (machine__is_host(machine)) |
1689 | dso->origin = DSO__ORIG_KMODULE; | 1791 | dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; |
1690 | else | 1792 | else |
1691 | dso->origin = DSO__ORIG_GUEST_KMODULE; | 1793 | dso->symtab_type = SYMTAB__GUEST_KMODULE; |
1692 | map_groups__insert(&self->kmaps, map); | 1794 | map_groups__insert(&machine->kmaps, map); |
1693 | return map; | 1795 | return map; |
1694 | } | 1796 | } |
1695 | 1797 | ||
1696 | static int machine__create_modules(struct machine *self) | 1798 | static int machine__create_modules(struct machine *machine) |
1697 | { | 1799 | { |
1698 | char *line = NULL; | 1800 | char *line = NULL; |
1699 | size_t n; | 1801 | size_t n; |
@@ -1702,13 +1804,16 @@ static int machine__create_modules(struct machine *self) | |||
1702 | const char *modules; | 1804 | const char *modules; |
1703 | char path[PATH_MAX]; | 1805 | char path[PATH_MAX]; |
1704 | 1806 | ||
1705 | if (machine__is_default_guest(self)) | 1807 | if (machine__is_default_guest(machine)) |
1706 | modules = symbol_conf.default_guest_modules; | 1808 | modules = symbol_conf.default_guest_modules; |
1707 | else { | 1809 | else { |
1708 | sprintf(path, "%s/proc/modules", self->root_dir); | 1810 | sprintf(path, "%s/proc/modules", machine->root_dir); |
1709 | modules = path; | 1811 | modules = path; |
1710 | } | 1812 | } |
1711 | 1813 | ||
1814 | if (symbol__restricted_filename(path, "/proc/modules")) | ||
1815 | return -1; | ||
1816 | |||
1712 | file = fopen(modules, "r"); | 1817 | file = fopen(modules, "r"); |
1713 | if (file == NULL) | 1818 | if (file == NULL) |
1714 | return -1; | 1819 | return -1; |
@@ -1741,16 +1846,16 @@ static int machine__create_modules(struct machine *self) | |||
1741 | *sep = '\0'; | 1846 | *sep = '\0'; |
1742 | 1847 | ||
1743 | snprintf(name, sizeof(name), "[%s]", line); | 1848 | snprintf(name, sizeof(name), "[%s]", line); |
1744 | map = machine__new_module(self, start, name); | 1849 | map = machine__new_module(machine, start, name); |
1745 | if (map == NULL) | 1850 | if (map == NULL) |
1746 | goto out_delete_line; | 1851 | goto out_delete_line; |
1747 | dso__kernel_module_get_build_id(map->dso, self->root_dir); | 1852 | dso__kernel_module_get_build_id(map->dso, machine->root_dir); |
1748 | } | 1853 | } |
1749 | 1854 | ||
1750 | free(line); | 1855 | free(line); |
1751 | fclose(file); | 1856 | fclose(file); |
1752 | 1857 | ||
1753 | return machine__set_modules_path(self); | 1858 | return machine__set_modules_path(machine); |
1754 | 1859 | ||
1755 | out_delete_line: | 1860 | out_delete_line: |
1756 | free(line); | 1861 | free(line); |
@@ -1758,26 +1863,30 @@ out_failure: | |||
1758 | return -1; | 1863 | return -1; |
1759 | } | 1864 | } |
1760 | 1865 | ||
1761 | static int dso__load_vmlinux(struct dso *self, struct map *map, | 1866 | int dso__load_vmlinux(struct dso *dso, struct map *map, |
1762 | const char *vmlinux, symbol_filter_t filter) | 1867 | const char *vmlinux, symbol_filter_t filter) |
1763 | { | 1868 | { |
1764 | int err = -1, fd; | 1869 | int err = -1, fd; |
1870 | char symfs_vmlinux[PATH_MAX]; | ||
1765 | 1871 | ||
1766 | fd = open(vmlinux, O_RDONLY); | 1872 | snprintf(symfs_vmlinux, sizeof(symfs_vmlinux), "%s%s", |
1873 | symbol_conf.symfs, vmlinux); | ||
1874 | fd = open(symfs_vmlinux, O_RDONLY); | ||
1767 | if (fd < 0) | 1875 | if (fd < 0) |
1768 | return -1; | 1876 | return -1; |
1769 | 1877 | ||
1770 | dso__set_loaded(self, map->type); | 1878 | dso__set_long_name(dso, (char *)vmlinux); |
1771 | err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); | 1879 | dso__set_loaded(dso, map->type); |
1880 | err = dso__load_sym(dso, map, symfs_vmlinux, fd, filter, 0, 0); | ||
1772 | close(fd); | 1881 | close(fd); |
1773 | 1882 | ||
1774 | if (err > 0) | 1883 | if (err > 0) |
1775 | pr_debug("Using %s for symbols\n", vmlinux); | 1884 | pr_debug("Using %s for symbols\n", symfs_vmlinux); |
1776 | 1885 | ||
1777 | return err; | 1886 | return err; |
1778 | } | 1887 | } |
1779 | 1888 | ||
1780 | int dso__load_vmlinux_path(struct dso *self, struct map *map, | 1889 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, |
1781 | symbol_filter_t filter) | 1890 | symbol_filter_t filter) |
1782 | { | 1891 | { |
1783 | int i, err = 0; | 1892 | int i, err = 0; |
@@ -1786,20 +1895,20 @@ int dso__load_vmlinux_path(struct dso *self, struct map *map, | |||
1786 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", | 1895 | pr_debug("Looking at the vmlinux_path (%d entries long)\n", |
1787 | vmlinux_path__nr_entries + 1); | 1896 | vmlinux_path__nr_entries + 1); |
1788 | 1897 | ||
1789 | filename = dso__build_id_filename(self, NULL, 0); | 1898 | filename = dso__build_id_filename(dso, NULL, 0); |
1790 | if (filename != NULL) { | 1899 | if (filename != NULL) { |
1791 | err = dso__load_vmlinux(self, map, filename, filter); | 1900 | err = dso__load_vmlinux(dso, map, filename, filter); |
1792 | if (err > 0) { | 1901 | if (err > 0) { |
1793 | dso__set_long_name(self, filename); | 1902 | dso__set_long_name(dso, filename); |
1794 | goto out; | 1903 | goto out; |
1795 | } | 1904 | } |
1796 | free(filename); | 1905 | free(filename); |
1797 | } | 1906 | } |
1798 | 1907 | ||
1799 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { | 1908 | for (i = 0; i < vmlinux_path__nr_entries; ++i) { |
1800 | err = dso__load_vmlinux(self, map, vmlinux_path[i], filter); | 1909 | err = dso__load_vmlinux(dso, map, vmlinux_path[i], filter); |
1801 | if (err > 0) { | 1910 | if (err > 0) { |
1802 | dso__set_long_name(self, strdup(vmlinux_path[i])); | 1911 | dso__set_long_name(dso, strdup(vmlinux_path[i])); |
1803 | break; | 1912 | break; |
1804 | } | 1913 | } |
1805 | } | 1914 | } |
@@ -1807,15 +1916,15 @@ out: | |||
1807 | return err; | 1916 | return err; |
1808 | } | 1917 | } |
1809 | 1918 | ||
1810 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 1919 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
1811 | symbol_filter_t filter) | 1920 | symbol_filter_t filter) |
1812 | { | 1921 | { |
1813 | int err; | 1922 | int err; |
1814 | const char *kallsyms_filename = NULL; | 1923 | const char *kallsyms_filename = NULL; |
1815 | char *kallsyms_allocated_filename = NULL; | 1924 | char *kallsyms_allocated_filename = NULL; |
1816 | /* | 1925 | /* |
1817 | * Step 1: if the user specified a vmlinux filename, use it and only | 1926 | * Step 1: if the user specified a kallsyms or vmlinux filename, use |
1818 | * it, reporting errors to the user if it cannot be used. | 1927 | * it and only it, reporting errors to the user if it cannot be used. |
1819 | * | 1928 | * |
1820 | * For instance, try to analyse an ARM perf.data file _without_ a | 1929 | * For instance, try to analyse an ARM perf.data file _without_ a |
1821 | * build-id, or if the user specifies the wrong path to the right | 1930 | * build-id, or if the user specifies the wrong path to the right |
@@ -1828,11 +1937,16 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1828 | * validation in dso__load_vmlinux and will bail out if they don't | 1937 | * validation in dso__load_vmlinux and will bail out if they don't |
1829 | * match. | 1938 | * match. |
1830 | */ | 1939 | */ |
1940 | if (symbol_conf.kallsyms_name != NULL) { | ||
1941 | kallsyms_filename = symbol_conf.kallsyms_name; | ||
1942 | goto do_kallsyms; | ||
1943 | } | ||
1944 | |||
1831 | if (symbol_conf.vmlinux_name != NULL) { | 1945 | if (symbol_conf.vmlinux_name != NULL) { |
1832 | err = dso__load_vmlinux(self, map, | 1946 | err = dso__load_vmlinux(dso, map, |
1833 | symbol_conf.vmlinux_name, filter); | 1947 | symbol_conf.vmlinux_name, filter); |
1834 | if (err > 0) { | 1948 | if (err > 0) { |
1835 | dso__set_long_name(self, | 1949 | dso__set_long_name(dso, |
1836 | strdup(symbol_conf.vmlinux_name)); | 1950 | strdup(symbol_conf.vmlinux_name)); |
1837 | goto out_fixup; | 1951 | goto out_fixup; |
1838 | } | 1952 | } |
@@ -1840,23 +1954,27 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1840 | } | 1954 | } |
1841 | 1955 | ||
1842 | if (vmlinux_path != NULL) { | 1956 | if (vmlinux_path != NULL) { |
1843 | err = dso__load_vmlinux_path(self, map, filter); | 1957 | err = dso__load_vmlinux_path(dso, map, filter); |
1844 | if (err > 0) | 1958 | if (err > 0) |
1845 | goto out_fixup; | 1959 | goto out_fixup; |
1846 | } | 1960 | } |
1847 | 1961 | ||
1962 | /* do not try local files if a symfs was given */ | ||
1963 | if (symbol_conf.symfs[0] != 0) | ||
1964 | return -1; | ||
1965 | |||
1848 | /* | 1966 | /* |
1849 | * Say the kernel DSO was created when processing the build-id header table, | 1967 | * Say the kernel DSO was created when processing the build-id header table, |
1850 | * we have a build-id, so check if it is the same as the running kernel, | 1968 | * we have a build-id, so check if it is the same as the running kernel, |
1851 | * using it if it is. | 1969 | * using it if it is. |
1852 | */ | 1970 | */ |
1853 | if (self->has_build_id) { | 1971 | if (dso->has_build_id) { |
1854 | u8 kallsyms_build_id[BUILD_ID_SIZE]; | 1972 | u8 kallsyms_build_id[BUILD_ID_SIZE]; |
1855 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1973 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; |
1856 | 1974 | ||
1857 | if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, | 1975 | if (sysfs__read_build_id("/sys/kernel/notes", kallsyms_build_id, |
1858 | sizeof(kallsyms_build_id)) == 0) { | 1976 | sizeof(kallsyms_build_id)) == 0) { |
1859 | if (dso__build_id_equal(self, kallsyms_build_id)) { | 1977 | if (dso__build_id_equal(dso, kallsyms_build_id)) { |
1860 | kallsyms_filename = "/proc/kallsyms"; | 1978 | kallsyms_filename = "/proc/kallsyms"; |
1861 | goto do_kallsyms; | 1979 | goto do_kallsyms; |
1862 | } | 1980 | } |
@@ -1865,7 +1983,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1865 | * Now look if we have it on the build-id cache in | 1983 | * Now look if we have it on the build-id cache in |
1866 | * $HOME/.debug/[kernel.kallsyms]. | 1984 | * $HOME/.debug/[kernel.kallsyms]. |
1867 | */ | 1985 | */ |
1868 | build_id__sprintf(self->build_id, sizeof(self->build_id), | 1986 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), |
1869 | sbuild_id); | 1987 | sbuild_id); |
1870 | 1988 | ||
1871 | if (asprintf(&kallsyms_allocated_filename, | 1989 | if (asprintf(&kallsyms_allocated_filename, |
@@ -1892,7 +2010,7 @@ static int dso__load_kernel_sym(struct dso *self, struct map *map, | |||
1892 | } | 2010 | } |
1893 | 2011 | ||
1894 | do_kallsyms: | 2012 | do_kallsyms: |
1895 | err = dso__load_kallsyms(self, kallsyms_filename, map, filter); | 2013 | err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); |
1896 | if (err > 0) | 2014 | if (err > 0) |
1897 | pr_debug("Using %s for symbols\n", kallsyms_filename); | 2015 | pr_debug("Using %s for symbols\n", kallsyms_filename); |
1898 | free(kallsyms_allocated_filename); | 2016 | free(kallsyms_allocated_filename); |
@@ -1900,7 +2018,7 @@ do_kallsyms: | |||
1900 | if (err > 0) { | 2018 | if (err > 0) { |
1901 | out_fixup: | 2019 | out_fixup: |
1902 | if (kallsyms_filename != NULL) | 2020 | if (kallsyms_filename != NULL) |
1903 | dso__set_long_name(self, strdup("[kernel.kallsyms]")); | 2021 | dso__set_long_name(dso, strdup("[kernel.kallsyms]")); |
1904 | map__fixup_start(map); | 2022 | map__fixup_start(map); |
1905 | map__fixup_end(map); | 2023 | map__fixup_end(map); |
1906 | } | 2024 | } |
@@ -1908,8 +2026,8 @@ out_fixup: | |||
1908 | return err; | 2026 | return err; |
1909 | } | 2027 | } |
1910 | 2028 | ||
1911 | static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, | 2029 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
1912 | symbol_filter_t filter) | 2030 | symbol_filter_t filter) |
1913 | { | 2031 | { |
1914 | int err; | 2032 | int err; |
1915 | const char *kallsyms_filename = NULL; | 2033 | const char *kallsyms_filename = NULL; |
@@ -1929,7 +2047,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, | |||
1929 | * Or use file guest_kallsyms inputted by user on commandline | 2047 | * Or use file guest_kallsyms inputted by user on commandline |
1930 | */ | 2048 | */ |
1931 | if (symbol_conf.default_guest_vmlinux_name != NULL) { | 2049 | if (symbol_conf.default_guest_vmlinux_name != NULL) { |
1932 | err = dso__load_vmlinux(self, map, | 2050 | err = dso__load_vmlinux(dso, map, |
1933 | symbol_conf.default_guest_vmlinux_name, filter); | 2051 | symbol_conf.default_guest_vmlinux_name, filter); |
1934 | goto out_try_fixup; | 2052 | goto out_try_fixup; |
1935 | } | 2053 | } |
@@ -1942,7 +2060,7 @@ static int dso__load_guest_kernel_sym(struct dso *self, struct map *map, | |||
1942 | kallsyms_filename = path; | 2060 | kallsyms_filename = path; |
1943 | } | 2061 | } |
1944 | 2062 | ||
1945 | err = dso__load_kallsyms(self, kallsyms_filename, map, filter); | 2063 | err = dso__load_kallsyms(dso, kallsyms_filename, map, filter); |
1946 | if (err > 0) | 2064 | if (err > 0) |
1947 | pr_debug("Using %s for symbols\n", kallsyms_filename); | 2065 | pr_debug("Using %s for symbols\n", kallsyms_filename); |
1948 | 2066 | ||
@@ -1950,7 +2068,7 @@ out_try_fixup: | |||
1950 | if (err > 0) { | 2068 | if (err > 0) { |
1951 | if (kallsyms_filename != NULL) { | 2069 | if (kallsyms_filename != NULL) { |
1952 | machine__mmap_name(machine, path, sizeof(path)); | 2070 | machine__mmap_name(machine, path, sizeof(path)); |
1953 | dso__set_long_name(self, strdup(path)); | 2071 | dso__set_long_name(dso, strdup(path)); |
1954 | } | 2072 | } |
1955 | map__fixup_start(map); | 2073 | map__fixup_start(map); |
1956 | map__fixup_end(map); | 2074 | map__fixup_end(map); |
@@ -2003,12 +2121,12 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp) | |||
2003 | return ret; | 2121 | return ret; |
2004 | } | 2122 | } |
2005 | 2123 | ||
2006 | size_t machines__fprintf_dsos(struct rb_root *self, FILE *fp) | 2124 | size_t machines__fprintf_dsos(struct rb_root *machines, FILE *fp) |
2007 | { | 2125 | { |
2008 | struct rb_node *nd; | 2126 | struct rb_node *nd; |
2009 | size_t ret = 0; | 2127 | size_t ret = 0; |
2010 | 2128 | ||
2011 | for (nd = rb_first(self); nd; nd = rb_next(nd)) { | 2129 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { |
2012 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 2130 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
2013 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); | 2131 | ret += __dsos__fprintf(&pos->kernel_dsos, fp); |
2014 | ret += __dsos__fprintf(&pos->user_dsos, fp); | 2132 | ret += __dsos__fprintf(&pos->user_dsos, fp); |
@@ -2032,18 +2150,20 @@ static size_t __dsos__fprintf_buildid(struct list_head *head, FILE *fp, | |||
2032 | return ret; | 2150 | return ret; |
2033 | } | 2151 | } |
2034 | 2152 | ||
2035 | size_t machine__fprintf_dsos_buildid(struct machine *self, FILE *fp, bool with_hits) | 2153 | size_t machine__fprintf_dsos_buildid(struct machine *machine, FILE *fp, |
2154 | bool with_hits) | ||
2036 | { | 2155 | { |
2037 | return __dsos__fprintf_buildid(&self->kernel_dsos, fp, with_hits) + | 2156 | return __dsos__fprintf_buildid(&machine->kernel_dsos, fp, with_hits) + |
2038 | __dsos__fprintf_buildid(&self->user_dsos, fp, with_hits); | 2157 | __dsos__fprintf_buildid(&machine->user_dsos, fp, with_hits); |
2039 | } | 2158 | } |
2040 | 2159 | ||
2041 | size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_hits) | 2160 | size_t machines__fprintf_dsos_buildid(struct rb_root *machines, |
2161 | FILE *fp, bool with_hits) | ||
2042 | { | 2162 | { |
2043 | struct rb_node *nd; | 2163 | struct rb_node *nd; |
2044 | size_t ret = 0; | 2164 | size_t ret = 0; |
2045 | 2165 | ||
2046 | for (nd = rb_first(self); nd; nd = rb_next(nd)) { | 2166 | for (nd = rb_first(machines); nd; nd = rb_next(nd)) { |
2047 | struct machine *pos = rb_entry(nd, struct machine, rb_node); | 2167 | struct machine *pos = rb_entry(nd, struct machine, rb_node); |
2048 | ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); | 2168 | ret += machine__fprintf_dsos_buildid(pos, fp, with_hits); |
2049 | } | 2169 | } |
@@ -2052,97 +2172,143 @@ size_t machines__fprintf_dsos_buildid(struct rb_root *self, FILE *fp, bool with_ | |||
2052 | 2172 | ||
2053 | struct dso *dso__new_kernel(const char *name) | 2173 | struct dso *dso__new_kernel(const char *name) |
2054 | { | 2174 | { |
2055 | struct dso *self = dso__new(name ?: "[kernel.kallsyms]"); | 2175 | struct dso *dso = dso__new(name ?: "[kernel.kallsyms]"); |
2056 | 2176 | ||
2057 | if (self != NULL) { | 2177 | if (dso != NULL) { |
2058 | dso__set_short_name(self, "[kernel]"); | 2178 | dso__set_short_name(dso, "[kernel]"); |
2059 | self->kernel = DSO_TYPE_KERNEL; | 2179 | dso->kernel = DSO_TYPE_KERNEL; |
2060 | } | 2180 | } |
2061 | 2181 | ||
2062 | return self; | 2182 | return dso; |
2063 | } | 2183 | } |
2064 | 2184 | ||
2065 | static struct dso *dso__new_guest_kernel(struct machine *machine, | 2185 | static struct dso *dso__new_guest_kernel(struct machine *machine, |
2066 | const char *name) | 2186 | const char *name) |
2067 | { | 2187 | { |
2068 | char bf[PATH_MAX]; | 2188 | char bf[PATH_MAX]; |
2069 | struct dso *self = dso__new(name ?: machine__mmap_name(machine, bf, sizeof(bf))); | 2189 | struct dso *dso = dso__new(name ?: machine__mmap_name(machine, bf, |
2070 | 2190 | sizeof(bf))); | |
2071 | if (self != NULL) { | 2191 | if (dso != NULL) { |
2072 | dso__set_short_name(self, "[guest.kernel]"); | 2192 | dso__set_short_name(dso, "[guest.kernel]"); |
2073 | self->kernel = DSO_TYPE_GUEST_KERNEL; | 2193 | dso->kernel = DSO_TYPE_GUEST_KERNEL; |
2074 | } | 2194 | } |
2075 | 2195 | ||
2076 | return self; | 2196 | return dso; |
2077 | } | 2197 | } |
2078 | 2198 | ||
2079 | void dso__read_running_kernel_build_id(struct dso *self, struct machine *machine) | 2199 | void dso__read_running_kernel_build_id(struct dso *dso, struct machine *machine) |
2080 | { | 2200 | { |
2081 | char path[PATH_MAX]; | 2201 | char path[PATH_MAX]; |
2082 | 2202 | ||
2083 | if (machine__is_default_guest(machine)) | 2203 | if (machine__is_default_guest(machine)) |
2084 | return; | 2204 | return; |
2085 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); | 2205 | sprintf(path, "%s/sys/kernel/notes", machine->root_dir); |
2086 | if (sysfs__read_build_id(path, self->build_id, | 2206 | if (sysfs__read_build_id(path, dso->build_id, |
2087 | sizeof(self->build_id)) == 0) | 2207 | sizeof(dso->build_id)) == 0) |
2088 | self->has_build_id = true; | 2208 | dso->has_build_id = true; |
2089 | } | 2209 | } |
2090 | 2210 | ||
2091 | static struct dso *machine__create_kernel(struct machine *self) | 2211 | static struct dso *machine__create_kernel(struct machine *machine) |
2092 | { | 2212 | { |
2093 | const char *vmlinux_name = NULL; | 2213 | const char *vmlinux_name = NULL; |
2094 | struct dso *kernel; | 2214 | struct dso *kernel; |
2095 | 2215 | ||
2096 | if (machine__is_host(self)) { | 2216 | if (machine__is_host(machine)) { |
2097 | vmlinux_name = symbol_conf.vmlinux_name; | 2217 | vmlinux_name = symbol_conf.vmlinux_name; |
2098 | kernel = dso__new_kernel(vmlinux_name); | 2218 | kernel = dso__new_kernel(vmlinux_name); |
2099 | } else { | 2219 | } else { |
2100 | if (machine__is_default_guest(self)) | 2220 | if (machine__is_default_guest(machine)) |
2101 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; | 2221 | vmlinux_name = symbol_conf.default_guest_vmlinux_name; |
2102 | kernel = dso__new_guest_kernel(self, vmlinux_name); | 2222 | kernel = dso__new_guest_kernel(machine, vmlinux_name); |
2103 | } | 2223 | } |
2104 | 2224 | ||
2105 | if (kernel != NULL) { | 2225 | if (kernel != NULL) { |
2106 | dso__read_running_kernel_build_id(kernel, self); | 2226 | dso__read_running_kernel_build_id(kernel, machine); |
2107 | dsos__add(&self->kernel_dsos, kernel); | 2227 | dsos__add(&machine->kernel_dsos, kernel); |
2108 | } | 2228 | } |
2109 | return kernel; | 2229 | return kernel; |
2110 | } | 2230 | } |
2111 | 2231 | ||
2112 | int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) | 2232 | struct process_args { |
2233 | u64 start; | ||
2234 | }; | ||
2235 | |||
2236 | static int symbol__in_kernel(void *arg, const char *name, | ||
2237 | char type __used, u64 start, u64 end __used) | ||
2238 | { | ||
2239 | struct process_args *args = arg; | ||
2240 | |||
2241 | if (strchr(name, '[')) | ||
2242 | return 0; | ||
2243 | |||
2244 | args->start = start; | ||
2245 | return 1; | ||
2246 | } | ||
2247 | |||
2248 | /* Figure out the start address of kernel map from /proc/kallsyms */ | ||
2249 | static u64 machine__get_kernel_start_addr(struct machine *machine) | ||
2250 | { | ||
2251 | const char *filename; | ||
2252 | char path[PATH_MAX]; | ||
2253 | struct process_args args; | ||
2254 | |||
2255 | if (machine__is_host(machine)) { | ||
2256 | filename = "/proc/kallsyms"; | ||
2257 | } else { | ||
2258 | if (machine__is_default_guest(machine)) | ||
2259 | filename = (char *)symbol_conf.default_guest_kallsyms; | ||
2260 | else { | ||
2261 | sprintf(path, "%s/proc/kallsyms", machine->root_dir); | ||
2262 | filename = path; | ||
2263 | } | ||
2264 | } | ||
2265 | |||
2266 | if (symbol__restricted_filename(filename, "/proc/kallsyms")) | ||
2267 | return 0; | ||
2268 | |||
2269 | if (kallsyms__parse(filename, &args, symbol__in_kernel) <= 0) | ||
2270 | return 0; | ||
2271 | |||
2272 | return args.start; | ||
2273 | } | ||
2274 | |||
2275 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel) | ||
2113 | { | 2276 | { |
2114 | enum map_type type; | 2277 | enum map_type type; |
2278 | u64 start = machine__get_kernel_start_addr(machine); | ||
2115 | 2279 | ||
2116 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 2280 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
2117 | struct kmap *kmap; | 2281 | struct kmap *kmap; |
2118 | 2282 | ||
2119 | self->vmlinux_maps[type] = map__new2(0, kernel, type); | 2283 | machine->vmlinux_maps[type] = map__new2(start, kernel, type); |
2120 | if (self->vmlinux_maps[type] == NULL) | 2284 | if (machine->vmlinux_maps[type] == NULL) |
2121 | return -1; | 2285 | return -1; |
2122 | 2286 | ||
2123 | self->vmlinux_maps[type]->map_ip = | 2287 | machine->vmlinux_maps[type]->map_ip = |
2124 | self->vmlinux_maps[type]->unmap_ip = identity__map_ip; | 2288 | machine->vmlinux_maps[type]->unmap_ip = |
2125 | 2289 | identity__map_ip; | |
2126 | kmap = map__kmap(self->vmlinux_maps[type]); | 2290 | kmap = map__kmap(machine->vmlinux_maps[type]); |
2127 | kmap->kmaps = &self->kmaps; | 2291 | kmap->kmaps = &machine->kmaps; |
2128 | map_groups__insert(&self->kmaps, self->vmlinux_maps[type]); | 2292 | map_groups__insert(&machine->kmaps, |
2293 | machine->vmlinux_maps[type]); | ||
2129 | } | 2294 | } |
2130 | 2295 | ||
2131 | return 0; | 2296 | return 0; |
2132 | } | 2297 | } |
2133 | 2298 | ||
2134 | void machine__destroy_kernel_maps(struct machine *self) | 2299 | void machine__destroy_kernel_maps(struct machine *machine) |
2135 | { | 2300 | { |
2136 | enum map_type type; | 2301 | enum map_type type; |
2137 | 2302 | ||
2138 | for (type = 0; type < MAP__NR_TYPES; ++type) { | 2303 | for (type = 0; type < MAP__NR_TYPES; ++type) { |
2139 | struct kmap *kmap; | 2304 | struct kmap *kmap; |
2140 | 2305 | ||
2141 | if (self->vmlinux_maps[type] == NULL) | 2306 | if (machine->vmlinux_maps[type] == NULL) |
2142 | continue; | 2307 | continue; |
2143 | 2308 | ||
2144 | kmap = map__kmap(self->vmlinux_maps[type]); | 2309 | kmap = map__kmap(machine->vmlinux_maps[type]); |
2145 | map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); | 2310 | map_groups__remove(&machine->kmaps, |
2311 | machine->vmlinux_maps[type]); | ||
2146 | if (kmap->ref_reloc_sym) { | 2312 | if (kmap->ref_reloc_sym) { |
2147 | /* | 2313 | /* |
2148 | * ref_reloc_sym is shared among all maps, so free just | 2314 | * ref_reloc_sym is shared among all maps, so free just |
@@ -2156,25 +2322,25 @@ void machine__destroy_kernel_maps(struct machine *self) | |||
2156 | kmap->ref_reloc_sym = NULL; | 2322 | kmap->ref_reloc_sym = NULL; |
2157 | } | 2323 | } |
2158 | 2324 | ||
2159 | map__delete(self->vmlinux_maps[type]); | 2325 | map__delete(machine->vmlinux_maps[type]); |
2160 | self->vmlinux_maps[type] = NULL; | 2326 | machine->vmlinux_maps[type] = NULL; |
2161 | } | 2327 | } |
2162 | } | 2328 | } |
2163 | 2329 | ||
2164 | int machine__create_kernel_maps(struct machine *self) | 2330 | int machine__create_kernel_maps(struct machine *machine) |
2165 | { | 2331 | { |
2166 | struct dso *kernel = machine__create_kernel(self); | 2332 | struct dso *kernel = machine__create_kernel(machine); |
2167 | 2333 | ||
2168 | if (kernel == NULL || | 2334 | if (kernel == NULL || |
2169 | __machine__create_kernel_maps(self, kernel) < 0) | 2335 | __machine__create_kernel_maps(machine, kernel) < 0) |
2170 | return -1; | 2336 | return -1; |
2171 | 2337 | ||
2172 | if (symbol_conf.use_modules && machine__create_modules(self) < 0) | 2338 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) |
2173 | pr_debug("Problems creating module maps, continuing anyway...\n"); | 2339 | pr_debug("Problems creating module maps, continuing anyway...\n"); |
2174 | /* | 2340 | /* |
2175 | * Now that we have all the maps created, just set the ->end of them: | 2341 | * Now that we have all the maps created, just set the ->end of them: |
2176 | */ | 2342 | */ |
2177 | map_groups__fixup_end(&self->kmaps); | 2343 | map_groups__fixup_end(&machine->kmaps); |
2178 | return 0; | 2344 | return 0; |
2179 | } | 2345 | } |
2180 | 2346 | ||
@@ -2194,9 +2360,6 @@ static int vmlinux_path__init(void) | |||
2194 | struct utsname uts; | 2360 | struct utsname uts; |
2195 | char bf[PATH_MAX]; | 2361 | char bf[PATH_MAX]; |
2196 | 2362 | ||
2197 | if (uname(&uts) < 0) | ||
2198 | return -1; | ||
2199 | |||
2200 | vmlinux_path = malloc(sizeof(char *) * 5); | 2363 | vmlinux_path = malloc(sizeof(char *) * 5); |
2201 | if (vmlinux_path == NULL) | 2364 | if (vmlinux_path == NULL) |
2202 | return -1; | 2365 | return -1; |
@@ -2209,6 +2372,14 @@ static int vmlinux_path__init(void) | |||
2209 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 2372 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
2210 | goto out_fail; | 2373 | goto out_fail; |
2211 | ++vmlinux_path__nr_entries; | 2374 | ++vmlinux_path__nr_entries; |
2375 | |||
2376 | /* only try running kernel version if no symfs was given */ | ||
2377 | if (symbol_conf.symfs[0] != 0) | ||
2378 | return 0; | ||
2379 | |||
2380 | if (uname(&uts) < 0) | ||
2381 | return -1; | ||
2382 | |||
2212 | snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); | 2383 | snprintf(bf, sizeof(bf), "/boot/vmlinux-%s", uts.release); |
2213 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); | 2384 | vmlinux_path[vmlinux_path__nr_entries] = strdup(bf); |
2214 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) | 2385 | if (vmlinux_path[vmlinux_path__nr_entries] == NULL) |
@@ -2233,11 +2404,11 @@ out_fail: | |||
2233 | return -1; | 2404 | return -1; |
2234 | } | 2405 | } |
2235 | 2406 | ||
2236 | size_t machine__fprintf_vmlinux_path(struct machine *self, FILE *fp) | 2407 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) |
2237 | { | 2408 | { |
2238 | int i; | 2409 | int i; |
2239 | size_t printed = 0; | 2410 | size_t printed = 0; |
2240 | struct dso *kdso = self->vmlinux_maps[MAP__FUNCTION]->dso; | 2411 | struct dso *kdso = machine->vmlinux_maps[MAP__FUNCTION]->dso; |
2241 | 2412 | ||
2242 | if (kdso->has_build_id) { | 2413 | if (kdso->has_build_id) { |
2243 | char filename[PATH_MAX]; | 2414 | char filename[PATH_MAX]; |
@@ -2266,11 +2437,34 @@ static int setup_list(struct strlist **list, const char *list_str, | |||
2266 | return 0; | 2437 | return 0; |
2267 | } | 2438 | } |
2268 | 2439 | ||
2440 | static bool symbol__read_kptr_restrict(void) | ||
2441 | { | ||
2442 | bool value = false; | ||
2443 | |||
2444 | if (geteuid() != 0) { | ||
2445 | FILE *fp = fopen("/proc/sys/kernel/kptr_restrict", "r"); | ||
2446 | if (fp != NULL) { | ||
2447 | char line[8]; | ||
2448 | |||
2449 | if (fgets(line, sizeof(line), fp) != NULL) | ||
2450 | value = atoi(line) != 0; | ||
2451 | |||
2452 | fclose(fp); | ||
2453 | } | ||
2454 | } | ||
2455 | |||
2456 | return value; | ||
2457 | } | ||
2458 | |||
2269 | int symbol__init(void) | 2459 | int symbol__init(void) |
2270 | { | 2460 | { |
2461 | const char *symfs; | ||
2462 | |||
2271 | if (symbol_conf.initialized) | 2463 | if (symbol_conf.initialized) |
2272 | return 0; | 2464 | return 0; |
2273 | 2465 | ||
2466 | symbol_conf.priv_size = ALIGN(symbol_conf.priv_size, sizeof(u64)); | ||
2467 | |||
2274 | elf_version(EV_CURRENT); | 2468 | elf_version(EV_CURRENT); |
2275 | if (symbol_conf.sort_by_name) | 2469 | if (symbol_conf.sort_by_name) |
2276 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - | 2470 | symbol_conf.priv_size += (sizeof(struct symbol_name_rb_node) - |
@@ -2296,6 +2490,20 @@ int symbol__init(void) | |||
2296 | symbol_conf.sym_list_str, "symbol") < 0) | 2490 | symbol_conf.sym_list_str, "symbol") < 0) |
2297 | goto out_free_comm_list; | 2491 | goto out_free_comm_list; |
2298 | 2492 | ||
2493 | /* | ||
2494 | * A path to symbols of "/" is identical to "" | ||
2495 | * reset here for simplicity. | ||
2496 | */ | ||
2497 | symfs = realpath(symbol_conf.symfs, NULL); | ||
2498 | if (symfs == NULL) | ||
2499 | symfs = symbol_conf.symfs; | ||
2500 | if (strcmp(symfs, "/") == 0) | ||
2501 | symbol_conf.symfs = ""; | ||
2502 | if (symfs != symbol_conf.symfs) | ||
2503 | free((void *)symfs); | ||
2504 | |||
2505 | symbol_conf.kptr_restrict = symbol__read_kptr_restrict(); | ||
2506 | |||
2299 | symbol_conf.initialized = true; | 2507 | symbol_conf.initialized = true; |
2300 | return 0; | 2508 | return 0; |
2301 | 2509 | ||
@@ -2318,9 +2526,9 @@ void symbol__exit(void) | |||
2318 | symbol_conf.initialized = false; | 2526 | symbol_conf.initialized = false; |
2319 | } | 2527 | } |
2320 | 2528 | ||
2321 | int machines__create_kernel_maps(struct rb_root *self, pid_t pid) | 2529 | int machines__create_kernel_maps(struct rb_root *machines, pid_t pid) |
2322 | { | 2530 | { |
2323 | struct machine *machine = machines__findnew(self, pid); | 2531 | struct machine *machine = machines__findnew(machines, pid); |
2324 | 2532 | ||
2325 | if (machine == NULL) | 2533 | if (machine == NULL) |
2326 | return -1; | 2534 | return -1; |
@@ -2371,7 +2579,7 @@ char *strxfrchar(char *s, char from, char to) | |||
2371 | return s; | 2579 | return s; |
2372 | } | 2580 | } |
2373 | 2581 | ||
2374 | int machines__create_guest_kernel_maps(struct rb_root *self) | 2582 | int machines__create_guest_kernel_maps(struct rb_root *machines) |
2375 | { | 2583 | { |
2376 | int ret = 0; | 2584 | int ret = 0; |
2377 | struct dirent **namelist = NULL; | 2585 | struct dirent **namelist = NULL; |
@@ -2382,7 +2590,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self) | |||
2382 | if (symbol_conf.default_guest_vmlinux_name || | 2590 | if (symbol_conf.default_guest_vmlinux_name || |
2383 | symbol_conf.default_guest_modules || | 2591 | symbol_conf.default_guest_modules || |
2384 | symbol_conf.default_guest_kallsyms) { | 2592 | symbol_conf.default_guest_kallsyms) { |
2385 | machines__create_kernel_maps(self, DEFAULT_GUEST_KERNEL_ID); | 2593 | machines__create_kernel_maps(machines, DEFAULT_GUEST_KERNEL_ID); |
2386 | } | 2594 | } |
2387 | 2595 | ||
2388 | if (symbol_conf.guestmount) { | 2596 | if (symbol_conf.guestmount) { |
@@ -2403,7 +2611,7 @@ int machines__create_guest_kernel_maps(struct rb_root *self) | |||
2403 | pr_debug("Can't access file %s\n", path); | 2611 | pr_debug("Can't access file %s\n", path); |
2404 | goto failure; | 2612 | goto failure; |
2405 | } | 2613 | } |
2406 | machines__create_kernel_maps(self, pid); | 2614 | machines__create_kernel_maps(machines, pid); |
2407 | } | 2615 | } |
2408 | failure: | 2616 | failure: |
2409 | free(namelist); | 2617 | free(namelist); |
@@ -2412,23 +2620,23 @@ failure: | |||
2412 | return ret; | 2620 | return ret; |
2413 | } | 2621 | } |
2414 | 2622 | ||
2415 | void machines__destroy_guest_kernel_maps(struct rb_root *self) | 2623 | void machines__destroy_guest_kernel_maps(struct rb_root *machines) |
2416 | { | 2624 | { |
2417 | struct rb_node *next = rb_first(self); | 2625 | struct rb_node *next = rb_first(machines); |
2418 | 2626 | ||
2419 | while (next) { | 2627 | while (next) { |
2420 | struct machine *pos = rb_entry(next, struct machine, rb_node); | 2628 | struct machine *pos = rb_entry(next, struct machine, rb_node); |
2421 | 2629 | ||
2422 | next = rb_next(&pos->rb_node); | 2630 | next = rb_next(&pos->rb_node); |
2423 | rb_erase(&pos->rb_node, self); | 2631 | rb_erase(&pos->rb_node, machines); |
2424 | machine__delete(pos); | 2632 | machine__delete(pos); |
2425 | } | 2633 | } |
2426 | } | 2634 | } |
2427 | 2635 | ||
2428 | int machine__load_kallsyms(struct machine *self, const char *filename, | 2636 | int machine__load_kallsyms(struct machine *machine, const char *filename, |
2429 | enum map_type type, symbol_filter_t filter) | 2637 | enum map_type type, symbol_filter_t filter) |
2430 | { | 2638 | { |
2431 | struct map *map = self->vmlinux_maps[type]; | 2639 | struct map *map = machine->vmlinux_maps[type]; |
2432 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | 2640 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); |
2433 | 2641 | ||
2434 | if (ret > 0) { | 2642 | if (ret > 0) { |
@@ -2438,16 +2646,16 @@ int machine__load_kallsyms(struct machine *self, const char *filename, | |||
2438 | * kernel, with modules between them, fixup the end of all | 2646 | * kernel, with modules between them, fixup the end of all |
2439 | * sections. | 2647 | * sections. |
2440 | */ | 2648 | */ |
2441 | __map_groups__fixup_end(&self->kmaps, type); | 2649 | __map_groups__fixup_end(&machine->kmaps, type); |
2442 | } | 2650 | } |
2443 | 2651 | ||
2444 | return ret; | 2652 | return ret; |
2445 | } | 2653 | } |
2446 | 2654 | ||
2447 | int machine__load_vmlinux_path(struct machine *self, enum map_type type, | 2655 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
2448 | symbol_filter_t filter) | 2656 | symbol_filter_t filter) |
2449 | { | 2657 | { |
2450 | struct map *map = self->vmlinux_maps[type]; | 2658 | struct map *map = machine->vmlinux_maps[type]; |
2451 | int ret = dso__load_vmlinux_path(map->dso, map, filter); | 2659 | int ret = dso__load_vmlinux_path(map->dso, map, filter); |
2452 | 2660 | ||
2453 | if (ret > 0) { | 2661 | if (ret > 0) { |