summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKeshavamurthy Anil S <anil.s.keshavamurthy@intel.com>2005-09-06 15:19:32 -0700
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 16:58:00 -0700
commit661e5a3d9958dc83d610992da85625c0ada9bb06 (patch)
tree914bff2285c3eee9324d0d0a8eb633926ef47008
parent83005161c84efa70f3d4dc193eb1024a40b650dc (diff)
[PATCH] Kprobes/IA64: fix race when break hits and kprobe not found
This patch addresses a potential race condition for a case where Kprobe has been removed right after another CPU has taken a break hit. The way this is addressed here is when the CPU that has taken a break hit does not find its corresponding kprobe, then we check to see if the original instruction got replaced with other than break. If it got replaced with other than break instruction, then we continue to execute from the replaced instruction, else if we find that it is still a break, then we let the kernel handle this, as this might be the break instruction inserted by other than kprobe(may be kernel debugger). Signed-off-by: Anil S Keshavamurthy <anil.s.keshavamurthy@intel.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/ia64/kernel/kprobes.c45
1 files changed, 45 insertions, 0 deletions
diff --git a/arch/ia64/kernel/kprobes.c b/arch/ia64/kernel/kprobes.c
index 82a41ac2938..4b1bd539ec4 100644
--- a/arch/ia64/kernel/kprobes.c
+++ b/arch/ia64/kernel/kprobes.c
@@ -554,6 +554,38 @@ static void __kprobes prepare_ss(struct kprobe *p, struct pt_regs *regs)
ia64_psr(regs)->ss = 1;
}
+static int __kprobes is_ia64_break_inst(struct pt_regs *regs)
+{
+ unsigned int slot = ia64_psr(regs)->ri;
+ unsigned int template, major_opcode;
+ unsigned long kprobe_inst;
+ unsigned long *kprobe_addr = (unsigned long *)regs->cr_iip;
+ bundle_t bundle;
+
+ memcpy(&bundle, kprobe_addr, sizeof(bundle_t));
+ template = bundle.quad0.template;
+
+ /* Move to slot 2, if bundle is MLX type and kprobe slot is 1 */
+ if (slot == 1 && bundle_encoding[template][1] == L)
+ slot++;
+
+ /* Get Kprobe probe instruction at given slot*/
+ get_kprobe_inst(&bundle, slot, &kprobe_inst, &major_opcode);
+
+ /* For break instruction,
+ * Bits 37:40 Major opcode to be zero
+ * Bits 27:32 X6 to be zero
+ * Bits 32:35 X3 to be zero
+ */
+ if (major_opcode || ((kprobe_inst >> 27) & 0x1FF) ) {
+ /* Not a break instruction */
+ return 0;
+ }
+
+ /* Is a break instruction */
+ return 1;
+}
+
static int __kprobes pre_kprobes_handler(struct die_args *args)
{
struct kprobe *p;
@@ -601,6 +633,19 @@ static int __kprobes pre_kprobes_handler(struct die_args *args)
p = get_kprobe(addr);
if (!p) {
unlock_kprobes();
+ if (!is_ia64_break_inst(regs)) {
+ /*
+ * 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 our break, let kernel handle it */
goto no_kprobe;
}