Commit | Line | Data |
---|---|---|
a6576540 MD |
1 | /* SPDX-License-Identifier: (GPL-2.0-only OR LGPL-2.1-only) |
2 | * | |
3 | * wrapper/kallsyms.c | |
4 | * | |
5 | * Wrapper around kallsyms. Using kprobes to get its address when available. | |
6 | * | |
7 | * Can we mainline LTTng already so we don't have to waste our time doing this | |
8 | * kind of hack ? | |
9 | * | |
10 | * Copyright (C) 2020 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
11 | */ | |
12 | ||
13 | #include <linux/kprobes.h> | |
14 | #include <linux/module.h> | |
15 | #include <wrapper/kallsyms.h> | |
16 | ||
5f4c791e | 17 | #if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,7,0)) |
a6576540 MD |
18 | |
19 | #ifndef CONFIG_KPROBES | |
20 | # error "LTTng-modules requires CONFIG_KPROBES on kernels >= 5.7.0" | |
21 | #endif | |
22 | ||
23 | static | |
24 | unsigned long (*kallsyms_lookup_name_sym)(const char *name); | |
25 | ||
26 | static | |
27 | int dummy_kprobe_handler(struct kprobe *p, struct pt_regs *regs) | |
28 | { | |
29 | return 0; | |
30 | } | |
31 | ||
b4a626cb | 32 | #ifdef LTTNG_CONFIG_PPC64_ELF_ABI_V2 |
a6576540 | 33 | static |
b4a626cb | 34 | void kallsyms_pre_arch_adjust(struct kprobe *probe) |
a6576540 | 35 | { |
67c5ffca HZ |
36 | /* |
37 | * With powerpc64 ABIv2, we need the global entry point of | |
38 | * kallsyms_lookup_name to call it later, while kprobe_register would | |
39 | * automatically adjust the global entry point to the local entry point, | |
40 | * when a kprobe was registered at a function entry. So we add 4 bytes | |
41 | * which is the length of one instruction to kallsyms_lookup_name to | |
42 | * avoid the adjustment. | |
43 | */ | |
b4a626cb MD |
44 | probe->offset = 4; |
45 | } | |
46 | #else | |
47 | static | |
48 | void kallsyms_pre_arch_adjust(struct kprobe *probe) | |
49 | { | |
50 | } | |
67c5ffca | 51 | #endif |
b4a626cb | 52 | |
47af6022 | 53 | #ifdef LTTNG_CONFIG_PPC64_ELF_ABI_V2 |
b4a626cb MD |
54 | static |
55 | unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe) | |
56 | { | |
67c5ffca | 57 | /* Substract 4 bytes to get what we originally want */ |
b4a626cb MD |
58 | return (unsigned long)(((char *)probe->addr) - 4); |
59 | } | |
60 | ||
a1f1ecf4 | 61 | #elif defined(LTTNG_CONFIG_PPC64_ELF_ABI_V1) |
b4a626cb MD |
62 | # if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,18,0)) |
63 | # include <asm/elf.h> | |
64 | # define LTTNG_FUNC_DESC_TYPE struct func_desc | |
65 | # define LTTNG_FUNC_DESC_ADDR_NAME addr | |
66 | # else | |
67 | # include <asm/types.h> | |
68 | # define LTTNG_FUNC_DESC_TYPE func_descr_t | |
69 | # define LTTNG_FUNC_DESC_ADDR_NAME entry | |
70 | ||
71 | static | |
72 | LTTNG_FUNC_DESC_TYPE kallsyms_lookup_name_func_desc; | |
73 | # endif | |
74 | ||
75 | static | |
76 | unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe) | |
77 | { | |
a1f1ecf4 MJ |
78 | /* |
79 | * Build a function descriptor from the address of | |
80 | * 'kallsyms_lookup_name' returned by kprobe and the toc of | |
81 | * 'sprint_symbol' which is in the same compile unit and exported. I | |
82 | * hate this on so many levels but it works. | |
83 | */ | |
84 | kallsyms_lookup_name_func_desc.LTTNG_FUNC_DESC_ADDR_NAME = (unsigned long) probe.addr; | |
85 | kallsyms_lookup_name_func_desc.toc = ((LTTNG_FUNC_DESC_TYPE *) &sprint_symbol)->toc; | |
b4a626cb MD |
86 | return (unsigned long) &kallsyms_lookup_name_func_desc; |
87 | } | |
88 | #elif defined(CONFIG_ARM) && defined(CONFIG_THUMB2_KERNEL) | |
89 | static | |
90 | unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe) | |
91 | { | |
92 | unsigned long addr = (unsigned long)probe->addr; | |
93 | ||
a6576540 MD |
94 | if (addr) |
95 | addr |= 1; /* set bit 0 in address for thumb mode */ | |
b4a626cb MD |
96 | return addr; |
97 | } | |
98 | #else | |
99 | static | |
100 | unsigned long kallsyms_get_arch_call_addr(const struct kprobe *probe) | |
101 | { | |
102 | return (unsigned long)probe->addr; | |
103 | } | |
a6576540 | 104 | #endif |
b4a626cb MD |
105 | |
106 | static | |
107 | unsigned long do_get_kallsyms(void) | |
108 | { | |
109 | struct kprobe probe; | |
110 | int ret; | |
111 | unsigned long addr; | |
112 | ||
113 | memset(&probe, 0, sizeof(probe)); | |
114 | probe.pre_handler = dummy_kprobe_handler; | |
115 | probe.symbol_name = "kallsyms_lookup_name"; | |
116 | kallsyms_pre_arch_adjust(&probe); | |
117 | ret = register_kprobe(&probe); | |
118 | if (ret) | |
119 | return 0; | |
120 | addr = kallsyms_get_arch_call_addr(&probe); | |
a6576540 MD |
121 | unregister_kprobe(&probe); |
122 | return addr; | |
123 | } | |
124 | ||
125 | unsigned long wrapper_kallsyms_lookup_name(const char *name) | |
126 | { | |
127 | if (!kallsyms_lookup_name_sym) { | |
128 | kallsyms_lookup_name_sym = (void *)do_get_kallsyms(); | |
129 | } | |
92e2c5fe MD |
130 | if (kallsyms_lookup_name_sym) { |
131 | struct irq_ibt_state irq_ibt_state; | |
132 | unsigned long ret; | |
133 | ||
134 | irq_ibt_state = wrapper_irq_ibt_save(); | |
135 | ret = kallsyms_lookup_name_sym(name); | |
136 | wrapper_irq_ibt_restore(irq_ibt_state); | |
137 | return ret; | |
138 | } else { | |
5a15f70c | 139 | printk_once(KERN_WARNING "LTTng: requires kallsyms_lookup_name\n"); |
a6576540 MD |
140 | return 0; |
141 | } | |
142 | } | |
143 | EXPORT_SYMBOL_GPL(wrapper_kallsyms_lookup_name); | |
144 | ||
145 | #endif | |
612ddfa1 | 146 | |
95b4bc7d | 147 | #if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,4,0) && defined(CONFIG_ANDROID)) |
612ddfa1 L |
148 | MODULE_IMPORT_NS(VFS_internal_I_am_really_a_filesystem_and_am_NOT_a_driver); |
149 | #endif |