Skip to content

Commit 1c5aae7

Browse files
ahunter6acmel
authored andcommitted
perf machine: Create maps for x86 PTI entry trampolines
Create maps for x86 PTI entry trampolines, based on symbols found in kallsyms. It is also necessary to keep track of whether the trampolines have been mapped particularly when the kernel dso is kcore. Signed-off-by: Adrian Hunter <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Dave Hansen <[email protected]> Cc: H. Peter Anvin <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Joerg Roedel <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Link: http://lkml.kernel.org/r/[email protected] [ Fix extra_kernel_map_info.cnt designed struct initializer on gcc 4.4.7 (centos:6, etc) ] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 5759a68 commit 1c5aae7

File tree

5 files changed

+187
-19
lines changed

5 files changed

+187
-19
lines changed

tools/perf/arch/x86/util/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ libperf-y += pmu.o
44
libperf-y += kvm-stat.o
55
libperf-y += perf_regs.o
66
libperf-y += group.o
7+
libperf-y += machine.o
78

89
libperf-$(CONFIG_DWARF) += dwarf-regs.o
910
libperf-$(CONFIG_BPF_PROLOGUE) += dwarf-regs.o

tools/perf/arch/x86/util/machine.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
#include <linux/types.h>
3+
#include <linux/string.h>
4+
#include <stdlib.h>
5+
6+
#include "../../util/machine.h"
7+
#include "../../util/map.h"
8+
#include "../../util/symbol.h"
9+
#include "../../util/sane_ctype.h"
10+
11+
#include <symbol/kallsyms.h>
12+
13+
#if defined(__x86_64__)
14+
15+
struct extra_kernel_map_info {
16+
int cnt;
17+
int max_cnt;
18+
struct extra_kernel_map *maps;
19+
bool get_entry_trampolines;
20+
u64 entry_trampoline;
21+
};
22+
23+
static int add_extra_kernel_map(struct extra_kernel_map_info *mi, u64 start,
24+
u64 end, u64 pgoff, const char *name)
25+
{
26+
if (mi->cnt >= mi->max_cnt) {
27+
void *buf;
28+
size_t sz;
29+
30+
mi->max_cnt = mi->max_cnt ? mi->max_cnt * 2 : 32;
31+
sz = sizeof(struct extra_kernel_map) * mi->max_cnt;
32+
buf = realloc(mi->maps, sz);
33+
if (!buf)
34+
return -1;
35+
mi->maps = buf;
36+
}
37+
38+
mi->maps[mi->cnt].start = start;
39+
mi->maps[mi->cnt].end = end;
40+
mi->maps[mi->cnt].pgoff = pgoff;
41+
strlcpy(mi->maps[mi->cnt].name, name, KMAP_NAME_LEN);
42+
43+
mi->cnt += 1;
44+
45+
return 0;
46+
}
47+
48+
static int find_extra_kernel_maps(void *arg, const char *name, char type,
49+
u64 start)
50+
{
51+
struct extra_kernel_map_info *mi = arg;
52+
53+
if (!mi->entry_trampoline && kallsyms2elf_binding(type) == STB_GLOBAL &&
54+
!strcmp(name, "_entry_trampoline")) {
55+
mi->entry_trampoline = start;
56+
return 0;
57+
}
58+
59+
if (is_entry_trampoline(name)) {
60+
u64 end = start + page_size;
61+
62+
return add_extra_kernel_map(mi, start, end, 0, name);
63+
}
64+
65+
return 0;
66+
}
67+
68+
int machine__create_extra_kernel_maps(struct machine *machine,
69+
struct dso *kernel)
70+
{
71+
struct extra_kernel_map_info mi = { .cnt = 0, };
72+
char filename[PATH_MAX];
73+
int ret;
74+
int i;
75+
76+
machine__get_kallsyms_filename(machine, filename, PATH_MAX);
77+
78+
if (symbol__restricted_filename(filename, "/proc/kallsyms"))
79+
return 0;
80+
81+
ret = kallsyms__parse(filename, &mi, find_extra_kernel_maps);
82+
if (ret)
83+
goto out_free;
84+
85+
if (!mi.entry_trampoline)
86+
goto out_free;
87+
88+
for (i = 0; i < mi.cnt; i++) {
89+
struct extra_kernel_map *xm = &mi.maps[i];
90+
91+
xm->pgoff = mi.entry_trampoline;
92+
ret = machine__create_extra_kernel_map(machine, kernel, xm);
93+
if (ret)
94+
goto out_free;
95+
}
96+
97+
machine->trampolines_mapped = mi.cnt;
98+
out_free:
99+
free(mi.maps);
100+
return ret;
101+
}
102+
103+
#endif

