# warning ARCH_REG_VAL is not implemented for this architecture. FBI will work improperly or even crash!!!
#endif // ARCH
+#if defined(CONFIG_ARM)
+#define SP(regs) (regs)->ARM_sp
+#elif defined(CONFIG_X86)
+#define SP(regs) (regs)->EREG(sp)
+#else
+#error SP(regs) is not implemented
+#endif /* CONFIG_* */
+
unsigned long (*dbi_ujprobe_event_pre_handler_custom_p)
(us_proc_ip_t *, struct pt_regs *) = NULL;
EXPORT_SYMBOL(dbi_ujprobe_event_pre_handler_custom_p);
struct pt_regs *regs)
{
#ifdef CONFIG_ADD_THREAD_STACK_INFO
- return (task->stack_start - regs->ARM_sp);
+ return (task->stack_start - SP(regs));
#else
struct vm_area_struct *vma = NULL;
struct mm_struct *mm = NULL;
if (!atomic)
down_read(&mm->mmap_sem);
- vma = find_vma(mm, regs->ARM_sp);
+ vma = find_vma(mm, SP(regs));
if (vma)
- result = vma->vm_end - regs->ARM_sp;
+ result = vma->vm_end - SP(regs);
else
result = 0;
{
unsigned long stack_sz = get_stack_size(task, regs);
unsigned long real_sz = (stack_sz > sz ? sz: stack_sz);
- int res = read_proc_vm_atomic(task, regs->ARM_sp, buf, real_sz);
+ int res = read_proc_vm_atomic(task, SP(regs), buf, real_sz);
return res;
}
EXPORT_SYMBOL_GPL(get_stack);
#define SUPRESS_BUG_MESSAGES
+extern unsigned int *sched_addr;
+extern unsigned int *fork_addr;
+
+extern struct kprobe * per_cpu__current_kprobe;
+
extern struct kprobe * per_cpu__current_kprobe;
+extern spinlock_t kretprobe_lock;
+extern struct kretprobe *sched_rp;
extern struct hlist_head kprobe_insn_pages;
extern struct hlist_head uprobe_insn_pages;
DECLARE_MOD_FUNC_DEP(module_free, void, struct module *mod, void *module_region);
DECLARE_MOD_FUNC_DEP(fixup_exception, int, struct pt_regs * regs);
+DECLARE_MOD_FUNC_DEP(freeze_processes, int, void);
+DECLARE_MOD_FUNC_DEP(thaw_processes, void, void);
+
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
DECLARE_MOD_FUNC_DEP(text_poke, void, void *addr, unsigned char *opcode, int len);
#else
if ((unsigned long) p->addr & 0x01)
{
DBPRINTF ("Attempt to register kprobe at an unaligned address\n");
- ret = -EINVAL;
+ //ret = -EINVAL;
}
void prepare_singlestep (struct kprobe *p, struct pt_regs *regs)
{
-
if(p->ss_addr)
{
regs->EREG (ip) = (unsigned long)p->ss_addr;
return ret;
}
+void patch_suspended_task_ret_addr(struct task_struct *p, struct kretprobe *rp)
+{
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_node *node, *tmp;
+ struct hlist_head *head;
+ unsigned long flags;
+ int found = 0;
+
+ /* DO NOT patch exiting tasks */
+ /*if ((p->state & TASK_DEAD) || (p->exit_state != 0) || (p->flags & PF_EXITING) || (p->flags & PF_EXITPIDONE))
+ return;*/
+ /*spin_lock_irq(&p->pi_lock);
+ if (unlikely((p->flags & PF_EXITING) || (p->flags & PF_EXITPIDONE))) {
+ spin_unlock_irq(&p->pi_lock);
+ return;
+ }
+ spin_unlock_irq(&p->pi_lock);*/
+
+ spin_lock_irqsave(&kretprobe_lock, flags);
+ head = kretprobe_inst_table_head(p);
+ hlist_for_each_entry_safe(ri, node, tmp, head, hlist) {
+ if (ri->rp == rp && p == ri->task) {
+ found = 1;
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+
+ if (found) {
+ /* update PC */
+ if (p->thread.EREG(ip) != &kretprobe_trampoline) {
+ ri->ret_addr = (kprobe_opcode_t *)p->thread.EREG(ip);
+ p->thread.EREG(ip) = &kretprobe_trampoline;
+ }
+ return;
+ }
+
+ spin_lock_irqsave(&kretprobe_lock, flags);
+ if ((ri = get_free_rp_inst(rp)) != NULL) {
+ ri->rp = rp;
+ ri->rp2 = NULL;
+ ri->task = p;
+ ri->ret_addr = (kprobe_opcode_t *)p->thread.EREG(ip);
+ p->thread.EREG(ip) = &kretprobe_trampoline;
+ add_rp_inst(ri);
+ } else {
+ printk("no ri for %d\n", p->pid);
+ BUG();
+ }
+ spin_unlock_irqrestore(&kretprobe_lock, flags);
+}
+
int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs)
{
+//#if 0
+ struct jprobe *jp = container_of (p, struct jprobe, kp);
+ kprobe_pre_entry_handler_t pre_entry;
+ entry_point_t entry;
+
+ unsigned long addr, args[6];
+ struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
+
+ DBPRINTF ("setjmp_pre_handler %p:%d", p->addr, p->tgid);
+ pre_entry = (kprobe_pre_entry_handler_t) jp->pre_entry;
+ entry = (entry_point_t) jp->entry;
+
+ if (!p->tgid || (p->tgid == current->tgid)) {
+ /* handle __switch_to probe */
+ if(!p->tgid && (p->addr == sched_addr) && sched_rp) {
+ struct task_struct *p, *g;
+ rcu_read_lock();
+ //swapper task
+ if(current != &init_task)
+ patch_suspended_task_ret_addr(&init_task, sched_rp);
+ // other tasks
+ do_each_thread(g, p){
+ if(current != p)
+ patch_suspended_task_ret_addr(p, sched_rp);
+ } while_each_thread(g, p);
+ rcu_read_unlock();
+ }
+
+ /* TODO handle do_exit probe */
+ }
+
+ if (p->tgid) {
+ regs->EREG(flags) &= ~IF_MASK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+ trace_hardirqs_off ();
+#endif
+ if (p->tgid == current->tgid) {
+ // read first 6 args from stack
+ if (!read_proc_vm_atomic (current, regs->EREG(sp) + 4, args, sizeof(args)))
+ panic ("failed to read user space func arguments %lx!\n", regs->EREG(sp)+4);
+ if (pre_entry)
+ p->ss_addr = pre_entry (jp->priv_arg, regs);
+ if (entry)
+ entry (args[0], args[1], args[2], args[3], args[4], args[5]);
+ } else {
+ dbi_arch_uprobe_return();
+ }
+
+ return 2;
+ } else {
+ kcb->jprobe_saved_regs = *regs;
+ kcb->jprobe_saved_esp = ®s->EREG(sp);
+ addr = (unsigned long) (kcb->jprobe_saved_esp);
+
+ /* TBD: As Linus pointed out, gcc assumes that the callee
+ * owns the argument space and could overwrite it, e.g.
+ * tailcall optimization. So, to be absolutely safe
+ * we also save and restore enough stack bytes to cover
+ * the argument area. */
+ memcpy (kcb->jprobes_stack, (kprobe_opcode_t *)addr, MIN_STACK_SIZE (addr));
+ regs->EREG (flags) &= ~IF_MASK;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 18)
+ trace_hardirqs_off ();
+#endif
+ if (pre_entry)
+ p->ss_addr = pre_entry(jp->priv_arg, regs);
+ regs->EREG(ip) = (unsigned long) (jp->entry);
+ }
+
+ return 1;
+//#endif /* 0 */
+
+#if 0 /* initial version */
struct jprobe *jp = container_of (p, struct jprobe, kp);
kprobe_pre_entry_handler_t pre_entry;
entry_point_t entry;
}
return 1;
+#endif /* 0 */
}
void dbi_jprobe_return (void)
DBPRINTF ("switch (val) %lu %d %d", val, DIE_INT3, DIE_TRAP);
switch (val)
{
- //#ifdef CONFIG_KPROBES
- // case DIE_INT3:
- //#else
+#ifdef CONFIG_KPROBES
+ case DIE_INT3:
+#else
case DIE_TRAP:
- //#endif
+#endif
DBPRINTF ("before kprobe_handler ret=%d %p", ret, args->regs);
if (kprobe_handler (args->regs))
ret = NOTIFY_STOP;