| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  * Kernel probes (kprobes) for SuperH | 
 |  * | 
 |  * Copyright (C) 2007 Chris Smith <chris.smith@st.com> | 
 |  * Copyright (C) 2006 Lineo Solutions, Inc. | 
 |  */ | 
 | #include <linux/kprobes.h> | 
 | #include <linux/extable.h> | 
 | #include <linux/ptrace.h> | 
 | #include <linux/preempt.h> | 
 | #include <linux/kdebug.h> | 
 | #include <linux/slab.h> | 
 | #include <asm/cacheflush.h> | 
 | #include <linux/uaccess.h> | 
 |  | 
 | DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL; | 
 | DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); | 
 |  | 
 | static DEFINE_PER_CPU(struct kprobe, saved_current_opcode); | 
 | static DEFINE_PER_CPU(struct kprobe, saved_next_opcode); | 
 | static DEFINE_PER_CPU(struct kprobe, saved_next_opcode2); | 
 |  | 
 | #define OPCODE_JMP(x)	(((x) & 0xF0FF) == 0x402b) | 
 | #define OPCODE_JSR(x)	(((x) & 0xF0FF) == 0x400b) | 
 | #define OPCODE_BRA(x)	(((x) & 0xF000) == 0xa000) | 
 | #define OPCODE_BRAF(x)	(((x) & 0xF0FF) == 0x0023) | 
 | #define OPCODE_BSR(x)	(((x) & 0xF000) == 0xb000) | 
 | #define OPCODE_BSRF(x)	(((x) & 0xF0FF) == 0x0003) | 
 |  | 
 | #define OPCODE_BF_S(x)	(((x) & 0xFF00) == 0x8f00) | 
 | #define OPCODE_BT_S(x)	(((x) & 0xFF00) == 0x8d00) | 
 |  | 
 | #define OPCODE_BF(x)	(((x) & 0xFF00) == 0x8b00) | 
 | #define OPCODE_BT(x)	(((x) & 0xFF00) == 0x8900) | 
 |  | 
 | #define OPCODE_RTS(x)	(((x) & 0x000F) == 0x000b) | 
 | #define OPCODE_RTE(x)	(((x) & 0xFFFF) == 0x002b) | 
 |  | 
 | int __kprobes arch_prepare_kprobe(struct kprobe *p) | 
 | { | 
 | 	kprobe_opcode_t opcode = *(kprobe_opcode_t *) (p->addr); | 
 |  | 
 | 	if (OPCODE_RTE(opcode)) | 
 | 		return -EFAULT;	/* Bad breakpoint */ | 
 |  | 
 | 	memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); | 
 | 	p->opcode = opcode; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 
 | { | 
 | 	*p->addr = BREAKPOINT_INSTRUCTION; | 
 | 	flush_icache_range((unsigned long)p->addr, | 
 | 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t)); | 
 | } | 
 |  | 
 | void __kprobes arch_disarm_kprobe(struct kprobe *p) | 
 | { | 
 | 	*p->addr = p->opcode; | 
 | 	flush_icache_range((unsigned long)p->addr, | 
 | 			   (unsigned long)p->addr + sizeof(kprobe_opcode_t)); | 
 | } | 
 |  | 
 | int __kprobes arch_trampoline_kprobe(struct kprobe *p) | 
 | { | 
 | 	if (*p->addr == BREAKPOINT_INSTRUCTION) | 
 | 		return 1; | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /** | 
 |  * If an illegal slot instruction exception occurs for an address | 
 |  * containing a kprobe, remove the probe. | 
 |  * | 
 |  * Returns 0 if the exception was handled successfully, 1 otherwise. | 
 |  */ | 
 | int __kprobes kprobe_handle_illslot(unsigned long pc) | 
 | { | 
 | 	struct kprobe *p = get_kprobe((kprobe_opcode_t *) pc + 1); | 
 |  | 
 | 	if (p != NULL) { | 
 | 		printk("Warning: removing kprobe from delay slot: 0x%.8x\n", | 
 | 		       (unsigned int)pc + 2); | 
 | 		unregister_kprobe(p); | 
 | 		return 0; | 
 | 	} | 
 |  | 
 | 	return 1; | 
 | } | 
 |  | 
 | void __kprobes arch_remove_kprobe(struct kprobe *p) | 
 | { | 
 | 	struct kprobe *saved = this_cpu_ptr(&saved_next_opcode); | 
 |  | 
 | 	if (saved->addr) { | 
 | 		arch_disarm_kprobe(p); | 
 | 		arch_disarm_kprobe(saved); | 
 |  | 
 | 		saved->addr = NULL; | 
 | 		saved->opcode = 0; | 
 |  | 
 | 		saved = this_cpu_ptr(&saved_next_opcode2); | 
 | 		if (saved->addr) { | 
 | 			arch_disarm_kprobe(saved); | 
 |  | 
 | 			saved->addr = NULL; | 
 | 			saved->opcode = 0; | 
 | 		} | 
 | 	} | 
 | } | 
 |  | 
 | static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb) | 
 | { | 
 | 	kcb->prev_kprobe.kp = kprobe_running(); | 
 | 	kcb->prev_kprobe.status = kcb->kprobe_status; | 
 | } | 
 |  | 
 | static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb) | 
 | { | 
 | 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); | 
 | 	kcb->kprobe_status = kcb->prev_kprobe.status; | 
 | } | 
 |  | 
 | static void __kprobes set_current_kprobe(struct kprobe *p, struct pt_regs *regs, | 
 | 					 struct kprobe_ctlblk *kcb) | 
 | { | 
 | 	__this_cpu_write(current_kprobe, p); | 
 | } | 
 |  | 
 | /* | 
 |  * Singlestep is implemented by disabling the current kprobe and setting one | 
 |  * on the next instruction, following branches. Two probes are set if the | 
 |  * branch is conditional. | 
 |  */ | 
 | static void __kprobes prepare_singlestep(struct kprobe *p, struct pt_regs *regs) | 
 | { | 
 | 	__this_cpu_write(saved_current_opcode.addr, (kprobe_opcode_t *)regs->pc); | 
 |  | 
 | 	if (p != NULL) { | 
 | 		struct kprobe *op1, *op2; | 
 |  | 
 | 		arch_disarm_kprobe(p); | 
 |  | 
 | 		op1 = this_cpu_ptr(&saved_next_opcode); | 
 | 		op2 = this_cpu_ptr(&saved_next_opcode2); | 
 |  | 
 | 		if (OPCODE_JSR(p->opcode) || OPCODE_JMP(p->opcode)) { | 
 | 			unsigned int reg_nr = ((p->opcode >> 8) & 0x000F); | 
 | 			op1->addr = (kprobe_opcode_t *) regs->regs[reg_nr]; | 
 | 		} else if (OPCODE_BRA(p->opcode) || OPCODE_BSR(p->opcode)) { | 
 | 			unsigned long disp = (p->opcode & 0x0FFF); | 
 | 			op1->addr = | 
 | 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2); | 
 |  | 
 | 		} else if (OPCODE_BRAF(p->opcode) || OPCODE_BSRF(p->opcode)) { | 
 | 			unsigned int reg_nr = ((p->opcode >> 8) & 0x000F); | 
 | 			op1->addr = | 
 | 			    (kprobe_opcode_t *) (regs->pc + 4 + | 
 | 						 regs->regs[reg_nr]); | 
 |  | 
 | 		} else if (OPCODE_RTS(p->opcode)) { | 
 | 			op1->addr = (kprobe_opcode_t *) regs->pr; | 
 |  | 
 | 		} else if (OPCODE_BF(p->opcode) || OPCODE_BT(p->opcode)) { | 
 | 			unsigned long disp = (p->opcode & 0x00FF); | 
 | 			/* case 1 */ | 
 | 			op1->addr = p->addr + 1; | 
 | 			/* case 2 */ | 
 | 			op2->addr = | 
 | 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2); | 
 | 			op2->opcode = *(op2->addr); | 
 | 			arch_arm_kprobe(op2); | 
 |  | 
 | 		} else if (OPCODE_BF_S(p->opcode) || OPCODE_BT_S(p->opcode)) { | 
 | 			unsigned long disp = (p->opcode & 0x00FF); | 
 | 			/* case 1 */ | 
 | 			op1->addr = p->addr + 2; | 
 | 			/* case 2 */ | 
 | 			op2->addr = | 
 | 			    (kprobe_opcode_t *) (regs->pc + 4 + disp * 2); | 
 | 			op2->opcode = *(op2->addr); | 
 | 			arch_arm_kprobe(op2); | 
 |  | 
 | 		} else { | 
 | 			op1->addr = p->addr + 1; | 
 | 		} | 
 |  | 
 | 		op1->opcode = *(op1->addr); | 
 | 		arch_arm_kprobe(op1); | 
 | 	} | 
 | } | 
 |  | 
 | /* Called with kretprobe_lock held */ | 
 | void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, | 
 | 				      struct pt_regs *regs) | 
 | { | 
 | 	ri->ret_addr = (kprobe_opcode_t *) regs->pr; | 
 |  | 
 | 	/* Replace the return addr with trampoline addr */ | 
 | 	regs->pr = (unsigned long)kretprobe_trampoline; | 
 | } | 
 |  | 
 | static int __kprobes kprobe_handler(struct pt_regs *regs) | 
 | { | 
 | 	struct kprobe *p; | 
 | 	int ret = 0; | 
 | 	kprobe_opcode_t *addr = NULL; | 
 | 	struct kprobe_ctlblk *kcb; | 
 |  | 
 | 	/* | 
 | 	 * We don't want to be preempted for the entire | 
 | 	 * duration of kprobe processing | 
 | 	 */ | 
 | 	preempt_disable(); | 
 | 	kcb = get_kprobe_ctlblk(); | 
 |  | 
 | 	addr = (kprobe_opcode_t *) (regs->pc); | 
 |  | 
 | 	/* Check we're not actually recursing */ | 
 | 	if (kprobe_running()) { | 
 | 		p = get_kprobe(addr); | 
 | 		if (p) { | 
 | 			if (kcb->kprobe_status == KPROBE_HIT_SS && | 
 | 			    *p->ainsn.insn == BREAKPOINT_INSTRUCTION) { | 
 | 				goto no_kprobe; | 
 | 			} | 
 | 			/* We have reentered the kprobe_handler(), since | 
 | 			 * another probe was hit while within the handler. | 
 | 			 * We here save the original kprobes variables and | 
 | 			 * just single step on the instruction of the new probe | 
 | 			 * without calling any user handlers. | 
 | 			 */ | 
 | 			save_previous_kprobe(kcb); | 
 | 			set_current_kprobe(p, regs, kcb); | 
 | 			kprobes_inc_nmissed_count(p); | 
 | 			prepare_singlestep(p, regs); | 
 | 			kcb->kprobe_status = KPROBE_REENTER; | 
 | 			return 1; | 
 | 		} | 
 | 		goto no_kprobe; | 
 | 	} | 
 |  | 
 | 	p = get_kprobe(addr); | 
 | 	if (!p) { | 
 | 		/* Not one of ours: let kernel handle it */ | 
 | 		if (*(kprobe_opcode_t *)addr != BREAKPOINT_INSTRUCTION) { | 
 | 			/* | 
 | 			 * The breakpoint instruction was removed right | 
 | 			 * after we hit it. Another cpu has removed | 
 | 			 * either a probepoint or a debugger breakpoint | 
 | 			 * at this address. In either case, no further | 
 | 			 * handling of this interrupt is appropriate. | 
 | 			 */ | 
 | 			ret = 1; | 
 | 		} | 
 |  | 
 | 		goto no_kprobe; | 
 | 	} | 
 |  | 
 | 	set_current_kprobe(p, regs, kcb); | 
 | 	kcb->kprobe_status = KPROBE_HIT_ACTIVE; | 
 |  | 
 | 	if (p->pre_handler && p->pre_handler(p, regs)) { | 
 | 		/* handler has already set things up, so skip ss setup */ | 
 | 		reset_current_kprobe(); | 
 | 		preempt_enable_no_resched(); | 
 | 		return 1; | 
 | 	} | 
 |  | 
 | 	prepare_singlestep(p, regs); | 
 | 	kcb->kprobe_status = KPROBE_HIT_SS; | 
 | 	return 1; | 
 |  | 
 | no_kprobe: | 
 | 	preempt_enable_no_resched(); | 
 | 	return ret; | 
 | } | 
 |  | 
 | /* | 
 |  * For function-return probes, init_kprobes() establishes a probepoint | 
 |  * here. When a retprobed function returns, this probe is hit and | 
 |  * trampoline_probe_handler() runs, calling the kretprobe's handler. | 
 |  */ | 
 | static void __used kretprobe_trampoline_holder(void) | 
 | { | 
 | 	asm volatile (".globl kretprobe_trampoline\n" | 
 | 		      "kretprobe_trampoline:\n\t" | 
 | 		      "nop\n"); | 
 | } | 
 |  | 
 | /* | 
 |  * Called when we hit the probe point at kretprobe_trampoline | 
 |  */ | 
 | int __kprobes trampoline_probe_handler(struct kprobe *p, struct pt_regs *regs) | 
 | { | 
 | 	struct kretprobe_instance *ri = NULL; | 
 | 	struct hlist_head *head, empty_rp; | 
 | 	struct hlist_node *tmp; | 
 | 	unsigned long flags, orig_ret_address = 0; | 
 | 	unsigned long trampoline_address = (unsigned long)&kretprobe_trampoline; | 
 |  | 
 | 	INIT_HLIST_HEAD(&empty_rp); | 
 | 	kretprobe_hash_lock(current, &head, &flags); | 
 |  | 
 | 	/* | 
 | 	 * It is possible to have multiple instances associated with a given | 
 | 	 * task either because an multiple functions in the call path | 
 | 	 * have a return probe installed on them, and/or more then one return | 
 | 	 * return probe was registered for a target function. | 
 | 	 * | 
 | 	 * We can handle this because: | 
 | 	 *     - instances are always inserted at the head of the list | 
 | 	 *     - when multiple return probes are registered for the same | 
 | 	 *       function, the first instance's ret_addr will point to the | 
 | 	 *       real return address, and all the rest will point to | 
 | 	 *       kretprobe_trampoline | 
 | 	 */ | 
 | 	hlist_for_each_entry_safe(ri, tmp, head, hlist) { | 
 | 		if (ri->task != current) | 
 | 			/* another task is sharing our hash bucket */ | 
 | 			continue; | 
 |  | 
 | 		if (ri->rp && ri->rp->handler) { | 
 | 			__this_cpu_write(current_kprobe, &ri->rp->kp); | 
 | 			ri->rp->handler(ri, regs); | 
 | 			__this_cpu_write(current_kprobe, NULL); | 
 | 		} | 
 |  | 
 | 		orig_ret_address = (unsigned long)ri->ret_addr; | 
 | 		recycle_rp_inst(ri, &empty_rp); | 
 |  | 
 | 		if (orig_ret_address != trampoline_address) | 
 | 			/* | 
 | 			 * This is the real return address. Any other | 
 | 			 * instances associated with this task are for | 
 | 			 * other calls deeper on the call stack | 
 | 			 */ | 
 | 			break; | 
 | 	} | 
 |  | 
 | 	kretprobe_assert(ri, orig_ret_address, trampoline_address); | 
 |  | 
 | 	regs->pc = orig_ret_address; | 
 | 	kretprobe_hash_unlock(current, &flags); | 
 |  | 
 | 	hlist_for_each_entry_safe(ri, tmp, &empty_rp, hlist) { | 
 | 		hlist_del(&ri->hlist); | 
 | 		kfree(ri); | 
 | 	} | 
 |  | 
 | 	return orig_ret_address; | 
 | } | 
 |  | 
 | static int __kprobes post_kprobe_handler(struct pt_regs *regs) | 
 | { | 
 | 	struct kprobe *cur = kprobe_running(); | 
 | 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 
 | 	kprobe_opcode_t *addr = NULL; | 
 | 	struct kprobe *p = NULL; | 
 |  | 
 | 	if (!cur) | 
 | 		return 0; | 
 |  | 
 | 	if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { | 
 | 		kcb->kprobe_status = KPROBE_HIT_SSDONE; | 
 | 		cur->post_handler(cur, regs, 0); | 
 | 	} | 
 |  | 
 | 	p = this_cpu_ptr(&saved_next_opcode); | 
 | 	if (p->addr) { | 
 | 		arch_disarm_kprobe(p); | 
 | 		p->addr = NULL; | 
 | 		p->opcode = 0; | 
 |  | 
 | 		addr = __this_cpu_read(saved_current_opcode.addr); | 
 | 		__this_cpu_write(saved_current_opcode.addr, NULL); | 
 |  | 
 | 		p = get_kprobe(addr); | 
 | 		arch_arm_kprobe(p); | 
 |  | 
 | 		p = this_cpu_ptr(&saved_next_opcode2); | 
 | 		if (p->addr) { | 
 | 			arch_disarm_kprobe(p); | 
 | 			p->addr = NULL; | 
 | 			p->opcode = 0; | 
 | 		} | 
 | 	} | 
 |  | 
 | 	/* Restore back the original saved kprobes variables and continue. */ | 
 | 	if (kcb->kprobe_status == KPROBE_REENTER) { | 
 | 		restore_previous_kprobe(kcb); | 
 | 		goto out; | 
 | 	} | 
 |  | 
 | 	reset_current_kprobe(); | 
 |  | 
 | out: | 
 | 	preempt_enable_no_resched(); | 
 |  | 
 | 	return 1; | 
 | } | 
 |  | 
 | int __kprobes kprobe_fault_handler(struct pt_regs *regs, int trapnr) | 
 | { | 
 | 	struct kprobe *cur = kprobe_running(); | 
 | 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 
 | 	const struct exception_table_entry *entry; | 
 |  | 
 | 	switch (kcb->kprobe_status) { | 
 | 	case KPROBE_HIT_SS: | 
 | 	case KPROBE_REENTER: | 
 | 		/* | 
 | 		 * We are here because the instruction being single | 
 | 		 * stepped caused a page fault. We reset the current | 
 | 		 * kprobe, point the pc back to the probe address | 
 | 		 * and allow the page fault handler to continue as a | 
 | 		 * normal page fault. | 
 | 		 */ | 
 | 		regs->pc = (unsigned long)cur->addr; | 
 | 		if (kcb->kprobe_status == KPROBE_REENTER) | 
 | 			restore_previous_kprobe(kcb); | 
 | 		else | 
 | 			reset_current_kprobe(); | 
 | 		preempt_enable_no_resched(); | 
 | 		break; | 
 | 	case KPROBE_HIT_ACTIVE: | 
 | 	case KPROBE_HIT_SSDONE: | 
 | 		/* | 
 | 		 * We increment the nmissed count for accounting, | 
 | 		 * we can also use npre/npostfault count for accounting | 
 | 		 * these specific fault cases. | 
 | 		 */ | 
 | 		kprobes_inc_nmissed_count(cur); | 
 |  | 
 | 		/* | 
 | 		 * We come here because instructions in the pre/post | 
 | 		 * handler caused the page_fault, this could happen | 
 | 		 * if handler tries to access user space by | 
 | 		 * copy_from_user(), get_user() etc. Let the | 
 | 		 * user-specified handler try to fix it first. | 
 | 		 */ | 
 | 		if (cur->fault_handler && cur->fault_handler(cur, regs, trapnr)) | 
 | 			return 1; | 
 |  | 
 | 		/* | 
 | 		 * In case the user-specified fault handler returned | 
 | 		 * zero, try to fix up. | 
 | 		 */ | 
 | 		if ((entry = search_exception_tables(regs->pc)) != NULL) { | 
 | 			regs->pc = entry->fixup; | 
 | 			return 1; | 
 | 		} | 
 |  | 
 | 		/* | 
 | 		 * fixup_exception() could not handle it, | 
 | 		 * Let do_page_fault() fix it. | 
 | 		 */ | 
 | 		break; | 
 | 	default: | 
 | 		break; | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | /* | 
 |  * Wrapper routine to for handling exceptions. | 
 |  */ | 
 | int __kprobes kprobe_exceptions_notify(struct notifier_block *self, | 
 | 				       unsigned long val, void *data) | 
 | { | 
 | 	struct kprobe *p = NULL; | 
 | 	struct die_args *args = (struct die_args *)data; | 
 | 	int ret = NOTIFY_DONE; | 
 | 	kprobe_opcode_t *addr = NULL; | 
 | 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 
 |  | 
 | 	addr = (kprobe_opcode_t *) (args->regs->pc); | 
 | 	if (val == DIE_TRAP && | 
 | 	    args->trapnr == (BREAKPOINT_INSTRUCTION & 0xff)) { | 
 | 		if (!kprobe_running()) { | 
 | 			if (kprobe_handler(args->regs)) { | 
 | 				ret = NOTIFY_STOP; | 
 | 			} else { | 
 | 				/* Not a kprobe trap */ | 
 | 				ret = NOTIFY_DONE; | 
 | 			} | 
 | 		} else { | 
 | 			p = get_kprobe(addr); | 
 | 			if ((kcb->kprobe_status == KPROBE_HIT_SS) || | 
 | 			    (kcb->kprobe_status == KPROBE_REENTER)) { | 
 | 				if (post_kprobe_handler(args->regs)) | 
 | 					ret = NOTIFY_STOP; | 
 | 			} else { | 
 | 				if (kprobe_handler(args->regs)) | 
 | 					ret = NOTIFY_STOP; | 
 | 			} | 
 | 		} | 
 | 	} | 
 |  | 
 | 	return ret; | 
 | } | 
 |  | 
 | static struct kprobe trampoline_p = { | 
 | 	.addr = (kprobe_opcode_t *)&kretprobe_trampoline, | 
 | 	.pre_handler = trampoline_probe_handler | 
 | }; | 
 |  | 
 | int __init arch_init_kprobes(void) | 
 | { | 
 | 	return register_kprobe(&trampoline_p); | 
 | } |