tools/perf/util/machine.c

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -807,8 +807,8 @@ struct process_args {
807807
u64 start;
808808
};
809809

810-
static void machine__get_kallsyms_filename(struct machine *machine, char *buf,
811-
size_t bufsz)
810+
void machine__get_kallsyms_filename(struct machine *machine, char *buf,
811+
size_t bufsz)
812812
{
813813
if (machine__is_default_guest(machine))
814814
scnprintf(buf, bufsz, "%s", symbol_conf.default_guest_kallsyms);
@@ -851,17 +851,9 @@ static int machine__get_running_kernel_start(struct machine *machine,
851851
return 0;
852852
}
853853

854-
/* Kernel-space maps for symbols that are outside the main kernel map and module maps */
855-
struct extra_kernel_map {
856-
u64 start;
857-
u64 end;
858-
u64 pgoff;
859-
char name[KMAP_NAME_LEN];
860-
};
861-
862-
static int machine__create_extra_kernel_map(struct machine *machine,
863-
struct dso *kernel,
864-
struct extra_kernel_map *xm)
854+
int machine__create_extra_kernel_map(struct machine *machine,
855+
struct dso *kernel,
856+
struct extra_kernel_map *xm)
865857
{
866858
struct kmap *kmap;
867859
struct map *map;
@@ -923,9 +915,33 @@ static u64 find_entry_trampoline(struct dso *dso)
923915
int machine__map_x86_64_entry_trampolines(struct machine *machine,
924916
struct dso *kernel)
925917
{
926-
u64 pgoff = find_entry_trampoline(kernel);
918+
struct map_groups *kmaps = &machine->kmaps;
919+
struct maps *maps = &kmaps->maps;
927920
int nr_cpus_avail, cpu;
921+
bool found = false;
922+
struct map *map;
923+
u64 pgoff;
924+
925+
/*
926+
* In the vmlinux case, pgoff is a virtual address which must now be
927+
* mapped to a vmlinux offset.
928+
*/
929+
for (map = maps__first(maps); map; map = map__next(map)) {
930+
struct kmap *kmap = __map__kmap(map);
931+
struct map *dest_map;
932+
933+
if (!kmap || !is_entry_trampoline(kmap->name))
934+
continue;
935+
936+
dest_map = map_groups__find(kmaps, map->pgoff);
937+
if (dest_map != map)
938+
map->pgoff = dest_map->map_ip(dest_map, map->pgoff);
939+
found = true;
940+
}
941+
if (found || machine->trampolines_mapped)
942+
return 0;
928943

944+
pgoff = find_entry_trampoline(kernel);
929945
if (!pgoff)
930946
return 0;
931947

@@ -948,6 +964,14 @@ int machine__map_x86_64_entry_trampolines(struct machine *machine,
948964
return -1;
949965
}
950966

967+
machine->trampolines_mapped = nr_cpus_avail;
968+
969+
return 0;
970+
}
971+
972+
int __weak machine__create_extra_kernel_maps(struct machine *machine __maybe_unused,
973+
struct dso *kernel __maybe_unused)
974+
{
951975
return 0;
952976
}
953977

@@ -1306,9 +1330,8 @@ int machine__create_kernel_maps(struct machine *machine)
13061330
return -1;
13071331

13081332
ret = __machine__create_kernel_maps(machine, kernel);
1309-
dso__put(kernel);
13101333
if (ret < 0)
1311-
return -1;
1334+
goto out_put;
13121335

13131336
if (symbol_conf.use_modules && machine__create_modules(machine) < 0) {
13141337
if (machine__is_host(machine))
@@ -1323,7 +1346,8 @@ int machine__create_kernel_maps(struct machine *machine)
13231346
if (name &&
13241347
map__set_kallsyms_ref_reloc_sym(machine->vmlinux_map, name, addr)) {
13251348
machine__destroy_kernel_maps(machine);
1326-
return -1;
1349+
ret = -1;
1350+
goto out_put;
13271351
}
13281352

13291353
/* we have a real start address now, so re-order the kmaps */
@@ -1339,12 +1363,16 @@ int machine__create_kernel_maps(struct machine *machine)
13391363
map__put(map);
13401364
}
13411365

1366+
if (machine__create_extra_kernel_maps(machine, kernel))
1367+
pr_debug("Problems creating extra kernel maps, continuing anyway...\n");
1368+
13421369
/* update end address of the kernel map using adjacent module address */
13431370
map = map__next(machine__kernel_map(machine));
13441371
if (map)
13451372
machine__set_kernel_mmap(machine, addr, map->start);
1346-
1347-
return 0;
1373+
out_put:
1374+
dso__put(kernel);
1375+
return ret;
13481376
}
13491377

13501378
static bool machine__uses_kcore(struct machine *machine)

tools/perf/util/machine.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct machine {
5656
void *priv;
5757
u64 db_id;
5858
};
59+
bool trampolines_mapped;
5960
};
6061

