aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/kprobes.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/kprobes.c')
-rw-r--r--arch/powerpc/kernel/kprobes.c92
1 files changed, 44 insertions, 48 deletions
diff --git a/arch/powerpc/kernel/kprobes.c b/arch/powerpc/kernel/kprobes.c
index bebc3007a793..ca5d5a081e75 100644
--- a/arch/powerpc/kernel/kprobes.c
+++ b/arch/powerpc/kernel/kprobes.c
@@ -43,12 +43,6 @@ DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
43 43
44struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}}; 44struct kretprobe_blackpoint kretprobe_blacklist[] = {{NULL, NULL}};
45 45
46int is_current_kprobe_addr(unsigned long addr)
47{
48 struct kprobe *p = kprobe_running();
49 return (p && (unsigned long)p->addr == addr) ? 1 : 0;
50}
51
52bool arch_within_kprobe_blacklist(unsigned long addr) 46bool arch_within_kprobe_blacklist(unsigned long addr)
53{ 47{
54 return (addr >= (unsigned long)__kprobes_text_start && 48 return (addr >= (unsigned long)__kprobes_text_start &&
@@ -59,7 +53,7 @@ bool arch_within_kprobe_blacklist(unsigned long addr)
59 53
60kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset) 54kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset)
61{ 55{
62 kprobe_opcode_t *addr; 56 kprobe_opcode_t *addr = NULL;
63 57
64#ifdef PPC64_ELF_ABI_v2 58#ifdef PPC64_ELF_ABI_v2
65 /* PPC64 ABIv2 needs local entry point */ 59 /* PPC64 ABIv2 needs local entry point */
@@ -91,36 +85,29 @@ kprobe_opcode_t *kprobe_lookup_name(const char *name, unsigned int offset)
91 * Also handle <module:symbol> format. 85 * Also handle <module:symbol> format.
92 */ 86 */
93 char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN]; 87 char dot_name[MODULE_NAME_LEN + 1 + KSYM_NAME_LEN];
94 const char *modsym;
95 bool dot_appended = false; 88 bool dot_appended = false;
96 if ((modsym = strchr(name, ':')) != NULL) { 89 const char *c;
97 modsym++; 90 ssize_t ret = 0;
98 if (*modsym != '\0' && *modsym != '.') { 91 int len = 0;
99 /* Convert to <module:.symbol> */ 92
100 strncpy(dot_name, name, modsym - name); 93 if ((c = strnchr(name, MODULE_NAME_LEN, ':')) != NULL) {
101 dot_name[modsym - name] = '.'; 94 c++;
102 dot_name[modsym - name + 1] = '\0'; 95 len = c - name;
103 strncat(dot_name, modsym, 96 memcpy(dot_name, name, len);
104 sizeof(dot_name) - (modsym - name) - 2); 97 } else
105 dot_appended = true; 98 c = name;
106 } else { 99
107 dot_name[0] = '\0'; 100 if (*c != '\0' && *c != '.') {
108 strncat(dot_name, name, sizeof(dot_name) - 1); 101 dot_name[len++] = '.';
109 }
110 } else if (name[0] != '.') {
111 dot_name[0] = '.';
112 dot_name[1] = '\0';
113 strncat(dot_name, name, KSYM_NAME_LEN - 2);
114 dot_appended = true; 102 dot_appended = true;
115 } else {
116 dot_name[0] = '\0';
117 strncat(dot_name, name, KSYM_NAME_LEN - 1);
118 } 103 }
119 addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name); 104 ret = strscpy(dot_name + len, c, KSYM_NAME_LEN);
120 if (!addr && dot_appended) { 105 if (ret > 0)
121 /* Let's try the original non-dot symbol lookup */ 106 addr = (kprobe_opcode_t *)kallsyms_lookup_name(dot_name);
107
108 /* Fallback to the original non-dot symbol lookup */
109 if (!addr && dot_appended)
122 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); 110 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name);
123 }
124#else 111#else
125 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name); 112 addr = (kprobe_opcode_t *)kallsyms_lookup_name(name);
126#endif 113#endif
@@ -239,7 +226,7 @@ void arch_prepare_kretprobe(struct kretprobe_instance *ri, struct pt_regs *regs)
239} 226}
240NOKPROBE_SYMBOL(arch_prepare_kretprobe); 227NOKPROBE_SYMBOL(arch_prepare_kretprobe);
241 228
242int try_to_emulate(struct kprobe *p, struct pt_regs *regs) 229static int try_to_emulate(struct kprobe *p, struct pt_regs *regs)
243{ 230{
244 int ret; 231 int ret;
245 unsigned int insn = *p->ainsn.insn; 232 unsigned int insn = *p->ainsn.insn;
@@ -261,9 +248,20 @@ int try_to_emulate(struct kprobe *p, struct pt_regs *regs)
261 */ 248 */
262 printk("Can't step on instruction %x\n", insn); 249 printk("Can't step on instruction %x\n", insn);
263 BUG(); 250 BUG();
264 } else if (ret == 0) 251 } else {
265 /* This instruction can't be boosted */ 252 /*
266 p->ainsn.boostable = -1; 253 * If we haven't previously emulated this instruction, then it
254 * can't be boosted. Note it down so we don't try to do so again.
255 *
256 * If, however, we had emulated this instruction in the past,
257 * then this is just an error with the current run (for
258 * instance, exceptions due to a load/store). We return 0 so
259 * that this is now single-stepped, but continue to try
260 * emulating it in subsequent probe hits.
261 */
262 if (unlikely(p->ainsn.boostable != 1))
263 p->ainsn.boostable = -1;
264 }
267 265
268 return ret; 266 return ret;
269} 267}
@@ -639,24 +637,22 @@ NOKPROBE_SYMBOL(setjmp_pre_handler);
639 637
640void __used jprobe_return(void) 638void __used jprobe_return(void)
641{ 639{
642 asm volatile("trap" ::: "memory"); 640 asm volatile("jprobe_return_trap:\n"
641 "trap\n"
642 ::: "memory");
643} 643}
644NOKPROBE_SYMBOL(jprobe_return); 644NOKPROBE_SYMBOL(jprobe_return);
645 645
646static void __used jprobe_return_end(void)
647{
648}
649NOKPROBE_SYMBOL(jprobe_return_end);
650
651int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs) 646int longjmp_break_handler(struct kprobe *p, struct pt_regs *regs)
652{ 647{
653 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 648 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
654 649
655 /* 650 if (regs->nip != ppc_kallsyms_lookup_name("jprobe_return_trap")) {
656 * FIXME - we should ideally be validating that we got here 'cos 651 pr_debug("longjmp_break_handler NIP (0x%lx) does not match jprobe_return_trap (0x%lx)\n",
657 * of the "trap" in jprobe_return() above, before restoring the 652 regs->nip, ppc_kallsyms_lookup_name("jprobe_return_trap"));
658 * saved regs... 653 return 0;
659 */ 654 }
655
660 memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs)); 656 memcpy(regs, &kcb->jprobe_saved_regs, sizeof(struct pt_regs));
661 /* It's OK to start function graph tracing again */ 657 /* It's OK to start function graph tracing again */
662 unpause_graph_tracing(); 658 unpause_graph_tracing();