aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-rw-r--r--tools/perf/util/event.c36
-rw-r--r--tools/perf/util/event.h6
-rw-r--r--tools/perf/util/include/asm/hash.h6
-rw-r--r--tools/perf/util/machine.c42
-rw-r--r--tools/perf/util/machine.h2
-rw-r--r--tools/perf/util/map.c5
-rw-r--r--tools/perf/util/map.h1
-rw-r--r--tools/perf/util/symbol-elf.c4
-rw-r--r--tools/perf/util/symbol.c65
9 files changed, 129 insertions, 38 deletions
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 1fc1c2f04772..b0f3ca850e9e 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -470,23 +470,32 @@ static int find_symbol_cb(void *arg, const char *name, char type,
470 return 1; 470 return 1;
471} 471}
472 472
473u64 kallsyms__get_function_start(const char *kallsyms_filename,
474 const char *symbol_name)
475{
476 struct process_symbol_args args = { .name = symbol_name, };
477
478 if (kallsyms__parse(kallsyms_filename, &args, find_symbol_cb) <= 0)
479 return 0;
480
481 return args.start;
482}
483
473int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 484int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
474 perf_event__handler_t process, 485 perf_event__handler_t process,
475 struct machine *machine, 486 struct machine *machine)
476 const char *symbol_name)
477{ 487{
478 size_t size; 488 size_t size;
479 const char *filename, *mmap_name; 489 const char *mmap_name;
480 char path[PATH_MAX];
481 char name_buff[PATH_MAX]; 490 char name_buff[PATH_MAX];
482 struct map *map; 491 struct map *map;
492 struct kmap *kmap;
483 int err; 493 int err;
484 /* 494 /*
485 * We should get this from /sys/kernel/sections/.text, but till that is 495 * We should get this from /sys/kernel/sections/.text, but till that is
486 * available use this, and after it is use this as a fallback for older 496 * available use this, and after it is use this as a fallback for older
487 * kernels. 497 * kernels.
488 */ 498 */
489 struct process_symbol_args args = { .name = symbol_name, };
490 union perf_event *event = zalloc((sizeof(event->mmap) + 499 union perf_event *event = zalloc((sizeof(event->mmap) +
491 machine->id_hdr_size)); 500 machine->id_hdr_size));
492 if (event == NULL) { 501 if (event == NULL) {
@@ -502,30 +511,19 @@ int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
502 * see kernel/perf_event.c __perf_event_mmap 511 * see kernel/perf_event.c __perf_event_mmap
503 */ 512 */
504 event->header.misc = PERF_RECORD_MISC_KERNEL; 513 event->header.misc = PERF_RECORD_MISC_KERNEL;
505 filename = "/proc/kallsyms";
506 } else { 514 } else {
507 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL; 515 event->header.misc = PERF_RECORD_MISC_GUEST_KERNEL;
508 if (machine__is_default_guest(machine))
509 filename = (char *) symbol_conf.default_guest_kallsyms;
510 else {
511 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
512 filename = path;
513 }
514 }
515
516 if (kallsyms__parse(filename, &args, find_symbol_cb) <= 0) {
517 free(event);
518 return -ENOENT;
519 } 516 }
520 517
521 map = machine->vmlinux_maps[MAP__FUNCTION]; 518 map = machine->vmlinux_maps[MAP__FUNCTION];
519 kmap = map__kmap(map);
522 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename), 520 size = snprintf(event->mmap.filename, sizeof(event->mmap.filename),
523 "%s%s", mmap_name, symbol_name) + 1; 521 "%s%s", mmap_name, kmap->ref_reloc_sym->name) + 1;
524 size = PERF_ALIGN(size, sizeof(u64)); 522 size = PERF_ALIGN(size, sizeof(u64));
525 event->mmap.header.type = PERF_RECORD_MMAP; 523 event->mmap.header.type = PERF_RECORD_MMAP;
526 event->mmap.header.size = (sizeof(event->mmap) - 524 event->mmap.header.size = (sizeof(event->mmap) -
527 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size); 525 (sizeof(event->mmap.filename) - size) + machine->id_hdr_size);
528 event->mmap.pgoff = args.start; 526 event->mmap.pgoff = kmap->ref_reloc_sym->addr;
529 event->mmap.start = map->start; 527 event->mmap.start = map->start;
530 event->mmap.len = map->end - event->mmap.start; 528 event->mmap.len = map->end - event->mmap.start;
531 event->mmap.pid = machine->pid; 529 event->mmap.pid = machine->pid;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index faf6e219be21..851fa06f4a42 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -214,8 +214,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool,
214 struct machine *machine, bool mmap_data); 214 struct machine *machine, bool mmap_data);
215int perf_event__synthesize_kernel_mmap(struct perf_tool *tool, 215int perf_event__synthesize_kernel_mmap(struct perf_tool *tool,
216 perf_event__handler_t process, 216 perf_event__handler_t process,
217 struct machine *machine, 217 struct machine *machine);
218 const char *symbol_name);
219 218
220int perf_event__synthesize_modules(struct perf_tool *tool, 219int perf_event__synthesize_modules(struct perf_tool *tool,
221 perf_event__handler_t process, 220 perf_event__handler_t process,
@@ -279,4 +278,7 @@ size_t perf_event__fprintf_mmap2(union perf_event *event, FILE *fp);
279size_t perf_event__fprintf_task(union perf_event *event, FILE *fp); 278size_t perf_event__fprintf_task(union perf_event *event, FILE *fp);
280size_t perf_event__fprintf(union perf_event *event, FILE *fp); 279size_t perf_event__fprintf(union perf_event *event, FILE *fp);
281 280
281u64 kallsyms__get_function_start(const char *kallsyms_filename,
282 const char *symbol_name);
283
282#endif /* __PERF_RECORD_H */ 284#endif /* __PERF_RECORD_H */
diff --git a/tools/perf/util/include/asm/hash.h b/tools/perf/util/include/asm/hash.h
new file mode 100644
index 000000000000..d82b170bb216
--- /dev/null
+++ b/tools/perf/util/include/asm/hash.h
@@ -0,0 +1,6 @@
1#ifndef __ASM_GENERIC_HASH_H
2#define __ASM_GENERIC_HASH_H
3
4/* Stub */
5
6#endif /* __ASM_GENERIC_HASH_H */
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index ded74590b92f..c872991e0f65 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -496,19 +496,22 @@ static int symbol__in_kernel(void *arg, const char *name,
496 return 1; 496 return 1;
497} 497}
498 498
499static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
500 size_t bufsz)
501{
502 if (machine__is_default_guest(machine))
503 scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms);
504 else
505 scnprintf(buf, bufsz, "%s/proc/kallsyms", machine->root_dir);
506}
507
499/* Figure out the start address of kernel map from /proc/kallsyms */ 508/* Figure out the start address of kernel map from /proc/kallsyms */
500static u64 machine__get_kernel_start_addr(struct machine *machine) 509static u64 machine__get_kernel_start_addr(struct machine *machine)
501{ 510{
502 const char *filename; 511 char filename[PATH_MAX];
503 char path[PATH_MAX];
504 struct process_args args; 512 struct process_args args;
505 513
506 if (machine__is_default_guest(machine)) 514 machine__get_kallsyms_filename(machine, filename, PATH_MAX);
507 filename = (char *)symbol_conf.default_guest_kallsyms;
508 else {
509 sprintf(path, "%s/proc/kallsyms", machine->root_dir);
510 filename = path;
511 }
512 515
513 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 516 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
514 return 0; 517 return 0;
@@ -829,9 +832,25 @@ static int machine__create_modules(struct machine *machine)
829 return 0; 832 return 0;
830} 833}
831 834
835const char *ref_reloc_sym_names[] = {"_text", "_stext", NULL};
836
832int machine__create_kernel_maps(struct machine *machine) 837int machine__create_kernel_maps(struct machine *machine)
833{ 838{
834 struct dso *kernel = machine__get_kernel(machine); 839 struct dso *kernel = machine__get_kernel(machine);
840 char filename[PATH_MAX];
841 const char *name;
842 u64 addr = 0;
843 int i;
844
845 machine__get_kallsyms_filename(machine, filename, PATH_MAX);
846
847 for (i = 0; (name = ref_reloc_sym_names[i]) != NULL; i++) {
848 addr = kallsyms__get_function_start(filename, name);
849 if (addr)
850 break;
851 }
852 if (!addr)
853 return -1;
835 854
836 if (kernel == NULL || 855 if (kernel == NULL ||
837 __machine__create_kernel_maps(machine, kernel) < 0) 856 __machine__create_kernel_maps(machine, kernel) < 0)
@@ -850,6 +869,13 @@ int machine__create_kernel_maps(struct machine *machine)
850 * Now that we have all the maps created, just set the ->end of them: 869 * Now that we have all the maps created, just set the ->end of them:
851 */ 870 */
852 map_groups__fixup_end(&machine->kmaps); 871 map_groups__fixup_end(&machine->kmaps);
872
873 if (maps__set_kallsyms_ref_reloc_sym(machine->vmlinux_maps, name,
874 addr)) {
875 machine__destroy_kernel_maps(machine);
876 return -1;
877 }
878
853 return 0; 879 return 0;
854} 880}
855 881
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 477133015440..f77e91e483dc 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -18,6 +18,8 @@ union perf_event;
18#define HOST_KERNEL_ID (-1) 18#define HOST_KERNEL_ID (-1)
19#define DEFAULT_GUEST_KERNEL_ID (0) 19#define DEFAULT_GUEST_KERNEL_ID (0)
20 20
21extern const char *ref_reloc_sym_names[];
22
21struct machine { 23struct machine {
22 struct rb_node rb_node; 24 struct rb_node rb_node;
23 pid_t pid; 25 pid_t pid;
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 3b97513f0e77..39cd2d0faff6 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -39,6 +39,7 @@ void map__init(struct map *map, enum map_type type,
39 map->start = start; 39 map->start = start;
40 map->end = end; 40 map->end = end;
41 map->pgoff = pgoff; 41 map->pgoff = pgoff;
42 map->reloc = 0;
42 map->dso = dso; 43 map->dso = dso;
43 map->map_ip = map__map_ip; 44 map->map_ip = map__map_ip;
44 map->unmap_ip = map__unmap_ip; 45 map->unmap_ip = map__unmap_ip;
@@ -288,7 +289,7 @@ u64 map__rip_2objdump(struct map *map, u64 rip)
288 if (map->dso->rel) 289 if (map->dso->rel)
289 return rip - map->pgoff; 290 return rip - map->pgoff;
290 291
291 return map->unmap_ip(map, rip); 292 return map->unmap_ip(map, rip) - map->reloc;
292} 293}
293 294
294/** 295/**
@@ -311,7 +312,7 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
311 if (map->dso->rel) 312 if (map->dso->rel)
312 return map->unmap_ip(map, ip + map->pgoff); 313 return map->unmap_ip(map, ip + map->pgoff);
313 314
314 return ip; 315 return ip + map->reloc;
315} 316}
316 317
317void map_groups__init(struct map_groups *mg) 318void map_groups__init(struct map_groups *mg)
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 18068c6b71c1..257e513205ce 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -36,6 +36,7 @@ struct map {
36 bool erange_warned; 36 bool erange_warned;
37 u32 priv; 37 u32 priv;
38 u64 pgoff; 38 u64 pgoff;
39 u64 reloc;
39 u32 maj, min; /* only valid for MMAP2 record */ 40 u32 maj, min; /* only valid for MMAP2 record */
40 u64 ino; /* only valid for MMAP2 record */ 41 u64 ino; /* only valid for MMAP2 record */
41 u64 ino_generation;/* only valid for MMAP2 record */ 42 u64 ino_generation;/* only valid for MMAP2 record */
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 759456728703..3e9f336740fa 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -751,6 +751,8 @@ int dso__load_sym(struct dso *dso, struct map *map,
751 if (strcmp(elf_name, kmap->ref_reloc_sym->name)) 751 if (strcmp(elf_name, kmap->ref_reloc_sym->name))
752 continue; 752 continue;
753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; 753 kmap->ref_reloc_sym->unrelocated_addr = sym.st_value;
754 map->reloc = kmap->ref_reloc_sym->addr -
755 kmap->ref_reloc_sym->unrelocated_addr;
754 break; 756 break;
755 } 757 }
756 } 758 }
@@ -922,6 +924,7 @@ int dso__load_sym(struct dso *dso, struct map *map,
922 (u64)shdr.sh_offset); 924 (u64)shdr.sh_offset);
923 sym.st_value -= shdr.sh_addr - shdr.sh_offset; 925 sym.st_value -= shdr.sh_addr - shdr.sh_offset;
924 } 926 }
927new_symbol:
925 /* 928 /*
926 * We need to figure out if the object was created from C++ sources 929 * We need to figure out if the object was created from C++ sources
927 * DWARF DW_compile_unit has this, but we don't always have access 930 * DWARF DW_compile_unit has this, but we don't always have access
@@ -933,7 +936,6 @@ int dso__load_sym(struct dso *dso, struct map *map,
933 if (demangled != NULL) 936 if (demangled != NULL)
934 elf_name = demangled; 937 elf_name = demangled;
935 } 938 }
936new_symbol:
937 f = symbol__new(sym.st_value, sym.st_size, 939 f = symbol__new(sym.st_value, sym.st_size,
938 GELF_ST_BIND(sym.st_info), elf_name); 940 GELF_ST_BIND(sym.st_info), elf_name);
939 free(demangled); 941 free(demangled);
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 39ce9adbaaf0..a9d758a3b371 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -627,7 +627,7 @@ static int dso__split_kallsyms_for_kcore(struct dso *dso, struct map *map,
627 * kernel range is broken in several maps, named [kernel].N, as we don't have 627 * kernel range is broken in several maps, named [kernel].N, as we don't have
628 * the original ELF section names vmlinux have. 628 * the original ELF section names vmlinux have.
629 */ 629 */
630static int dso__split_kallsyms(struct dso *dso, struct map *map, 630static int dso__split_kallsyms(struct dso *dso, struct map *map, u64 delta,
631 symbol_filter_t filter) 631 symbol_filter_t filter)
632{ 632{
633 struct map_groups *kmaps = map__kmap(map)->kmaps; 633 struct map_groups *kmaps = map__kmap(map)->kmaps;
@@ -692,6 +692,12 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map,
692 char dso_name[PATH_MAX]; 692 char dso_name[PATH_MAX];
693 struct dso *ndso; 693 struct dso *ndso;
694 694
695 if (delta) {
696 /* Kernel was relocated at boot time */
697 pos->start -= delta;
698 pos->end -= delta;
699 }
700
695 if (count == 0) { 701 if (count == 0) {
696 curr_map = map; 702 curr_map = map;
697 goto filter_symbol; 703 goto filter_symbol;
@@ -721,6 +727,10 @@ static int dso__split_kallsyms(struct dso *dso, struct map *map,
721 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip; 727 curr_map->map_ip = curr_map->unmap_ip = identity__map_ip;
722 map_groups__insert(kmaps, curr_map); 728 map_groups__insert(kmaps, curr_map);
723 ++kernel_range; 729 ++kernel_range;
730 } else if (delta) {
731 /* Kernel was relocated at boot time */
732 pos->start -= delta;
733 pos->end -= delta;
724 } 734 }
725filter_symbol: 735filter_symbol:
726 if (filter && filter(curr_map, pos)) { 736 if (filter && filter(curr_map, pos)) {
@@ -976,6 +986,23 @@ static int validate_kcore_modules(const char *kallsyms_filename,
976 return 0; 986 return 0;
977} 987}
978 988
989static int validate_kcore_addresses(const char *kallsyms_filename,
990 struct map *map)
991{
992 struct kmap *kmap = map__kmap(map);
993
994 if (kmap->ref_reloc_sym && kmap->ref_reloc_sym->name) {
995 u64 start;
996
997 start = kallsyms__get_function_start(kallsyms_filename,
998 kmap->ref_reloc_sym->name);
999 if (start != kmap->ref_reloc_sym->addr)
1000 return -EINVAL;
1001 }
1002
1003 return validate_kcore_modules(kallsyms_filename, map);
1004}
1005
979struct kcore_mapfn_data { 1006struct kcore_mapfn_data {
980 struct dso *dso; 1007 struct dso *dso;
981 enum map_type type; 1008 enum map_type type;
@@ -1019,8 +1046,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
1019 kallsyms_filename)) 1046 kallsyms_filename))
1020 return -EINVAL; 1047 return -EINVAL;
1021 1048
1022 /* All modules must be present at their original addresses */ 1049 /* Modules and kernel must be present at their original addresses */
1023 if (validate_kcore_modules(kallsyms_filename, map)) 1050 if (validate_kcore_addresses(kallsyms_filename, map))
1024 return -EINVAL; 1051 return -EINVAL;
1025 1052
1026 md.dso = dso; 1053 md.dso = dso;
@@ -1113,15 +1140,41 @@ out_err:
1113 return -EINVAL; 1140 return -EINVAL;
1114} 1141}
1115 1142
1143/*
1144 * If the kernel is relocated at boot time, kallsyms won't match. Compute the
1145 * delta based on the relocation reference symbol.
1146 */
1147static int kallsyms__delta(struct map *map, const char *filename, u64 *delta)
1148{
1149 struct kmap *kmap = map__kmap(map);
1150 u64 addr;
1151
1152 if (!kmap->ref_reloc_sym || !kmap->ref_reloc_sym->name)
1153 return 0;
1154
1155 addr = kallsyms__get_function_start(filename,
1156 kmap->ref_reloc_sym->name);
1157 if (!addr)
1158 return -1;
1159
1160 *delta = addr - kmap->ref_reloc_sym->addr;
1161 return 0;
1162}
1163
1116int dso__load_kallsyms(struct dso *dso, const char *filename, 1164int dso__load_kallsyms(struct dso *dso, const char *filename,
1117 struct map *map, symbol_filter_t filter) 1165 struct map *map, symbol_filter_t filter)
1118{ 1166{
1167 u64 delta = 0;
1168
1119 if (symbol__restricted_filename(filename, "/proc/kallsyms")) 1169 if (symbol__restricted_filename(filename, "/proc/kallsyms"))
1120 return -1; 1170 return -1;
1121 1171
1122 if (dso__load_all_kallsyms(dso, filename, map) < 0) 1172 if (dso__load_all_kallsyms(dso, filename, map) < 0)
1123 return -1; 1173 return -1;
1124 1174
1175 if (kallsyms__delta(map, filename, &delta))
1176 return -1;
1177
1125 symbols__fixup_duplicate(&dso->symbols[map->type]); 1178 symbols__fixup_duplicate(&dso->symbols[map->type]);
1126 symbols__fixup_end(&dso->symbols[map->type]); 1179 symbols__fixup_end(&dso->symbols[map->type]);
1127 1180
@@ -1133,7 +1186,7 @@ int dso__load_kallsyms(struct dso *dso, const char *filename,
1133 if (!dso__load_kcore(dso, map, filename)) 1186 if (!dso__load_kcore(dso, map, filename))
1134 return dso__split_kallsyms_for_kcore(dso, map, filter); 1187 return dso__split_kallsyms_for_kcore(dso, map, filter);
1135 else 1188 else
1136 return dso__split_kallsyms(dso, map, filter); 1189 return dso__split_kallsyms(dso, map, delta, filter);
1137} 1190}
1138 1191
1139static int dso__load_perf_map(struct dso *dso, struct map *map, 1192static int dso__load_perf_map(struct dso *dso, struct map *map,
@@ -1424,7 +1477,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz)
1424 continue; 1477 continue;
1425 scnprintf(kallsyms_filename, sizeof(kallsyms_filename), 1478 scnprintf(kallsyms_filename, sizeof(kallsyms_filename),
1426 "%s/%s/kallsyms", dir, dent->d_name); 1479 "%s/%s/kallsyms", dir, dent->d_name);
1427 if (!validate_kcore_modules(kallsyms_filename, map)) { 1480 if (!validate_kcore_addresses(kallsyms_filename, map)) {
1428 strlcpy(dir, kallsyms_filename, dir_sz); 1481 strlcpy(dir, kallsyms_filename, dir_sz);
1429 ret = 0; 1482 ret = 0;
1430 break; 1483 break;
@@ -1479,7 +1532,7 @@ static char *dso__find_kallsyms(struct dso *dso, struct map *map)
1479 if (fd != -1) { 1532 if (fd != -1) {
1480 close(fd); 1533 close(fd);
1481 /* If module maps match go with /proc/kallsyms */ 1534 /* If module maps match go with /proc/kallsyms */
1482 if (!validate_kcore_modules("/proc/kallsyms", map)) 1535 if (!validate_kcore_addresses("/proc/kallsyms", map))
1483 goto proc_kallsyms; 1536 goto proc_kallsyms;
1484 } 1537 }
1485 1538