aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNaveen N. Rao <naveen.n.rao@linux.vnet.ibm.com>2014-12-15 09:50:31 -0500
committerMichael Ellerman <mpe@ellerman.id.au>2015-01-22 22:02:51 -0500
commitbf794bf52a80c6278a028f0af2ca32d7c3508c9b (patch)
tree99156d7b3fa258a370e097cfe0a2ae04cd67616d
parent10ea834364c8670b3bf9bbbf6b9d27b4d2ebc9de (diff)
powerpc/kprobes: Fix kallsyms lookup across powerpc ABIv1 and ABIv2
Currently, all non-dot symbols are being treated as function descriptors in ABIv1. This is incorrect and is resulting in perf probe not working: # perf probe do_fork Added new event: Failed to write event: Invalid argument Error: Failed to add events. # dmesg | tail -1 [192268.073063] Could not insert probe at _text+768432: -22 perf probe bases all kernel probes on _text and writes, for example, "p:probe/do_fork _text+768432" to /sys/kernel/debug/tracing/kprobe_events. In-kernel, _text is being considered to be a function descriptor and is resulting in the above error. Fix this by changing how we lookup symbol addresses on ppc64. We first check for the dot variant of a symbol and look at the non-dot variant only if that fails. In this manner, we avoid having to look at the function descriptor. While at it, also separate out how this works on ABIv2 where we don't have dot symbols, but need to use the local entry point. Signed-off-by: Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
-rw-r--r--arch/powerpc/include/asm/kprobes.h63
1 files changed, 44 insertions, 19 deletions
diff --git a/arch/powerpc/include/asm/kprobes.h b/arch/powerpc/include/asm/kprobes.h
index af15d4d8d604..039b583db029 100644
--- a/arch/powerpc/include/asm/kprobes.h
+++ b/arch/powerpc/include/asm/kprobes.h
@@ -41,34 +41,59 @@ typedef ppc_opcode_t kprobe_opcode_t;
41#define MAX_INSN_SIZE 1 41#define MAX_INSN_SIZE 1
42 42
43#ifdef CONFIG_PPC64 43#ifdef CONFIG_PPC64
44#if defined(_CALL_ELF) && _CALL_ELF == 2
45/* PPC64 ABIv2 needs local entry point */
46#define kprobe_lookup_name(name, addr) \
47{ \
48 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \
49 if (addr) \
50 addr = (kprobe_opcode_t *)ppc_function_entry(addr); \
51}
52#else
44/* 53/*
45 * 64bit powerpc uses function descriptors. 54 * 64bit powerpc ABIv1 uses function descriptors:
46 * Handle cases where: 55 * - Check for the dot variant of the symbol first.
47 * - User passes a <.symbol> or <module:.symbol> 56 * - If that fails, try looking up the symbol provided.
48 * - User passes a <symbol> or <module:symbol> 57 *
49 * - User passes a non-existent symbol, kallsyms_lookup_name 58 * This ensures we always get to the actual symbol and not the descriptor.
50 * returns 0. Don't deref the NULL pointer in that case 59 * Also handle <module:symbol> format.
51 */ 60 */
52#define kprobe_lookup_name(name, addr) \ 61#define kprobe_lookup_name(name, addr) \
53{ \ 62{ \
54 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \ 63 char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN]; \
55 if (addr) { \ 64 char *modsym; \
56 char *colon; \ 65 bool dot_appended = false; \
57 if ((colon = strchr(name, ':')) != NULL) { \ 66 if ((modsym = strchr(name, ':')) != NULL) { \
58 colon++; \ 67 modsym++; \
59 if (*colon != '\0' && *colon != '.') \ 68 if (*modsym != '\0' && *modsym != '.') { \
60 addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ 69 /* Convert to <module:.symbol> */ \
61 } else if (name[0] != '.') \ 70 strncpy(dot_name, name, modsym - name); \
62 addr = (kprobe_opcode_t *)ppc_function_entry(addr); \ 71 dot_name[modsym - name] = '.'; \
63 } else { \ 72 dot_name[modsym - name + 1] = '\0'; \
64 char dot_name[KSYM_NAME_LEN]; \ 73 strncat(dot_name, modsym, \
74 sizeof(dot_name) - (modsym - name) - 2);\
75 dot_appended = true; \
76 } else { \
77 dot_name[0] = '\0'; \
78 strncat(dot_name, name, sizeof(dot_name) - 1); \
79 } \
80 } else if (name[0] != '.') { \
65 dot_name[0] = '.'; \ 81 dot_name[0] = '.'; \
66 dot_name[1] = '\0'; \ 82 dot_name[1] = '\0'; \
67 strncat(dot_name, name, KSYM_NAME_LEN - 2); \ 83 strncat(dot_name, name, KSYM_NAME_LEN - 2); \
68 addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \ 84 dot_appended = true; \
85 } else { \
86 dot_name[0] = '\0'; \
87 strncat(dot_name, name, KSYM_NAME_LEN - 1); \
88 } \
89 addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); \
90 if (!addr && dot_appended) { \
91 /* Let's try the original non-dot symbol lookup */ \
92 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); \
69 } \ 93 } \
70} 94}
71#endif 95#endif /* defined(_CALL_ELF) && _CALL_ELF == 2 */
96#endif /* CONFIG_PPC64 */
72 97
73#define flush_insn_slot(p) do { } while (0) 98#define flush_insn_slot(p) do { } while (0)
74#define kretprobe_blacklist_size 0 99#define kretprobe_blacklist_size 0