arch/sparc/kernel/kprobes.c

Source file repositories/reference/linux-study-clean/arch/sparc/kernel/kprobes.c

File Facts

System
Linux kernel
Corpus path
arch/sparc/kernel/kprobes.c
Extension
.c
Size
13017 bytes
Lines
490
Domain
Architecture Layer
Bucket
arch/sparc
Inferred role
Architecture Layer: implementation source
Status
source implementation candidate

Why This File Exists

CPU and platform-specific kernel glue: boot entry, traps, syscall entry, interrupts, page tables, context switch, and low-level barriers.

Dependency Surface

Detected Declarations

Annotated Snippet

if (p) {
			if (kcb->kprobe_status == KPROBE_HIT_SS) {
				regs->tstate = ((regs->tstate & ~TSTATE_PIL) |
					kcb->kprobe_orig_tstate_pil);
				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);
			kcb->kprobe_status = KPROBE_REENTER;
			prepare_singlestep(p, regs, kcb);
			return 1;
		} else if (*(u32 *)addr != BREAKPOINT_INSTRUCTION) {
			/* The breakpoint instruction was removed by
			 * another cpu right after we hit, no further
			 * handling of this interrupt is appropriate
			 */
			ret = 1;
		}
		goto no_kprobe;
	}

	p = get_kprobe(addr);
	if (!p) {
		if (*(u32 *)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;
		}
		/* Not one of ours: let kernel handle it */
		goto no_kprobe;
	}

	set_current_kprobe(p, regs, kcb);
	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
	if (p->pre_handler && p->pre_handler(p, regs)) {
		reset_current_kprobe();
		preempt_enable_no_resched();
		return 1;
	}

	prepare_singlestep(p, regs, kcb);
	kcb->kprobe_status = KPROBE_HIT_SS;
	return 1;

no_kprobe:
	preempt_enable_no_resched();
	return ret;
}

/* If INSN is a relative control transfer instruction,
 * return the corrected branch destination value.
 *
 * regs->tpc and regs->tnpc still hold the values of the
 * program counters at the time of trap due to the execution
 * of the BREAKPOINT_INSTRUCTION_2 at p->ainsn.insn[1]
 * 
 */
static unsigned long __kprobes relbranch_fixup(u32 insn, struct kprobe *p,
					       struct pt_regs *regs)
{
	unsigned long real_pc = (unsigned long) p->addr;

	/* Branch not taken, no mods necessary.  */
	if (regs->tnpc == regs->tpc + 0x4UL)
		return real_pc + 0x8UL;

	/* The three cases are call, branch w/prediction,
	 * and traditional branch.
	 */
	if ((insn & 0xc0000000) == 0x40000000 ||
	    (insn & 0xc1c00000) == 0x00400000 ||
	    (insn & 0xc1c00000) == 0x00800000) {
		unsigned long ainsn_addr;

		ainsn_addr = (unsigned long) &p->ainsn.insn[0];

		/* The instruction did all the work for us
		 * already, just apply the offset to the correct

Annotation

Implementation Notes