aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-record.c7
-rw-r--r--tools/perf/util/event.c64
-rw-r--r--tools/perf/util/event.h4
-rw-r--r--tools/perf/util/session.c46
-rw-r--r--tools/perf/util/session.h10
-rw-r--r--tools/perf/util/symbol.c7
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
192struct process_symbol_args {
193 const char *name;
194 u64 start;
195};
196
197static 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
208int 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
192static void thread__comm_adjust(struct thread *self) 236static 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
241int event__process_mmap(event_t *self, struct perf_session *session) 285int 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,
110void event__synthesize_threads(int (*process)(event_t *event, 110void 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);
113int 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
114int event__process_comm(event_t *self, struct perf_session *session); 118int event__process_comm(event_t *self, struct perf_session *session);
115int event__process_lost(event_t *self, struct perf_session *session); 119int 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
405int 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
423static u64 map__reloc_map_ip(struct map *map, u64 ip)
424{
425 return ip + (s64)map->pgoff;
426}
427
428static u64 map__reloc_unmap_ip(struct map *map, u64 ip)
429{
430 return ip - (s64)map->pgoff;
431}
432
433void 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
60int perf_header__read_build_ids(int input, u64 offset, u64 file_size); 64int perf_header__read_build_ids(int input, u64 offset, u64 file_size);
61 65
66int perf_session__set_kallsyms_ref_reloc_sym(struct perf_session *self,
67 const char *symbol_name,
68 u64 addr);
69void 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) {