spin_lock_irqsave(&uprobes_treelock, flags);
u = __insert_uprobe(uprobe);
spin_unlock_irqrestore(&uprobes_treelock, flags);
+
+ /* For now assume that the instruction need not be single-stepped */
+ uprobe->flags |= UPROBES_SKIP_SSTEP;
return u;
}
{
struct uprobe_consumer *consumer;
+ if (!(uprobe->flags & UPROBES_RUN_HANDLER))
+ return;
+
down_read(&uprobe->consumer_rwsem);
consumer = uprobe->consumers;
for (consumer = uprobe->consumers; consumer;
return -EEXIST;
addr = (unsigned long)vaddr;
- if (!uprobe->copy) {
+ if (!(uprobe->flags & UPROBES_COPY_INSN)) {
ret = copy_insn(uprobe, vma, addr);
if (ret)
return ret;
if (ret)
return ret;
- uprobe->copy = 1;
+ uprobe->flags |= UPROBES_COPY_INSN;
}
ret = set_bkpt(mm, uprobe, addr);
if (!ret)
if (ret) {
uprobe->consumers = NULL;
__unregister_uprobe(inode, offset, uprobe);
- }
+ } else
+ uprobe->flags |= UPROBES_RUN_HANDLER;
}
mutex_unlock(uprobes_hash(inode));
goto unreg_out;
}
- if (!uprobe->consumers)
+ if (!uprobe->consumers) {
__unregister_uprobe(inode, offset, uprobe);
-
+ uprobe->flags &= ~UPROBES_RUN_HANDLER;
+ }
mutex_unlock(uprobes_hash(inode));
unreg_out:
spin_lock_irq(&tsk->sighand->siglock);
clear_tsk_thread_flag(tsk, TIF_SIGPENDING);
spin_unlock_irq(&tsk->sighand->siglock);
+
+ if (__fatal_signal_pending(tsk) || xol_was_trapped(tsk)) {
+ utask->state = UTASK_SSTEP_TRAPPED;
+ set_tsk_thread_flag(tsk, TIF_UPROBE);
+ set_tsk_thread_flag(tsk, TIF_NOTIFY_RESUME);
+ }
}
return true;
}
+bool __weak can_skip_xol(struct pt_regs *regs, struct uprobe *u)
+{
+ u->flags &= ~UPROBES_SKIP_SSTEP;
+ return false;
+}
+
/*
* uprobe_notify_resume gets called in task context just before returning
* to userspace.
}
utask->active_uprobe = u;
handler_chain(u, regs);
+
+ if (u->flags & UPROBES_SKIP_SSTEP && can_skip_xol(regs, u))
+ goto cleanup_ret;
+
utask->state = UTASK_SSTEP;
if (!pre_ssout(u, regs, probept))
user_enable_single_step(current);
u = utask->active_uprobe;
if (utask->state == UTASK_SSTEP_ACK)
post_xol(u, regs);
+ else if (utask->state == UTASK_SSTEP_TRAPPED)
+ abort_xol(regs, u);
else
WARN_ON_ONCE(1);
utask->state = UTASK_RUNNING;
}
if (u) {
+ if (!(u->flags & UPROBES_SKIP_SSTEP))
+ set_instruction_pointer(regs, probept);
+
put_uprobe(u);
- set_instruction_pointer(regs, probept);
- } else {
- /*TODO Return SIGTRAP signal */
- }
+ } else
+ send_sig(SIGTRAP, current, 0);
}
/*