GNU Linux-libre 4.19.286-gnu1
[releases.git] / tools / perf / arch / x86 / util / machine.c
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