6162
static inline struct threads *machine__threads(struct machine *machine, pid_t tid)
@@ -268,6 +269,24 @@ int machine__set_current_tid(struct machine *machine, int cpu, pid_t pid,
268269
*/
269270
char *machine__resolve_kernel_addr(void *vmachine, unsigned long long *addrp, char **modp);
270271

272+
void machine__get_kallsyms_filename(struct machine *machine, char *buf,
273+
size_t bufsz);
274+
275+
int machine__create_extra_kernel_maps(struct machine *machine,
276+
struct dso *kernel);
277+
278+
/* Kernel-space maps for symbols that are outside the main kernel map and module maps */
279+
struct extra_kernel_map {
280+
u64 start;
281+
u64 end;
282+
u64 pgoff;
283+
char name[KMAP_NAME_LEN];
284+
};
285+
286+
int machine__create_extra_kernel_map(struct machine *machine,
287+
struct dso *kernel,
288+
struct extra_kernel_map *xm);
289+
271290
int machine__map_x86_64_entry_trampolines(struct machine *machine,
272291
struct dso *kernel);
273292

tools/perf/util/symbol.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,6 +1158,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
11581158
struct map_groups *kmaps = map__kmaps(map);
11591159
struct kcore_mapfn_data md;
11601160
struct map *old_map, *new_map, *replacement_map = NULL;
1161+
struct machine *machine;
11611162
bool is_64_bit;
11621163
int err, fd;
11631164
char kcore_filename[PATH_MAX];
@@ -1166,6 +1167,8 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
11661167
if (!kmaps)
11671168
return -EINVAL;
11681169

1170+
machine = kmaps->machine;
1171+
11691172
/* This function requires that the map is the kernel map */
11701173
if (!__map__is_kernel(map))
11711174
return -EINVAL;
@@ -1209,6 +1212,7 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
12091212
map_groups__remove(kmaps, old_map);
12101213
old_map = next;
12111214
}
1215+
machine->trampolines_mapped = false;
12121216

12131217
/* Find the kernel map using the '_stext' symbol */
12141218
if (!kallsyms__get_function_start(kallsyms_filename, "_stext", &stext)) {
@@ -1245,6 +1249,19 @@ static int dso__load_kcore(struct dso *dso, struct map *map,
12451249
map__put(new_map);
12461250
}
12471251

1252+
if (machine__is(machine, "x86_64")) {
1253+
u64 addr;
1254+
1255+
/*
1256+
* If one of the corresponding symbols is there, assume the
1257+
* entry trampoline maps are too.
1258+
*/
1259+
if (!kallsyms__get_function_start(kallsyms_filename,
1260+
ENTRY_TRAMPOLINE_NAME,
1261+
&addr))
1262+
machine->trampolines_mapped = true;
1263+
}
1264+
12481265
/*
12491266
* Set the data type and long name so that kcore can be read via
12501267
* dso__data_read_addr().

0 commit comments

Comments
 (0)