93017adc87a6ab40cec47989df3659e56a92b2f1
[lttng-modules.git] / src / wrapper / kallsyms.c
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
17 #if (LTTNG_LINUX_VERSION_CODE >= LTTNG_KERNEL_VERSION(5,7,0))
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
32 static
33 unsigned long do_get_kallsyms(void)
34 {
35 struct kprobe probe;
36 int ret;
37 unsigned long addr;
38
39 memset(&probe, 0, sizeof(probe));
40 probe.pre_handler = dummy_kprobe_handler;
41 probe.symbol_name = "kallsyms_lookup_name";
42 #ifdef PPC64_ELF_ABI_v2
43 /*
44 * With powerpc64 ABIv2, we need the global entry point of
45 * kallsyms_lookup_name to call it later, while kprobe_register would
46 * automatically adjust the global entry point to the local entry point,
47 * when a kprobe was registered at a function entry. So we add 4 bytes
48 * which is the length of one instruction to kallsyms_lookup_name to
49 * avoid the adjustment.
50 */
51 probe.offset = 4;
52 #endif
53 ret = register_kprobe(&probe);
54 if (ret)
55 return 0;
56 #ifdef PPC64_ELF_ABI_v2
57 /* Substract 4 bytes to get what we originally want */
58 addr = (unsigned long)(((char *)probe.addr) - 4);
59 #else
60 addr = (unsigned long)probe.addr;
61 #endif
62 #ifdef CONFIG_ARM
63 #ifdef CONFIG_THUMB2_KERNEL
64 if (addr)
65 addr |= 1; /* set bit 0 in address for thumb mode */
66 #endif
67 #endif
68 unregister_kprobe(&probe);
69 return addr;
70 }
71
72 unsigned long wrapper_kallsyms_lookup_name(const char *name)
73 {
74 if (!kallsyms_lookup_name_sym) {
75 kallsyms_lookup_name_sym = (void *)do_get_kallsyms();
76 }
77 if (kallsyms_lookup_name_sym)
78 return kallsyms_lookup_name_sym(name);
79 else {
80 printk_once(KERN_WARNING "LTTng: requires kallsyms_lookup_name\n");
81 return 0;
82 }
83 }
84 EXPORT_SYMBOL_GPL(wrapper_kallsyms_lookup_name);
85
86 #endif
This page took 0.03068 seconds and 3 git commands to generate.