diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-record.c | 7 | ||||
-rw-r--r-- | tools/perf/util/event.c | 64 | ||||
-rw-r--r-- | tools/perf/util/event.h | 4 | ||||
-rw-r--r-- | tools/perf/util/session.c | 46 | ||||
-rw-r--r-- | tools/perf/util/session.h | 10 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 7 |
6 files changed, 133 insertions, 5 deletions
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 265425322734..8f88420e066b 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -551,6 +551,13 @@ static int __cmd_record(int argc, const char **argv) | |||
551 | return err; | 551 | return err; |
552 | } | 552 | } |
553 | 553 | ||
554 | err = event__synthesize_kernel_mmap(process_synthesized_event, | ||
555 | session, "_text"); | ||
556 | if (err < 0) { | ||
557 | pr_err("Couldn't record kernel reference relocation symbol.\n"); | ||
558 | return err; | ||
559 | } | ||
560 | |||
554 | if (!system_wide && profile_cpu == -1) | 561 | if (!system_wide && profile_cpu == -1) |
555 | event__synthesize_thread(pid, process_synthesized_event, | 562 | event__synthesize_thread(pid, process_synthesized_event, |
556 | session); | 563 | session); |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index bb0fd6da2d56..1a31feb9999f 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -189,6 +189,50 @@ void event__synthesize_threads(int (*process)(event_t *event, | |||
189 | closedir(proc); | 189 | closedir(proc); |
190 | } | 190 | } |
191 | 191 | ||
192 | struct process_symbol_args { | ||
193 | const char *name; | ||
194 | u64 start; | ||
195 | }; | ||
196 | |||
197 | static int find_symbol_cb(void *arg, const char *name, char type, u64 start) | ||
198 | { | ||
199 | struct process_symbol_args *args = arg; | ||
200 | |||
201 | if (!symbol_type__is_a(type, MAP__FUNCTION) || strcmp(name, args->name)) | ||
202 | return 0; | ||
203 | |||
204 | args->start = start; | ||
205 | return 1; | ||
206 | } | ||
207 | |||
208 | int event__synthesize_kernel_mmap(int (*process)(event_t *event, | ||
209 | struct perf_session *session), | ||
210 | struct perf_session *session, | ||
211 | const char *symbol_name) | ||
212 | { | ||
213 | size_t size; | ||
214 | event_t ev = { | ||
215 | .header = { .type = PERF_RECORD_MMAP }, | ||
216 | }; | ||
217 | /* | ||
218 | * We should get this from /sys/kernel/sections/.text, but till that is | ||
219 | * available use this, and after it is use this as a fallback for older | ||
220 | * kernels. | ||
221 | */ | ||
222 | struct process_symbol_args args = { .name = symbol_name, }; | ||
223 | |||
224 | if (kallsyms__parse(&args, find_symbol_cb) <= 0) | ||
225 | return -ENOENT; | ||
226 | |||
227 | size = snprintf(ev.mmap.filename, sizeof(ev.mmap.filename), | ||
228 | "[kernel.kallsyms.%s]", symbol_name) + 1; | ||
229 | size = ALIGN(size, sizeof(u64)); | ||
230 | ev.mmap.header.size = (sizeof(ev.mmap) - (sizeof(ev.mmap.filename) - size)); | ||
231 | ev.mmap.start = args.start; | ||
232 | |||
233 | return process(&ev, session); | ||
234 | } | ||
235 | |||
192 | static void thread__comm_adjust(struct thread *self) | 236 | static void thread__comm_adjust(struct thread *self) |
193 | { | 237 | { |
194 | char *comm = self->comm; | 238 | char *comm = self->comm; |
@@ -240,9 +284,9 @@ int event__process_lost(event_t *self, struct perf_session *session) | |||
240 | 284 | ||
241 | int event__process_mmap(event_t *self, struct perf_session *session) | 285 | int event__process_mmap(event_t *self, struct perf_session *session) |
242 | { | 286 | { |
243 | struct thread *thread = perf_session__findnew(session, self->mmap.pid); | 287 | struct thread *thread; |
244 | struct map *map = map__new(&self->mmap, MAP__FUNCTION, | 288 | struct map *map; |
245 | session->cwd, session->cwdlen); | 289 | static const char kmmap_prefix[] = "[kernel.kallsyms."; |
246 | 290 | ||
247 | dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", | 291 | dump_printf(" %d/%d: [%p(%p) @ %p]: %s\n", |
248 | self->mmap.pid, self->mmap.tid, | 292 | self->mmap.pid, self->mmap.tid, |
@@ -251,6 +295,20 @@ int event__process_mmap(event_t *self, struct perf_session *session) | |||
251 | (void *)(long)self->mmap.pgoff, | 295 | (void *)(long)self->mmap.pgoff, |
252 | self->mmap.filename); | 296 | self->mmap.filename); |
253 | 297 | ||
298 | if (self->mmap.pid == 0 && | ||
299 | memcmp(self->mmap.filename, kmmap_prefix, | ||
300 | sizeof(kmmap_prefix) - 1) == 0) { | ||
301 | const char *symbol_name = (self->mmap.filename + | ||
302 | sizeof(kmmap_prefix) - 1); | ||
303 | perf_session__set_kallsyms_ref_reloc_sym(session, symbol_name, | ||
304 | self->mmap.start); | ||
305 | return 0; | ||
306 | } | ||
307 | |||
308 | thread = perf_session__findnew(session, self->mmap.pid); | ||
309 | map = map__new(&self->mmap, MAP__FUNCTION, | ||
310 | session->cwd, session->cwdlen); | ||
311 | |||
254 | if (thread == NULL || map == NULL) | 312 | if (thread == NULL || map == NULL) |
255 | dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); | 313 | dump_printf("problem processing PERF_RECORD_MMAP, skipping event.\n"); |
256 | else | 314 | else |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 80fb3653c809..61fc0dc658c2 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -110,6 +110,10 @@ int event__synthesize_thread(pid_t pid, | |||
110 | void event__synthesize_threads(int (*process)(event_t *event, | 110 | void event__synthesize_threads(int (*process)(event_t *event, |
111 | struct perf_session *session), | 111 | struct perf_session *session), |
112 | struct perf_session *session); | 112 | struct perf_session *session); |
113 | int event__synthesize_kernel_mmap(int (*process)(event_t *event, | ||
114 | struct perf_session *session), | ||
115 | struct perf_session *session, | ||
116 | const char *symbol_name); | ||
113 | 117 | ||
114 | int event__process_comm(event_t *self, struct perf_session *session); | 118 | int event__process_comm(event_t *self, struct perf_session *session); |
115 | int event__process_lost(event_t *self, struct perf_session *session); | 119 | int event__process_lost(event_t *self, struct perf_session *session); |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 7f0537d1add8..e0e6a075489e 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -401,3 +401,49 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg) | |||
401 | 401 | ||
402 | return true; | 402 | return true; |
403 | } | 403 | } |
404 | |||
405 | int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, | ||
406 | const char *symbol_name, | ||
407 | u64 addr) | ||
408 | { | ||
409 | char *bracket; | ||
410 | |||
411 | self->ref_reloc_sym.name = strdup(symbol_name); | ||
412 | if (self->ref_reloc_sym.name == NULL) | ||
413 | return -ENOMEM; | ||
414 | |||
415 | bracket = strchr(self->ref_reloc_sym.name, ']'); | ||
416 | if (bracket) | ||
417 | *bracket = '\0'; | ||
418 | |||
419 | self->ref_reloc_sym.addr = addr; | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static u64 map__reloc_map_ip(struct map *map, u64 ip) | ||
424 | { | ||
425 | return ip + (s64)map->pgoff; | ||
426 | } | ||
427 | |||
428 | static u64 map__reloc_unmap_ip(struct map *map, u64 ip) | ||
429 | { | ||
430 | return ip - (s64)map->pgoff; | ||
431 | } | ||
432 | |||
433 | void perf_session__reloc_vmlinux_maps(struct perf_session *self, | ||
434 | u64 unrelocated_addr) | ||
435 | { | ||
436 | enum map_type type; | ||
437 | s64 reloc = unrelocated_addr - self->ref_reloc_sym.addr; | ||
438 | |||
439 | if (!reloc) | ||
440 | return; | ||
441 | |||
442 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
443 | struct map *map = self->vmlinux_maps[type]; | ||
444 | |||
445 | map->map_ip = map__reloc_map_ip; | ||
446 | map->unmap_ip = map__reloc_unmap_ip; | ||
447 | map->pgoff = reloc; | ||
448 | } | ||
449 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 8db37bbf0e62..d4a9d20f8d44 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -24,6 +24,10 @@ struct perf_session { | |||
24 | unsigned long unknown_events; | 24 | unsigned long unknown_events; |
25 | struct rb_root hists; | 25 | struct rb_root hists; |
26 | u64 sample_type; | 26 | u64 sample_type; |
27 | struct { | ||
28 | const char *name; | ||
29 | u64 addr; | ||
30 | } ref_reloc_sym; | ||
27 | int fd; | 31 | int fd; |
28 | int cwdlen; | 32 | int cwdlen; |
29 | char *cwd; | 33 | char *cwd; |
@@ -59,4 +63,10 @@ bool perf_session__has_traces(struct perf_session *self, const char *msg); | |||
59 | 63 | ||
60 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); | 64 | int perf_header__read_build_ids(int input, u64 offset, u64 file_size); |
61 | 65 | ||
66 | int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self, | ||
67 | const char *symbol_name, | ||
68 | u64 addr); | ||
69 | void perf_session__reloc_vmlinux_maps(struct perf_session *self, | ||
70 | u64 unrelocated_addr); | ||
71 | |||
62 | #endif /* __PERF_SESSION_H */ | 72 | #endif /* __PERF_SESSION_H */ |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e290429e9c00..da2f07f1af8f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -956,11 +956,15 @@ static int dso__load_sym(struct dso *self, struct map *map, | |||
956 | 956 | ||
957 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { | 957 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { |
958 | struct symbol *f; | 958 | struct symbol *f; |
959 | const char *elf_name; | 959 | const char *elf_name = elf_sym__name(&sym, symstrs); |
960 | char *demangled = NULL; | 960 | char *demangled = NULL; |
961 | int is_label = elf_sym__is_label(&sym); | 961 | int is_label = elf_sym__is_label(&sym); |
962 | const char *section_name; | 962 | const char *section_name; |
963 | 963 | ||
964 | if (kernel && session->ref_reloc_sym.name != NULL && | ||
965 | strcmp(elf_name, session->ref_reloc_sym.name) == 0) | ||
966 | perf_session__reloc_vmlinux_maps(session, sym.st_value); | ||
967 | |||
964 | if (!is_label && !elf_sym__is_a(&sym, map->type)) | 968 | if (!is_label && !elf_sym__is_a(&sym, map->type)) |
965 | continue; | 969 | continue; |
966 | 970 | ||
@@ -973,7 +977,6 @@ static int dso__load_sym(struct dso *self, struct map *map, | |||
973 | if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) | 977 | if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) |
974 | continue; | 978 | continue; |
975 | 979 | ||
976 | elf_name = elf_sym__name(&sym, symstrs); | ||
977 | section_name = elf_sec__name(&shdr, secstrs); | 980 | section_name = elf_sec__name(&shdr, secstrs); |
978 | 981 | ||
979 | if (kernel || kmodule) { | 982 | if (kernel || kmodule) { |