if (!ret)
{
p->opcode = *p->addr;
- p->ainsn.boostable = 1;
uregs = pc_dep = 0;
// Rn, Rm ,Rd
(ARM_INSN_REG_RD (insn[0]) == 15)))
{
pc_dep = 1;
- DBPRINTF ("Unboostable insn %lx/%p/%d, DPI/LIO/SIO\n", insn[0], p, p->ainsn.boostable);
+ DBPRINTF ("Unboostable insn %lx/%p, DPI/LIO/SIO\n", insn[0], p);
}
}
// Rn, Rm, Rs
// check instructions that can write result to SP andu uses PC
if (pc_dep && (ARM_INSN_REG_RD (ainsn.insn[0]) == 13))
{
- free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0);
+ free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
ret = -EFAULT;
}
else
if (prep_pc_dep_insn_execbuf (insns, insn[0], uregs) != 0)
{
DBPRINTF ("failed to prepare exec buffer for insn %lx!", insn[0]);
- free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0);
+ free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
return -EINVAL;
}
insns[6] = (kprobe_opcode_t) (p->addr + 2);
}
else
{
- free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0);
+ free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
printk("arch_prepare_kprobe: instruction 0x%x not instrumentation, addr=0x%p\n", insn[0], p->addr);
}
}
ret = arch_copy_trampoline_arm_uprobe(p, task, 1);
if (ret) {
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_arm, 0);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
return -EFAULT;
}
p->ainsn.insn_thumb = get_insn_slot(task, atomic);
}
ret = arch_copy_trampoline_thumb_uprobe(p, task, 1);
if (ret) {
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_arm, 0);
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_thumb, 0);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
return -EFAULT;
}
if ((p->safe_arm == -1) && (p->safe_thumb == -1)) {
printk("Error in %s at %d: failed arch_copy_trampoline_*_uprobe() (both)\n", __FILE__, __LINE__);
if (!write_proc_vm_atomic (task, (unsigned long) p->addr, &p->opcode, sizeof (p->opcode)))
panic ("Failed to write memory %p!\n", p->addr);
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_arm, 0);
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn_thumb, 0);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
return -EFAULT;
}
- p->ainsn.boostable = 1;
return ret;
}
void prepare_singlestep (struct kprobe *p, struct pt_regs *regs)
{
- if(p->ss_addr)
- {
- regs->uregs[15] = (unsigned long) p->ss_addr;
+ if (p->ss_addr) {
+ regs->ARM_pc = (unsigned long)p->ss_addr;
p->ss_addr = NULL;
+ } else {
+ regs->ARM_pc = (unsigned long)p->ainsn.insn;
}
- else
- regs->uregs[15] = (unsigned long) p->ainsn.insn;
}
static void arm_save_previous_kprobe(struct kprobe_ctlblk *kcb, struct pt_regs *regs, struct kprobe *p_run)
(ARM_INSN_REG_RD (insn[0]) == 15)))
{
pc_dep = 1;
- DBPRINTF ("Unboostable insn %lx/%p/%d, DPI/LIO/SIO\n", insn[0], p, p->ainsn.boostable);
+ DBPRINTF ("Unboostable insn %lx/%p, DPI/LIO/SIO\n", insn[0], p);
}
}
// Rn, Rm, Rs
return 0;
}
+static int check_validity_insn(struct kprobe *p, struct pt_regs *regs, struct task_struct *task)
+{
+ struct kprobe *kp;
+
+ if (unlikely(thumb_mode(regs))) {
+ if (p->safe_thumb != -1) {
+ p->ainsn.insn = p->ainsn.insn_thumb;
+ list_for_each_entry_rcu(kp, &p->list, list) {
+ kp->ainsn.insn = p->ainsn.insn_thumb;
+ }
+ } else {
+ printk("Error in %s at %d: we are in thumb mode (!) and check instruction was fail \
+ (%0X instruction at %p address)!\n", __FILE__, __LINE__, p->opcode, p->addr);
+ // Test case when we do our actions on already running application
+ arch_disarm_uprobe(p, task);
+ return -1;
+ }
+ } else {
+ if (p->safe_arm != -1) {
+ p->ainsn.insn = p->ainsn.insn_arm;
+ list_for_each_entry_rcu(kp, &p->list, list) {
+ kp->ainsn.insn = p->ainsn.insn_arm;
+ }
+ } else {
+ printk("Error in %s at %d: we are in arm mode (!) and check instruction was fail \
+ (%0X instruction at %p address)!\n", __FILE__, __LINE__, p->opcode, p->addr );
+ // Test case when we do our actions on already running application
+ arch_disarm_uprobe(p, task);
+ return -1;
+ }
+ }
-int kprobe_handler (struct pt_regs *regs)
+ return 0;
+}
+
+int kprobe_handler(struct pt_regs *regs)
{
+ int err_out = 0;
+ char *msg_out = NULL;
+ unsigned long user_m = user_mode(regs);
+ pid_t tgid = (user_m) ? current->tgid : 0;
+ kprobe_opcode_t *addr = (kprobe_opcode_t *) (regs->ARM_pc);
+
struct kprobe *p = NULL, *p_run = NULL;
- int ret = 0, pid = 0, retprobe = 0, reenter = 0;
- kprobe_opcode_t *addr = NULL, *ssaddr = 0;
+ int ret = 0, retprobe = 0, reenter = 0;
+ kprobe_opcode_t *ssaddr = 0;
struct kprobe_ctlblk *kcb;
int i = 0;
-#ifdef OVERHEAD_DEBUG
- struct timeval swap_tv1;
- struct timeval swap_tv2;
-#endif
-#ifdef SUPRESS_BUG_MESSAGES
- int swap_oops_in_progress;
-#endif
- struct hlist_head *head;
- struct hlist_node *node;
- struct kprobe *pop, *retVal = NULL;
- struct kprobe *kp;
#ifdef SUPRESS_BUG_MESSAGES
+ int swap_oops_in_progress;
// oops_in_progress used to avoid BUG() messages that slow down kprobe_handler() execution
swap_oops_in_progress = oops_in_progress;
oops_in_progress = 1;
#endif
#ifdef OVERHEAD_DEBUG
+ struct timeval swap_tv1;
+ struct timeval swap_tv2;
#define USEC_IN_SEC_NUM 1000000
do_gettimeofday(&swap_tv1);
#endif
preempt_disable();
- addr = (kprobe_opcode_t *) (regs->uregs[15]);
- if (user_mode(regs))
- {
- head = &kprobe_table[hash_ptr (addr, KPROBE_HASH_BITS)];
- hlist_for_each_entry_rcu (pop, node, head, hlist) {
- /*
- * Searching occurred probe by
- * instruction address and task_struct
- */
- if (pop->addr == addr) {
- if (pop->tgid == current->tgid) {
- retVal = pop;
- break;
- }
- }
- }
- }
- if (retVal) {
- if (unlikely(thumb_mode(regs))) {
- if (pop->safe_thumb != -1) {
- pop->ainsn.insn = pop->ainsn.insn_thumb;
- list_for_each_entry_rcu (kp, &pop->list, list) {
- kp->ainsn.insn = pop->ainsn.insn_thumb;
- }
- }
- else {
- printk("Error in %s at %d: we are in thumb mode (!) and check instruction was fail \
- (%0X instruction at %p address)!\n", __FILE__, __LINE__, pop->opcode, pop->addr);
- // Test case when we do our actions on already running application
- arch_disarm_uprobe (pop, current);
- goto no_kprobe_live;
- }
- }
- else {
- if (pop->safe_arm != -1) {
- pop->ainsn.insn = pop->ainsn.insn_arm;
- list_for_each_entry_rcu (kp, &pop->list, list) {
- kp->ainsn.insn = pop->ainsn.insn_arm;
- }
- }
- else {
- printk("Error in %s at %d: we are in arm mode (!) and check instruction was fail \
- (%0X instruction at %p address)!\n", __FILE__, __LINE__, pop->opcode, pop->addr );
- // Test case when we do our actions on already running application
- arch_disarm_uprobe (pop, current);
- goto no_kprobe_live;
- }
- }
+
+ p = get_kprobe(addr, tgid);
+
+ if (user_m && p && (check_validity_insn(p, regs, current) != 0)) {
+ goto no_kprobe_live;
}
+
/* We're in an interrupt, but this is clear and BUG()-safe. */
kcb = get_kprobe_ctlblk ();
- if (user_mode (regs))
- {
- //DBPRINTF("exception[%lu] from user mode %s/%u addr %p (%lx).", nCount, current->comm, current->pid, addr, regs->uregs[14]);
- pid = current->tgid;
- }
+
/* Check we're not actually recursing */
// TODO: event is not saving in trace
p_run = kprobe_running(regs);
if (p_run)
{
- DBPRINTF ("lock???");
- p = get_kprobe (addr, pid, current);
+ DBPRINTF("lock???");
if (p)
{
- if(!pid && (addr == (kprobe_opcode_t *)kretprobe_trampoline)){
+ if (!tgid && (addr == (kprobe_opcode_t *)kretprobe_trampoline)) {
arm_save_previous_kprobe(kcb, regs, p_run);
kcb->kprobe_status = KPROBE_REENTER;
reenter = 1;
- }
- else {
+ } else {
/* 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.
*/
- if(!p->ainsn.boostable){
- arm_save_previous_kprobe(kcb, regs, p_run);
- set_current_kprobe(p, regs, kcb);
- }
kprobes_inc_nmissed_count (p);
prepare_singlestep (p, regs);
- if(!p->ainsn.boostable)
- kcb->kprobe_status = KPROBE_REENTER;
- preempt_enable_no_resched ();
-#ifdef OVERHEAD_DEBUG
- do_gettimeofday(&swap_tv2);
- swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
- (swap_tv2.tv_usec - swap_tv1.tv_usec));
-#endif
-#ifdef SUPRESS_BUG_MESSAGES
- oops_in_progress = swap_oops_in_progress;
-#endif
- return 0;
+
+ err_out = 0;
+ goto out;
}
- }
- else
- {
- if(pid) { //we can reenter probe upon uretprobe exception
+ } else {
+ if(tgid) { //we can reenter probe upon uretprobe exception
DBPRINTF ("check for UNDEF_INSTRUCTION %p\n", addr);
// UNDEF_INSTRUCTION from user space
- if (!thumb_mode ( regs ))
- p = get_kprobe_by_insn_slot_arm (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
- else
- p = get_kprobe_by_insn_slot_thumb ((unsigned long)addr - 0x1a, pid, current);
-
+ p = get_kprobe_by_insn_slot(addr, tgid, regs);
if (p) {
arm_save_previous_kprobe(kcb, regs, p_run);
kcb->kprobe_status = KPROBE_REENTER;
goto ss_probe;
} */
DBPRINTF ("unknown uprobe at %p cur at %p/%p\n", addr, p->addr, p->ainsn.insn);
- if(pid)
+ if (tgid)
ssaddr = p->ainsn.insn + UPROBES_TRAMP_SS_BREAK_IDX;
else
ssaddr = p->ainsn.insn + KPROBES_TRAMP_SS_BREAK_IDX;
- if (addr == ssaddr)
- {
- regs->uregs[15] = (unsigned long) (p->addr + 1);
- DBPRINTF ("finish step at %p cur at %p/%p, redirect to %lx\n", addr, p->addr, p->ainsn.insn, regs->uregs[15]);
+ if (addr == ssaddr) {
+ regs->ARM_pc = (unsigned long) (p->addr + 1);
+ DBPRINTF ("finish step at %p cur at %p/%p, redirect to %lx\n", addr, p->addr, p->ainsn.insn, regs->ARM_pc);
if (kcb->kprobe_status == KPROBE_REENTER) {
arm_restore_previous_kprobe(kcb, regs);
} else {
}
}
}
- if (!p)
- {
- p = get_kprobe (addr, pid, current);
- }
- if (!p)
- {
- if(pid) {
+
+ if (!p) {
+ if (tgid) {
DBPRINTF ("search UNDEF_INSTRUCTION %p\n", addr);
// UNDEF_INSTRUCTION from user space
- if (!thumb_mode ( regs ))
- p = get_kprobe_by_insn_slot_arm (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
- else
- p = get_kprobe_by_insn_slot_thumb ((unsigned long)addr - 0x1a, pid, current);
-
+ p = get_kprobe_by_insn_slot(addr, tgid, regs);
if (!p) {
/* Not one of ours: let kernel handle it */
DBPRINTF ("no_kprobe");
}
retprobe = 1;
DBPRINTF ("uretprobe %p\n", addr);
- }
- else {
+ } else {
/* Not one of ours: let kernel handle it */
DBPRINTF ("no_kprobe");
goto no_kprobe;
}
}
// restore opcode for thumb app
- if (user_mode( regs ) && thumb_mode( regs ))
- {
- if (!isThumb2(p->opcode))
- {
+ if (user_mode( regs ) && thumb_mode( regs )) {
+ if (!isThumb2(p->opcode)) {
unsigned long tmp = p->opcode >> 16;
write_proc_vm_atomic(current, (unsigned long)((unsigned short*)p->addr + 1), &tmp, 2);
- }else{
+ } else {
unsigned long tmp = p->opcode;
write_proc_vm_atomic(current, (unsigned long)((unsigned short*)p->addr), &tmp, 4);
}
set_current_kprobe(p, regs, kcb);
if(!reenter)
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
- if (retprobe) //(einsn == UNDEF_INSTRUCTION)
+ if (retprobe) { //(einsn == UNDEF_INSTRUCTION)
ret = trampoline_probe_handler (p, regs);
- else if (p->pre_handler)
- {
+ } else if (p->pre_handler) {
ret = p->pre_handler (p, regs);
- if(!p->ainsn.boostable)
- kcb->kprobe_status = KPROBE_HIT_SS;
- else if(p->pre_handler != trampoline_probe_handler) {
-#ifdef SUPRESS_BUG_MESSAGES
- preempt_disable();
-#endif
+ if(p->pre_handler != trampoline_probe_handler) {
reset_current_kprobe(regs);
-#ifdef SUPRESS_BUG_MESSAGES
- preempt_enable_no_resched();
-#endif
}
}
- if (ret)
- {
- DBPRINTF ("p->pre_handler 1");
+
+ if (ret) {
/* handler has already set things up, so skip ss setup */
-#ifdef OVERHEAD_DEBUG
- do_gettimeofday(&swap_tv2);
- swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
- (swap_tv2.tv_usec - swap_tv1.tv_usec));
-#endif
-#ifdef SUPRESS_BUG_MESSAGES
- oops_in_progress = swap_oops_in_progress;
-#endif
- return 0;
+ err_out = 0;
+ goto out;
}
- DBPRINTF ("p->pre_handler 0");
no_kprobe:
- preempt_enable_no_resched ();
-#ifdef OVERHEAD_DEBUG
- do_gettimeofday(&swap_tv2);
- swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
- (swap_tv2.tv_usec - swap_tv1.tv_usec));
-#endif
-#ifdef SUPRESS_BUG_MESSAGES
- oops_in_progress = swap_oops_in_progress;
-#endif
- printk("no_kprobe\n");
- return 1; // return with death
+ msg_out = "no_kprobe\n";
+ err_out = 1; // return with death
+ goto out;
+
no_kprobe_live:
- preempt_enable_no_resched ();
+ msg_out = "no_kprobe live\n";
+ err_out = 0; // ok - life is life
+ goto out;
+
+out:
+ preempt_enable_no_resched();
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
#ifdef SUPRESS_BUG_MESSAGES
oops_in_progress = swap_oops_in_progress;
#endif
- printk("no_kprobe live\n");
- return 0; // ok - life is life
+
+ if(msg_out) {
+ printk(msg_out);
+ }
+
+ return err_out;
}
int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs)
void dbi_jprobe_return (void)
{
- preempt_enable_no_resched();
}
void dbi_arch_uprobe_return (void)
{
- preempt_enable_no_resched();
}
int longjmp_break_handler (struct kprobe *p, struct pt_regs *regs)
}
spin_unlock_irqrestore (&kretprobe_lock, flags);
- preempt_enable_no_resched ();
/*
* By returning a non-zero value, we are telling
* kprobe_handler() that we don't want the post_handler
kprobe_opcode_t *insn;
kprobe_opcode_t *insn_arm;
kprobe_opcode_t *insn_thumb;
- /*
- * If this flag is not 0, this kprobe can be boost when its
- * post_handler and break_handler is not set.
- */
- int boostable;
};
typedef kprobe_opcode_t (*entry_point_t) (unsigned long, unsigned long, unsigned long, unsigned long, unsigned long, unsigned long);
*/
void kretprobe_trampoline_holder (void)
{
- asm volatile (".global kretprobe_trampoline\n"
+ asm volatile (".global kretprobe_trampoline\n"
"kretprobe_trampoline:\n"
- "nop\n"
+ "nop\n"
"nop\n");
}
void gen_insn_execbuf_holder (void)
{
- asm volatile (".global gen_insn_execbuf\n"
- "gen_insn_execbuf:\n"
+ asm volatile (".global gen_insn_execbuf\n"
+ "gen_insn_execbuf:\n"
"nop\n" // original instruction
- "nop\n" //ssbreak
+ "nop\n" //ssbreak
"nop\n"); //retbreak
}
-
+
int arch_check_insn (struct arch_specific_insn *ainsn)
{
switch (MIPS_INSN_OPCODE (ainsn->insn[0]))
{
- case MIPS_BEQ_OPCODE: //B, BEQ
- case MIPS_BEQL_OPCODE: //BEQL
- case MIPS_BNE_OPCODE: //BNE
- case MIPS_BNEL_OPCODE: //BNEL
- case MIPS_BGTZ_OPCODE: //BGTZ
+ case MIPS_BEQ_OPCODE: //B, BEQ
+ case MIPS_BEQL_OPCODE: //BEQL
+ case MIPS_BNE_OPCODE: //BNE
+ case MIPS_BNEL_OPCODE: //BNEL
+ case MIPS_BGTZ_OPCODE: //BGTZ
case MIPS_BGTZL_OPCODE: //BGTZL
- case MIPS_BLEZ_OPCODE: //BLEZ
- case MIPS_BLEZL_OPCODE: //BLEZL
- case MIPS_J_OPCODE: //J
+ case MIPS_BLEZ_OPCODE: //BLEZ
+ case MIPS_BLEZL_OPCODE: //BLEZL
+ case MIPS_J_OPCODE: //J
case MIPS_JAL_OPCODE: //JAL
DBPRINTF ("arch_check_insn: opcode");
ret = -EFAULT;
insns[KPROBES_TRAMP_SS_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
insns[KPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION;
DBPRINTF ("arch_prepare_kprobe: insn %lx", insn[0]);
- DBPRINTF ("arch_prepare_kprobe: to %p - %lx %lx %lx",
+ DBPRINTF ("arch_prepare_kprobe: to %p - %lx %lx %lx",
p->ainsn.insn, insns[0], insns[1], insns[2]);
memcpy (p->ainsn.insn, insns, sizeof(insns));
}
else
{
- free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0);
+ free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
}
}
- return ret;
+ return ret;
}
int arch_prepare_uprobe (struct kprobe *p, struct task_struct *task, int atomic)
insns[UPROBES_TRAMP_SS_BREAK_IDX] = BREAKPOINT_INSTRUCTION;
insns[UPROBES_TRAMP_RET_BREAK_IDX] = UNDEF_INSTRUCTION;
DBPRINTF ("arch_prepare_uprobe: insn %lx", insn[0]);
- DBPRINTF ("arch_prepare_uprobe: to %p - %lx %lx %lx",
+ DBPRINTF ("arch_prepare_uprobe: to %p - %lx %lx %lx",
p->ainsn.insn, insns[0], insns[1], insns[2]);
if (!write_proc_vm_atomic (task, (unsigned long) p->ainsn.insn, insns, sizeof (insns)))
{
panic("failed to write memory %p!\n", p->ainsn.insn);
DBPRINTF ("failed to write insn slot to process memory: insn %p, addr %p, probe %p!", insn, p->ainsn.insn, p->addr);
- /*printk ("failed to write insn slot to process memory: %p/%d insn %lx, addr %p, probe %p!\n",
+ /*printk ("failed to write insn slot to process memory: %p/%d insn %lx, addr %p, probe %p!\n",
task, task->pid, insn, p->ainsn.insn, p->addr);*/
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn, 0);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn);
return -EINVAL;
}
}
if (kcb->prev_kprobe.kp != NULL)
{
panic ("no space to save new probe[]: task = %d/%s, prev %d/%p, current %d/%p, new %d/%p,",
- current->pid, current->comm, kcb->prev_kprobe.kp->tgid, kcb->prev_kprobe.kp->addr,
+ current->pid, current->comm, kcb->prev_kprobe.kp->tgid, kcb->prev_kprobe.kp->addr,
kprobe_running()->tgid, kprobe_running()->addr, cur_p->tgid, cur_p->addr);
}
if (kprobe_running ())
{
DBPRINTF ("lock???");
- p = get_kprobe (addr, pid, current);
+ p = get_kprobe(addr, pid);
if (p)
{
if(!pid && (addr == (kprobe_opcode_t *)kretprobe_trampoline)){
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
}
else
{
- if(pid) { //we can reenter probe upon uretprobe exception
+ if(pid) { //we can reenter probe upon uretprobe exception
DBPRINTF ("check for UNDEF_INSTRUCTION %p\n", addr);
// UNDEF_INSTRUCTION from user space
p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
/*if (p->break_handler && p->break_handler(p, regs)) {
DBPRINTF("kprobe_running !!! goto ss");
goto ss_probe;
- } */
+ } */
DBPRINTF ("unknown uprobe at %p cur at %p/%p\n", addr, p->addr, p->ainsn.insn);
if(pid)
ssaddr = p->ainsn.insn + UPROBES_TRAMP_SS_BREAK_IDX;
else
- ssaddr = p->ainsn.insn + KPROBES_TRAMP_SS_BREAK_IDX;
+ ssaddr = p->ainsn.insn + KPROBES_TRAMP_SS_BREAK_IDX;
if (addr == ssaddr)
{
regs->cp0_epc = (unsigned long) (p->addr + 1);
//if(einsn != UNDEF_INSTRUCTION) {
DBPRINTF ("get_kprobe %p-%d", addr, pid);
if (!p)
- p = get_kprobe (addr, pid, current);
+ p = get_kprobe(addr, pid);
if (!p)
{
if(pid) {
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
//call handler for all kernel probes and user space ones which belong to current tgid
if (!p->tgid || (p->tgid == current->tgid))
- {
+ {
if(!p->tgid && (p->addr == sched_addr) && sched_rp){
struct task_struct *p, *g;
rcu_read_lock();
// other tasks
do_each_thread(g, p){
if(p == current)
- continue;
+ continue;
patch_suspended_task_ret_addr(p, sched_rp);
} while_each_thread(g, p);
rcu_read_unlock();
prepare_singlestep (p, regs);
- return 1;
+ return 1;
}
return -1;
}
//*p->addr = BREAKPOINT_INSTRUCTION;
- //*(p->addr+1) = p->opcode;
+ //*(p->addr+1) = p->opcode;
if (write_proc_vm_atomic (current, (unsigned long) (p->addr), insns, sizeof (insns)) < sizeof (insns))
{
printk ("ERROR[]: failed to write vm of proc %s/%u addr %p.", current->comm, current->pid, p->addr);
int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs)
{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head, empty_rp;
- struct hlist_node *node, *tmp;
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long) &kretprobe_trampoline;
- struct kretprobe *crp = NULL;
+ struct kretprobe *crp = NULL;
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
DBPRINTF ("start");
if (p && p->tgid){
- // in case of user space retprobe trampoline is at the Nth instruction of US tramp
+ // in case of user space retprobe trampoline is at the Nth instruction of US tramp
trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
}
- INIT_HLIST_HEAD (&empty_rp);
- spin_lock_irqsave (&kretprobe_lock, flags);
+ INIT_HLIST_HEAD (&empty_rp);
+ spin_lock_irqsave (&kretprobe_lock, flags);
head = kretprobe_inst_table_head (current);
/*
* 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
+ * have a return probe installed on them, and/or more then one
* return probe was registered for a target function.
*
* We can handle this because:
{
if (ri->task != current)
/* another task is sharing our hash bucket */
- continue;
+ continue;
if (ri->rp && ri->rp->handler){
ri->rp->handler (ri, regs, ri->rp->priv_arg);
}
- orig_ret_address = (unsigned long) ri->ret_addr;
+ orig_ret_address = (unsigned long) ri->ret_addr;
recycle_rp_inst (ri);
if (orig_ret_address != trampoline_address)
/*
if (ri->rp) BUG_ON (ri->rp->kp.tgid == 0);
else if (ri->rp2) BUG_ON (ri->rp2->kp.tgid == 0);
}
- if ((ri->rp && ri->rp->kp.tgid) || (ri->rp2 && ri->rp2->kp.tgid))
+ if ((ri->rp && ri->rp->kp.tgid) || (ri->rp2 && ri->rp2->kp.tgid))
BUG_ON (trampoline_address == (unsigned long) &kretprobe_trampoline);
regs->regs[31] = orig_ret_address;
- DBPRINTF ("regs->cp0_epc = 0x%lx", regs->cp0_epc);
- if (trampoline_address != (unsigned long) &kretprobe_trampoline)
+ DBPRINTF ("regs->cp0_epc = 0x%lx", regs->cp0_epc);
+ if (trampoline_address != (unsigned long) &kretprobe_trampoline)
regs->cp0_epc = orig_ret_address;
else
- regs->cp0_epc = regs->cp0_epc + 4;
- DBPRINTF ("regs->cp0_epc = 0x%lx", regs->cp0_epc);
+ regs->cp0_epc = regs->cp0_epc + 4;
+ DBPRINTF ("regs->cp0_epc = 0x%lx", regs->cp0_epc);
DBPRINTF ("regs->cp0_status = 0x%lx", regs->cp0_status);
if(p){ // ARM, MIPS, X86 user space
else
reset_current_kprobe ();
- //TODO: test - enter function, delete us retprobe, exit function
+ //TODO: test - enter function, delete us retprobe, exit function
// for user space retprobes only - deferred deletion
if (trampoline_address != (unsigned long) &kretprobe_trampoline)
{
- // if we are not at the end of the list and current retprobe should be disarmed
+ // if we are not at the end of the list and current retprobe should be disarmed
if (node && ri->rp2)
{
crp = ri->rp2;
- /*sprintf(die_msg, "deferred disarm p->addr = %p [%lx %lx %lx]\n",
+ /*sprintf(die_msg, "deferred disarm p->addr = %p [%lx %lx %lx]\n",
crp->kp.addr, *kaddrs[0], *kaddrs[1], *kaddrs[2]);
DIE(die_msg, regs); */
// look for other instances for the same retprobe
hlist_for_each_entry_continue (ri, node, hlist)
{
- if (ri->task != current)
+ if (ri->task != current)
continue; /* another task is sharing our hash bucket */
if (ri->rp2 == crp) //if instance belong to the same retprobe
break;
}
}
- spin_unlock_irqrestore (&kretprobe_lock, flags);
+ spin_unlock_irqrestore (&kretprobe_lock, flags);
hlist_for_each_entry_safe (ri, node, tmp, &empty_rp, hlist)
{
- hlist_del (&ri->hlist);
+ hlist_del (&ri->hlist);
kfree (ri);
}
preempt_enable_no_resched ();
//TODO: test - remove retprobe after func entry but before its exit
if ((ri = get_free_rp_inst (rp)) != NULL)
{
- ri->rp = rp;
- ri->rp2 = NULL;
+ ri->rp = rp;
+ ri->rp2 = NULL;
ri->task = current;
ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
if (rp->kp.tgid)
int __init arch_init_kprobes (void)
{
- unsigned int do_bp_handler;
+ unsigned int do_bp_handler;
unsigned int kprobe_handler_addr;
unsigned int insns_num = 0;
unsigned int code_size = 0;
- unsigned int reg_hi;
+ unsigned int reg_hi;
unsigned int reg_lo;
int ret;
if (arch_init_module_dependencies())
{
- DBPRINTF ("Unable to init module dependencies\n");
+ DBPRINTF ("Unable to init module dependencies\n");
return -1;
}
kprobe_handler_addr = (unsigned int) &kprobe_handler;
insns_num = sizeof (arr_traps_template) / sizeof (arr_traps_template[0]);
- code_size = insns_num * sizeof (unsigned int);
+ code_size = insns_num * sizeof (unsigned int);
DBPRINTF ("insns_num = %d\n", insns_num);
// Save original code
arr_traps_original = kmalloc (code_size, GFP_KERNEL);
if (!arr_traps_original)
{
- DBPRINTF ("Unable to allocate space for original code of <do_bp>!\n");
+ DBPRINTF ("Unable to allocate space for original code of <do_bp>!\n");
return -1;
}
memcpy (arr_traps_original, (void *) do_bp_handler, code_size);
reg_hi = HIWORD (kprobe_handler_addr);
- reg_lo = LOWORD (kprobe_handler_addr);
- if (reg_lo >= 0x8000)
- reg_hi += 0x0001;
- arr_traps_template[REG_HI_INDEX] |= reg_hi;
+ reg_lo = LOWORD (kprobe_handler_addr);
+ if (reg_lo >= 0x8000)
+ reg_hi += 0x0001;
+ arr_traps_template[REG_HI_INDEX] |= reg_hi;
arr_traps_template[REG_LO_INDEX] |= reg_lo;
// Insert new code
- memcpy ((void *) do_bp_handler, arr_traps_template, code_size);
- flush_icache_range (do_bp_handler, do_bp_handler + code_size);
+ memcpy ((void *) do_bp_handler, arr_traps_template, code_size);
+ flush_icache_range (do_bp_handler, do_bp_handler + code_size);
if((ret = dbi_register_kprobe (&trampoline_p)) != 0){
//dbi_unregister_jprobe(&do_exit_p, 0);
return ret;
unsigned int insns_num = 0;
unsigned int code_size = 0;
- // Get instruction address
+ // Get instruction address
do_bp_handler = (unsigned int) kallsyms_search ("do_undefinstr");
//dbi_unregister_jprobe(&do_exit_p, 0);
// Replace back the original code
insns_num = sizeof (arr_traps_template) / sizeof (arr_traps_template[0]);
- code_size = insns_num * sizeof (unsigned int);
- memcpy ((void *) do_bp_handler, arr_traps_original, code_size);
- flush_icache_range (do_bp_handler, do_bp_handler + code_size);
- kfree (arr_traps_original);
+ code_size = insns_num * sizeof (unsigned int);
+ memcpy ((void *) do_bp_handler, arr_traps_original, code_size);
+ flush_icache_range (do_bp_handler, do_bp_handler + code_size);
+ kfree (arr_traps_original);
arr_traps_original = NULL;
}
*
* 2008-2009 Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
* Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces.
- * 2010 Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- * 2012 Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
+ * 2010 Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
+ * 2012 Stanislav Andreev <s.andreev@samsung.com>: added time debug profiling support; BUG() message fix
*/
#include<linux/module.h>
*/
void kretprobe_trampoline_holder (void)
{
- asm volatile (".global kretprobe_trampoline\n"
+ asm volatile (".global kretprobe_trampoline\n"
"kretprobe_trampoline:\n"
" pushf\n"
/* skip cs, eip, orig_eax */
jop.raddr = (long) (to) - ((long) (from) + 5);
jop.op = RELATIVEJUMP_INSTRUCTION;
if (!write_proc_vm_atomic (current, (unsigned long)from, &jop, sizeof(jop)))
- panic ("failed to write jump opcode to user space %p!\n", from);
+ panic ("failed to write jump opcode to user space %p!\n", from);
}
/*
}
else
{
- free_insn_slot (&kprobe_insn_pages, NULL, p->ainsn.insn, 0);
+ free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
}
return ret;
{
panic("failed to write memory %p!\n", p->ainsn.insn);
DBPRINTF ("failed to write insn slot to process memory: insn %p, addr %p, probe %p!", insn, p->ainsn.insn, p->addr);
- free_insn_slot (&uprobe_insn_pages, task, p->ainsn.insn, 0);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn);
return -EINVAL;
}
}
}
else
regs->EREG (ip) = (unsigned long) p->ainsn.insn;
- }
+ }
}
if (kcb->prev_kprobe.kp != NULL)
{
panic ("no space to save new probe[]: task = %d/%s, prev %d/%p, current %d/%p, new %d/%p,",
- current->pid, current->comm, kcb->prev_kprobe.kp->tgid, kcb->prev_kprobe.kp->addr,
+ current->pid, current->comm, kcb->prev_kprobe.kp->tgid, kcb->prev_kprobe.kp->addr,
kprobe_running()->tgid, kprobe_running()->addr, cur_p->tgid, cur_p->addr);
}
struct kprobe *p = 0;
int ret = 0, pid = 0, retprobe = 0, reenter = 0;
kprobe_opcode_t *addr = NULL;
- struct kprobe_ctlblk *kcb;
+ struct kprobe_ctlblk *kcb;
#ifdef OVERHEAD_DEBUG
struct timeval swap_tv1;
struct timeval swap_tv2;
if (kprobe_running ())
{
DBPRINTF ("lock???");
- p = get_kprobe (addr, pid, current);
+ p = get_kprobe(addr, pid);
if (p)
{
DBPRINTF ("reenter p = %p", p);
}
}
else {
- //#warning BREAKPOINT_INSTRUCTION user mode handling is missed!!!
+ //#warning BREAKPOINT_INSTRUCTION user mode handling is missed!!!
}
/* We have reentered the kprobe_handler(), since
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
}
}
else {
- //#warning BREAKPOINT_INSTRUCTION user mode handling is missed!!!
- //we can reenter probe upon uretprobe exception
+ //#warning BREAKPOINT_INSTRUCTION user mode handling is missed!!!
+ //we can reenter probe upon uretprobe exception
DBPRINTF ("check for UNDEF_INSTRUCTION %p\n", addr);
// UNDEF_INSTRUCTION from user space
p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
DBPRINTF ("get_kprobe %p", addr);
if (!p)
- p = get_kprobe (addr, pid, current);
+ p = get_kprobe(addr, pid);
if (!p)
{
if(!pid){
}
}
else {
- //#warning BREAKPOINT_INSTRUCTION user mode handling is missed!!!
+ //#warning BREAKPOINT_INSTRUCTION user mode handling is missed!!!
DBPRINTF ("search UNDEF_INSTRUCTION %p\n", addr);
// UNDEF_INSTRUCTION from user space
p = get_kprobe_by_insn_slot (addr-UPROBES_TRAMP_RET_BREAK_IDX, pid, current);
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
#ifdef OVERHEAD_DEBUG
do_gettimeofday(&swap_tv2);
swap_sum_hit++;
- swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
+ swap_sum_time += ((swap_tv2.tv_sec - swap_tv1.tv_sec) * USEC_IN_SEC_NUM +
(swap_tv2.tv_usec - swap_tv1.tv_usec));
#endif
#ifdef SUPRESS_BUG_MESSAGES
return ret;
}
-int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs)
+int setjmp_pre_handler (struct kprobe *p, struct pt_regs *regs)
{
struct jprobe *jp = container_of (p, struct jprobe, kp);
kprobe_pre_entry_handler_t pre_entry;
kprobe_pre_entry_handler_t pre_entry;
entry_point_t entry;
- unsigned long addr, args[6];
+ unsigned long addr, args[6];
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
DBPRINTF ("setjmp_pre_handler %p:%d", p->addr, p->tgid);
/*
* These instructions can be executed directly if it
* jumps back to correct address.
- */
+ */
if(p->tgid)
- set_user_jmp_op ((void *) regs->EREG (ip), (void *) orig_eip + (regs->EREG (ip) - copy_eip));
+ set_user_jmp_op ((void *) regs->EREG (ip), (void *) orig_eip + (regs->EREG (ip) - copy_eip));
else
set_jmp_op ((void *) regs->EREG (ip), (void *) orig_eip + (regs->EREG (ip) - copy_eip));
p->ainsn.boostable = 1;
printk ("Current registers\n");
show_registers (regs);
panic("BUG");
- //BUG ();
+ //BUG ();
}
*regs = kcb->jprobe_saved_regs;
memcpy ((kprobe_opcode_t *) stack_addr, kcb->jprobes_stack, MIN_STACK_SIZE (stack_addr));
*/
int trampoline_probe_handler (struct kprobe *p, struct pt_regs *regs)
{
- struct kretprobe_instance *ri = NULL;
- struct hlist_head *head, empty_rp;
- struct hlist_node *node, *tmp;
+ struct kretprobe_instance *ri = NULL;
+ struct hlist_head *head, empty_rp;
+ struct hlist_node *node, *tmp;
unsigned long flags, orig_ret_address = 0;
unsigned long trampoline_address = (unsigned long) &kretprobe_trampoline;
- struct kretprobe *crp = NULL;
+ struct kretprobe *crp = NULL;
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk ();
DBPRINTF ("start");
if (p && p->tgid){
- // in case of user space retprobe trampoline is at the Nth instruction of US tramp
+ // in case of user space retprobe trampoline is at the Nth instruction of US tramp
trampoline_address = (unsigned long)(p->ainsn.insn + UPROBES_TRAMP_RET_BREAK_IDX);
}
- INIT_HLIST_HEAD (&empty_rp);
- spin_lock_irqsave (&kretprobe_lock, flags);
+ INIT_HLIST_HEAD (&empty_rp);
+ spin_lock_irqsave (&kretprobe_lock, flags);
/*
* We are using different hash keys (current and mm) for finding kernel
* space and user space probes. Kernel space probes can change mm field in
if(!p){ // X86 kernel space
DBPRINTF ("regs %p", regs);
/* fixup registers */
- regs->XREG (cs) = __KERNEL_CS | get_kernel_rpl ();
- regs->EREG (ip) = trampoline_address;
+ regs->XREG (cs) = __KERNEL_CS | get_kernel_rpl ();
+ regs->EREG (ip) = trampoline_address;
regs->ORIG_EAX_REG = 0xffffffff;
}
/*
* 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
+ * have a return probe installed on them, and/or more then one
* return probe was registered for a target function.
*
* We can handle this because:
{
if (ri->task != current)
/* another task is sharing our hash bucket */
- continue;
+ continue;
if (ri->rp && ri->rp->handler){
if(!p){ // X86 kernel space
- __get_cpu_var (current_kprobe) = &ri->rp->kp;
+ __get_cpu_var (current_kprobe) = &ri->rp->kp;
get_kprobe_ctlblk ()->kprobe_status = KPROBE_HIT_ACTIVE;
}
}
- orig_ret_address = (unsigned long) ri->ret_addr;
+ orig_ret_address = (unsigned long) ri->ret_addr;
recycle_rp_inst (ri);
if (orig_ret_address != trampoline_address)
/*
if (ri->rp) BUG_ON (ri->rp->kp.tgid == 0);
else if (ri->rp2) BUG_ON (ri->rp2->kp.tgid == 0);
}
- if ((ri->rp && ri->rp->kp.tgid) || (ri->rp2 && ri->rp2->kp.tgid))
+ if ((ri->rp && ri->rp->kp.tgid) || (ri->rp2 && ri->rp2->kp.tgid))
BUG_ON (trampoline_address == (unsigned long) &kretprobe_trampoline);
if(p){ // X86 user space
- regs->EREG(ip) = orig_ret_address;
+ regs->EREG(ip) = orig_ret_address;
//printk (" uretprobe regs->eip = 0x%lx\n", regs->EREG(ip));
}
else
reset_current_kprobe ();
- //TODO: test - enter function, delete us retprobe, exit function
+ //TODO: test - enter function, delete us retprobe, exit function
// for user space retprobes only - deferred deletion
if (trampoline_address != (unsigned long) &kretprobe_trampoline)
{
- // if we are not at the end of the list and current retprobe should be disarmed
+ // if we are not at the end of the list and current retprobe should be disarmed
if (node && ri->rp2)
{
struct hlist_node *current_node = node;
crp = ri->rp2;
- /*sprintf(die_msg, "deferred disarm p->addr = %p [%lx %lx %lx]\n",
+ /*sprintf(die_msg, "deferred disarm p->addr = %p [%lx %lx %lx]\n",
crp->kp.addr, *kaddrs[0], *kaddrs[1], *kaddrs[2]);
DIE(die_msg, regs); */
// look for other instances for the same retprobe
hlist_for_each_entry_safe (ri, node, tmp, &empty_rp, hlist)
{
- hlist_del (&ri->hlist);
+ hlist_del (&ri->hlist);
kfree (ri);
}
spin_unlock_irqrestore (&kretprobe_lock, flags);
//TODO: test - remove retprobe after func entry but before its exit
if ((ri = get_free_rp_inst (rp)) != NULL)
{
- ri->rp = rp;
- ri->rp2 = NULL;
+ ri->rp = rp;
+ ri->rp2 = NULL;
ri->task = current;
/* Replace the return addr with trampoline addr */
{
if (arch_init_module_dependencies())
{
- DBPRINTF ("Unable to init module dependencies\n");
+ DBPRINTF ("Unable to init module dependencies\n");
return -1;
}
void arch_remove_kprobe (struct kprobe *p, struct task_struct *task)
{
+ // TODO: check boostable for x86 and MIPS
if (p->tgid) {
#ifdef CONFIG_ARM
- free_insn_slot (&uprobe_insn_pages, task, \
- p->ainsn.insn_arm, (p->ainsn.boostable == 1));
- free_insn_slot (&uprobe_insn_pages, task, \
- p->ainsn.insn_thumb, (p->ainsn.boostable == 1));
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_arm);
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn_thumb);
#else /* CONFIG_ARM */
- free_insn_slot (&uprobe_insn_pages, task, \
- p->ainsn.insn, (p->ainsn.boostable == 1));
+ free_insn_slot(&uprobe_insn_pages, task, p->ainsn.insn);
#endif /* CONFIG_ARM */
} else {
- free_insn_slot (&kprobe_insn_pages, NULL, \
- p->ainsn.insn, (p->ainsn.boostable == 1));
+ free_insn_slot(&kprobe_insn_pages, NULL, p->ainsn.insn);
}
}
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
- * Copyright (C) Samsung Electronics, 2006-2010
+ * Copyright (C) Samsung Electronics, 2006-2012
*
* 2008-2009 Alexey Gerenkov <a.gerenkov@samsung.com> User-Space
* Probes initial implementation; Support x86/ARM/MIPS for both user and kernel spaces.
* 2010 Ekaterina Gorelkina <e.gorelkina@samsung.com>: redesign module for separating core and arch parts
- *
+ * 2012 Vyacheslav Cherkashin <v.cherkashin@samsung.com> new memory allocator for slots
*/
#include "dbi_insn_slots.h"
INIT_HLIST_NODE (&kip->hlist);
hlist_add_head_rcu(&kip->hlist, page_list);
+
return chunk_allocate(&kip->chunk, slot_size(task));
}
-void free_insn_slot(struct hlist_head *page_list, struct task_struct *task, kprobe_opcode_t *slot, int dirty)
+void free_insn_slot(struct hlist_head *page_list, struct task_struct *task, kprobe_opcode_t *slot)
{
struct kprobe_insn_page *kip;
struct hlist_node *pos;
- hlist_for_each_entry_rcu(kip, pos, page_list, hlist)
- {
+ hlist_for_each_entry_rcu(kip, pos, page_list, hlist) {
if (!(!task || (kip->task->tgid == task->tgid)))
continue;
}
#ifdef CONFIG_ARM
-struct kprobe *get_kprobe_by_insn_slot_arm (void *addr, int tgid, struct task_struct *ctask)
+static struct kprobe *get_kprobe_by_insn_slot_arm(kprobe_opcode_t *addr, pid_t tgid)
{
struct hlist_head *head;
struct hlist_node *node;
struct kprobe *p, *retVal = NULL;
- int uprobe_found;
//TODO: test - two processes invokes instrumented function
head = &uprobe_insn_slot_table[hash_ptr (addr, KPROBE_HASH_BITS)];
- hlist_for_each_entry_rcu (p, node, head, is_hlist_arm)
- {
- //if looking for kernel probe and this is kernel probe with the same addr OR
- //if looking for the user space probe and this is user space probe probe with the same addr and pid
- DBPRINTF ("get_kprobe: check probe at %p/%p, task %d/%d", addr, p->ainsn.insn, tgid, p->tgid);
- if (p->ainsn.insn == addr)
- {
- uprobe_found = 0;
- if (tgid == p->tgid)
- uprobe_found = 1;
- if (!tgid || uprobe_found)
- {
- retVal = p;
- if (tgid)
- DBPRINTF ("get_kprobe: found user space probe at %p for task %d", p->addr, p->tgid);
- else
- DBPRINTF ("get_kprobe: found kernel probe at %p", p->addr);
- break;
- }
+ hlist_for_each_entry_rcu (p, node, head, is_hlist_arm) {
+ if (p->ainsn.insn == addr && tgid == p->tgid) {
+ retVal = p;
+ break;
}
}
return retVal;
}
-struct kprobe *get_kprobe_by_insn_slot_thumb (void *addr, int tgid, struct task_struct *ctask)
+static struct kprobe *get_kprobe_by_insn_slot_thumb(kprobe_opcode_t *addr, pid_t tgid)
{
struct hlist_head *head;
struct hlist_node *node;
struct kprobe *p, *retVal = NULL;
- int uprobe_found;
//TODO: test - two processes invokes instrumented function
head = &uprobe_insn_slot_table[hash_ptr (addr, KPROBE_HASH_BITS)];
- hlist_for_each_entry_rcu (p, node, head, is_hlist_thumb)
- {
- //if looking for kernel probe and this is kernel probe with the same addr OR
- //if looking for the user space probe and this is user space probe probe with the same addr and pid
- /* printk("get_kprobe: check probe at %p/%p, task %d/%d\n", addr, p->ainsn.insn, tgid, p->tgid); */
- if (p->ainsn.insn == addr)
- {
- uprobe_found = 0;
- if (tgid == p->tgid)
- uprobe_found = 1;
- if (!tgid || uprobe_found)
- {
- retVal = p;
- if (tgid)
- DBPRINTF ("get_kprobe: found user space probe at %p for task %d", p->addr, p->tgid);
- else
- DBPRINTF ("get_kprobe: found kernel probe at %p", p->addr);
- break;
- }
+ hlist_for_each_entry_rcu (p, node, head, is_hlist_thumb) {
+ if (p->ainsn.insn == addr && tgid == p->tgid) {
+ retVal = p;
+ break;
}
}
DBPRINTF ("get_kprobe: probe %p", retVal);
return retVal;
}
+
+struct kprobe *get_kprobe_by_insn_slot(kprobe_opcode_t *addr, pid_t tgid, struct pt_regs *regs)
+{
+ struct kprobe *p = NULL;
+
+ if (!thumb_mode(regs)) {
+ p = get_kprobe_by_insn_slot_arm(addr - UPROBES_TRAMP_RET_BREAK_IDX, tgid);
+ } else {
+ p = get_kprobe_by_insn_slot_thumb((kprobe_opcode_t *)((unsigned long)addr - 0x1a), tgid);
+ }
+
+ return p;
+}
#else /* CONFIG_ARM */
struct kprobe *get_kprobe_by_insn_slot (void *addr, int tgid, struct task_struct *ctask)
{
struct hlist_head *head;
struct hlist_node *node;
struct kprobe *p, *retVal = NULL;
- int uprobe_found;
//TODO: test - two processes invokes instrumented function
head = &uprobe_insn_slot_table[hash_ptr (addr, KPROBE_HASH_BITS)];
- hlist_for_each_entry_rcu (p, node, head, is_hlist)
- {
- //if looking for kernel probe and this is kernel probe with the same addr OR
- //if looking for the user space probe and this is user space probe probe with the same addr and pid
- /* printk("get_kprobe: check probe at %p/%p, task %d/%d\n", addr, p->ainsn.insn, tgid, p->tgid); */
- if (p->ainsn.insn == addr)
- {
- uprobe_found = 0;
- if (tgid == p->tgid)
- uprobe_found = 1;
- if (!tgid || uprobe_found)
- {
- retVal = p;
- if (tgid)
- DBPRINTF ("get_kprobe: found user space probe at %p for task %d", p->addr, p->tgid);
- else
- DBPRINTF ("get_kprobe: found kernel probe at %p", p->addr);
- break;
- }
+ hlist_for_each_entry_rcu (p, node, head, is_hlist) {
+ if (p->ainsn.insn == addr && tgid == p->tgid) {
+ retVal = p;
+ break;
}
}
kprobe_opcode_t *get_insn_slot(struct task_struct *task, int atomic);
-void free_insn_slot(struct hlist_head *page_list, struct task_struct *task, kprobe_opcode_t *slot, int dirty);
+void free_insn_slot(struct hlist_head *page_list, struct task_struct *task, kprobe_opcode_t *slot);
#endif /* _SRC_INSNS_SLOTS_H */
* OR
* - with preemption disabled - from arch/xxx/kernel/kprobes.c
*/
-struct kprobe *get_kprobe (void *addr, int tgid, struct task_struct *ctask)
+struct kprobe *get_kprobe(kprobe_opcode_t *addr, pid_t tgid)
{
struct hlist_head *head;
struct hlist_node *node;
struct kprobe *p, *retVal = NULL;
- int ret = 0, uprobe_found;
- struct page *page = 0, *tpage = 0;
- struct vm_area_struct *vma = 0;
- struct task_struct *task = 0;
- void *paddr = 0;
head = &kprobe_table[hash_ptr (addr, KPROBE_HASH_BITS)];
- hlist_for_each_entry_rcu (p, node, head, hlist)
- {
- //if looking for kernel probe and this is kernel probe with the same addr OR
- //if looking for the user space probe and this is user space probe probe with the same addr and pid
- DBPRINTF ("get_kprobe: check probe at %p/%p, task %d/%d", addr, p->addr, tgid, p->tgid);
- if (p->addr == addr)
- {
- uprobe_found = 0;
- if (tgid == p->tgid)
- uprobe_found = 1;
- if (!tgid || uprobe_found)
- {
- retVal = p;
- if (tgid)
- DBPRINTF ("get_kprobe: found user space probe at %p for task %d", p->addr, p->tgid);
- else
- DBPRINTF ("get_kprobe: found kernel probe at %p", p->addr);
- break;
- }
+ hlist_for_each_entry_rcu(p, node, head, hlist) {
+ if (p->addr == addr && p->tgid == tgid) {
+ retVal = p;
+ break;
}
}
+
DBPRINTF ("get_kprobe: probe %p", retVal);
return retVal;
}
p->mod_refcounted = 0;
p->nmissed = 0;
- old_p = get_kprobe (p->addr, 0, NULL);
+ old_p = get_kprobe(p->addr, 0);
if (old_p)
{
ret = register_aggr_kprobe (old_p, p);
struct kprobe *old_p, *list_p;
int cleanup_p, pid = p->tgid;
- old_p = get_kprobe (p->addr, pid, NULL);
+ old_p = get_kprobe(p->addr, pid);
DBPRINTF ("dbi_unregister_kprobe p=%p old_p=%p", p, old_p);
if (unlikely (!old_p))
return;
clone->kp.post_handler = NULL;
clone->kp.fault_handler = NULL;
clone->kp.break_handler = NULL;
- old_p = get_kprobe (rp->kp.addr, rp->kp.tgid, NULL);
+ old_p = get_kprobe(rp->kp.addr, rp->kp.tgid);
if (old_p)
{
ret = register_aggr_kprobe (old_p, &clone->kp);
/* Get the kprobe at this addr (if any) - called with preemption disabled */
-struct kprobe *get_kprobe (void *addr, int pid, struct task_struct *ctask);
+struct kprobe *get_kprobe(kprobe_opcode_t *addr, pid_t tgid);
#ifdef CONFIG_ARM
-struct kprobe *get_kprobe_by_insn_slot_arm(void *addr, int tgid, struct task_struct *ctask);
-struct kprobe *get_kprobe_by_insn_slot_thumb(void *addr, int tgid, struct task_struct *ctask);
+struct kprobe *get_kprobe_by_insn_slot(kprobe_opcode_t *addr, pid_t tgid, struct pt_regs *regs);
#else /* CONFIG_ARM */
struct kprobe *get_kprobe_by_insn_slot (void *addr, int tgid, struct task_struct *ctask);
#endif /* CONFIG_ARM */
#endif
// get the first item
- old_p = get_kprobe (p->addr, p->tgid, NULL);
+ old_p = get_kprobe(p->addr, p->tgid);
if (old_p)
{
#ifdef CONFIG_ARM