return 0;
}
-static int fbi_probe_handler(struct kprobe *p, struct pt_regs *regs)
+static int fbi_probe_handler(struct uprobe *p, struct pt_regs *regs)
{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct us_ip *ip = container_of(up, struct us_ip, uprobe);
+ struct us_ip *ip = container_of(p, struct us_ip, uprobe);
struct fbi_info *fbi_i = &ip->info->fbi_i;
struct fbi_var_data *fbi_d = NULL;
uint8_t i;
void fbi_probe_init(struct us_ip *ip)
{
- ip->uprobe.kp.pre_handler = (kprobe_pre_handler_t)fbi_probe_handler;
+ ip->uprobe.pre_handler = (uprobe_pre_handler_t)fbi_probe_handler;
}
void fbi_probe_uninit(struct us_ip *ip)
static struct probe_info_new pin_main = MAKE_URPROBE(main_eh, main_rh, 0);
/* appcore_efl_main */
-static int ac_efl_main_h(struct kprobe *p, struct pt_regs *regs);
+static int ac_efl_main_h(struct uprobe *p, struct pt_regs *regs);
static struct probe_info_new pin_ac_efl_main = MAKE_UPROBE(ac_efl_main_h);
static struct probe_new p_ac_efl_main = {
.info = &pin_ac_efl_main
};
/* elm_run@plt */
-static int elm_run_h(struct kprobe *p, struct pt_regs *regs);
+static int elm_run_h(struct uprobe *p, struct pt_regs *regs);
static struct probe_info_new pin_elm_run = MAKE_UPROBE(elm_run_h);
static struct probe_new p_elm_run = {
.info = &pin_elm_run
}
}
-static int main_h(struct kprobe *p, struct pt_regs *regs)
+static int main_h(struct uprobe *p, struct pt_regs *regs)
{
struct tdata *tdata;
u64 time_start;
struct uretprobe *rp = ri->rp;
if (rp) {
- main_h(&rp->up.kp, regs);
+ main_h(&rp->up, regs);
if (get_quiet() == QT_OFF) {
struct us_ip *ip;
return 0;
}
-static int ac_efl_main_h(struct kprobe *p, struct pt_regs *regs)
+static int ac_efl_main_h(struct uprobe *p, struct pt_regs *regs)
{
stage_end(NPS_MAIN_E, NPS_AC_EFL_MAIN_E, NMS_MAIN);
return 0;
return 0;
}
-static int elm_run_h(struct kprobe *p, struct pt_regs *regs)
+static int elm_run_h(struct uprobe *p, struct pt_regs *regs)
{
stage_end(NPS_AC_INIT_R, NPS_ELM_RUN_E, NMS_CREATE);
return 0;
struct pt_regs *regs,
unsigned long vaddr)
{
- ri->rp->up.kp.ss_addr[smp_processor_id()] = (kprobe_opcode_t *)vaddr;
+ ri->rp->up.ss_addr[smp_processor_id()] = (kprobe_opcode_t *)vaddr;
#ifdef CONFIG_ARM
if (thumb_mode(regs)) {
"sp(%08lx), lr(%08lx), pc(%08lx)\n",
current->comm, current->tgid, current->pid,
(int)preload_pd_get_state(__get_process_data(ri->rp)),
- prefix, (unsigned long)ri->rp->up.kp.addr,
+ prefix, (unsigned long)ri->rp->up.addr,
regs->ARM_r0, regs->ARM_r1, regs->ARM_r2, regs->ARM_r3,
regs->ARM_r4, regs->ARM_r5, regs->ARM_r6, regs->ARM_r7,
regs->ARM_sp, regs->ARM_lr, regs->ARM_pc);
"ip(%08lx), arg0(%08lx), arg1(%08lx), raddr(%08lx)\n",
current->comm, current->tgid, current->pid,
(int)preload_pd_get_state(__get_process_data(ri->rp)),
- prefix, (unsigned long)ri->rp->up.kp.addr,
+ prefix, (unsigned long)ri->rp->up.addr,
regs->EREG(ip), swap_get_arg(regs, 0), swap_get_arg(regs, 1),
swap_get_ret_addr(regs));
#endif /* CONFIG_ARM */
-static int get_caller_handler(struct kprobe *p, struct pt_regs *regs)
+static int get_caller_handler(struct uprobe *p, struct pt_regs *regs)
{
unsigned long caller;
int ret;
return 0;
}
-static int get_call_type_handler(struct kprobe *p, struct pt_regs *regs)
+static int get_call_type_handler(struct uprobe *p, struct pt_regs *regs)
{
unsigned char call_type;
int ret;
return 0;
}
-static int write_msg_handler(struct kprobe *p, struct pt_regs *regs)
+static int write_msg_handler(struct uprobe *p, struct pt_regs *regs)
{
char *user_buf;
char *buf;
{
struct uprobe *up = &ip->uprobe;
- up->kp.pre_handler = get_caller_handler;
+ up->pre_handler = get_caller_handler;
return 0;
}
{
struct uprobe *up = &ip->uprobe;
- up->kp.pre_handler = get_call_type_handler;
+ up->pre_handler = get_call_type_handler;
return 0;
}
{
struct uprobe *up = &ip->uprobe;
- up->kp.pre_handler = write_msg_handler;
+ up->pre_handler = write_msg_handler;
return 0;
}
(insn & 0xf800) == 0xf800);
}
-static int arch_copy_trampoline_arm_uprobe(struct uprobe *up)
+static int arch_copy_trampoline_arm_uprobe(struct uprobe *p)
{
int ret;
- struct kprobe *p = up2kp(up);
unsigned long insn = p->opcode;
unsigned long vaddr = (unsigned long)p->addr;
- unsigned long *tramp = up->atramp.tramp_arm;
+ unsigned long *tramp = p->atramp.tramp_arm;
ret = arch_make_trampoline_arm(vaddr, insn, tramp);
p->safe_arm = !!ret;
return 0;
}
-static int arch_copy_trampoline_thumb_uprobe(struct uprobe *up)
+static int arch_copy_trampoline_thumb_uprobe(struct uprobe *p)
{
int uregs, pc_dep;
- struct kprobe *p = up2kp(up);
unsigned int addr;
unsigned long vaddr = (unsigned long)p->addr;
unsigned long insn = p->opcode;
- unsigned long *tramp = up->atramp.tramp_thumb;
- enum { tramp_len = sizeof(up->atramp.tramp_thumb) };
+ unsigned long *tramp = p->atramp.tramp_thumb;
+ enum { tramp_len = sizeof(p->atramp.tramp_thumb) };
p->safe_thumb = 1;
if (vaddr & 0x01) {
printk(KERN_INFO "Error in %s at %d: attempt to register "
- "kprobe at an unaligned address\n", __FILE__, __LINE__);
+ "uprobe at an unaligned address\n", __FILE__, __LINE__);
return -EINVAL;
}
* @return 0 on success,\n
* negative error code on error.
*/
-int arch_prepare_uprobe(struct uprobe *up)
+int arch_prepare_uprobe(struct uprobe *p)
{
- struct kprobe *p = up2kp(up);
- struct task_struct *task = up->task;
+ struct task_struct *task = p->task;
unsigned long vaddr = (unsigned long)p->addr;
unsigned long insn;
p->opcode = insn;
- arch_copy_trampoline_arm_uprobe(up);
- arch_copy_trampoline_thumb_uprobe(up);
+ arch_copy_trampoline_arm_uprobe(p);
+ arch_copy_trampoline_thumb_uprobe(p);
if ((p->safe_arm) && (p->safe_thumb)) {
printk(KERN_INFO "Error in %s at %d: failed "
return -EFAULT;
}
- up->atramp.utramp = swap_slot_alloc(up->sm);
- if (up->atramp.utramp == NULL) {
+ p->atramp.utramp = swap_slot_alloc(p->sm);
+ if (p->atramp.utramp == NULL) {
printk(KERN_INFO "Error: swap_slot_alloc failed (%08lx)\n",
vaddr);
return -ENOMEM;
void arch_opcode_analysis_uretprobe(struct uretprobe *rp)
{
/* Remove retprobe if first insn overwrites lr */
- rp->thumb_noret = !!(THUMB2_INSN_MATCH(BL, rp->up.kp.opcode) ||
- THUMB2_INSN_MATCH(BLX1, rp->up.kp.opcode) ||
- THUMB_INSN_MATCH(BLX2, rp->up.kp.opcode));
+ rp->thumb_noret = !!(THUMB2_INSN_MATCH(BL, rp->up.opcode) ||
+ THUMB2_INSN_MATCH(BLX1, rp->up.opcode) ||
+ THUMB_INSN_MATCH(BLX2, rp->up.opcode));
- rp->arm_noret = !!(ARM_INSN_MATCH(BL, rp->up.kp.opcode) ||
- ARM_INSN_MATCH(BLX1, rp->up.kp.opcode) ||
- ARM_INSN_MATCH(BLX2, rp->up.kp.opcode));
+ rp->arm_noret = !!(ARM_INSN_MATCH(BL, rp->up.opcode) ||
+ ARM_INSN_MATCH(BLX1, rp->up.opcode) ||
+ ARM_INSN_MATCH(BLX2, rp->up.opcode));
}
/**
ri->sp = (kprobe_opcode_t *)((long)ri->sp | !!thumb_mode(regs));
if (ri->preload_thumb) {
- regs->ARM_lr = (unsigned long)(ri->rp->up.kp.ainsn.insn) + 0x1b;
+ regs->ARM_lr = (unsigned long)(ri->rp->up.ainsn.insn) + 0x1b;
} else {
if (thumb_mode(regs))
- regs->ARM_lr = (unsigned long)(ri->rp->up.kp.ainsn.insn) + 0x1b;
+ regs->ARM_lr = (unsigned long)(ri->rp->up.ainsn.insn) + 0x1b;
else
- regs->ARM_lr = (unsigned long)(ri->rp->up.kp.ainsn.insn +
+ regs->ARM_lr = (unsigned long)(ri->rp->up.ainsn.insn +
UPROBES_TRAMP_RET_BREAK_IDX);
}
/* Understand function mode */
if ((long)ri->sp & 1) {
tramp = (unsigned long *)
- ((unsigned long)ri->rp->up.kp.ainsn.insn + 0x1b);
+ ((unsigned long)ri->rp->up.ainsn.insn + 0x1b);
} else {
- tramp = (unsigned long *)(ri->rp->up.kp.ainsn.insn +
+ tramp = (unsigned long *)(ri->rp->up.ainsn.insn +
UPROBES_TRAMP_RET_BREAK_IDX);
}
"%08lx (%08lx /%+d) - %p\n",
task->comm, task->tgid, task->pid,
(unsigned long)found, (unsigned long)sp,
- found - sp, ri->rp->up.kp.addr);
+ found - sp, ri->rp->up.addr);
retval = write_proc_vm_atomic(task, (unsigned long)found,
&ri->ret_addr,
sizeof(ri->ret_addr));
printk(KERN_INFO "---> %s (%d/%d): trampoline found at "
"lr = %08lx - %p\n",
task->comm, task->tgid, task->pid,
- ra, ri->rp->up.kp.addr);
+ ra, ri->rp->up.addr);
swap_set_ret_addr(uregs, (unsigned long)ri->ret_addr);
retval = 0;
} else if (retval) {
printk(KERN_INFO "---> %s (%d/%d): trampoline NOT found at "
"sp = %08lx, lr = %08lx - %p\n",
task->comm, task->tgid, task->pid,
- (unsigned long)sp, ra, ri->rp->up.kp.addr);
+ (unsigned long)sp, ra, ri->rp->up.addr);
}
return retval;
/**
* @brief Jump pre-handler.
*
- * @param p Pointer to the kprobe.
+ * @param p Pointer to the uprobe.
* @param regs Pointer to CPU register data.
* @return 0.
*/
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct ujprobe *jp = container_of(up, struct ujprobe, up);
+ struct ujprobe *jp = container_of(p, struct ujprobe, up);
- kprobe_pre_entry_handler_t pre_entry =
- (kprobe_pre_entry_handler_t)jp->pre_entry;
+ uprobe_pre_entry_handler_t pre_entry =
+ (uprobe_pre_entry_handler_t)jp->pre_entry;
entry_point_t entry = (entry_point_t)jp->entry;
if (pre_entry) {
/**
* @brief Gets trampoline address.
*
- * @param p Pointer to the kprobe.
+ * @param p Pointer to the uprobe.
* @param regs Pointer to CPU register data.
* @return Trampoline address.
*/
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
{
return thumb_mode(regs) ?
(unsigned long)(p->ainsn.insn) + 0x1b :
swap_slot_free(up->sm, up->atramp.utramp);
}
-static void restore_opcode_for_thumb(struct kprobe *p, struct pt_regs *regs)
+static void restore_opcode_for_thumb(struct uprobe *p, struct pt_regs *regs)
{
if (thumb_mode(regs) && !is_thumb2(p->opcode)) {
u16 tmp = p->opcode >> 16;
}
}
-static int make_trampoline(struct uprobe *up, struct pt_regs *regs)
+static int make_trampoline(struct uprobe *p, struct pt_regs *regs)
{
unsigned long *tramp, *utramp;
- struct kprobe *p = up2kp(up);
int sw;
/*
/* ARM */
case 0b110:
case 0b010:
- tramp = up->atramp.tramp_arm;
+ tramp = p->atramp.tramp_arm;
break;
/* THUMB */
case 0b111:
case 0b101:
restore_opcode_for_thumb(p, regs);
- tramp = up->atramp.tramp_thumb;
+ tramp = p->atramp.tramp_thumb;
break;
default:
printk(KERN_INFO "Error in %s at %d: we are in arm mode "
"(%0lX instruction at %p address)!\n",
__FILE__, __LINE__, p->opcode, p->addr);
- disarm_uprobe(p, up->task);
+ disarm_uprobe(p, p->task);
return 1;
}
- utramp = up->atramp.utramp;
+ utramp = p->atramp.utramp;
- if (!write_proc_vm_atomic(up->task, (unsigned long)utramp, tramp,
+ if (!write_proc_vm_atomic(p->task, (unsigned long)utramp, tramp,
UPROBES_TRAMP_LEN * sizeof(*tramp))) {
printk(KERN_ERR "failed to write memory %p!\n", utramp);
return -EINVAL;
return 0;
}
+/**
+ * @brief Prepares singlestep for current CPU.
+ *
+ * @param p Pointer to uprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+
+static void uprobe_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ if (p->ss_addr[cpu]) {
+ regs->ARM_pc = (unsigned long)p->ss_addr[cpu];
+ p->ss_addr[cpu] = NULL;
+ } else {
+ regs->ARM_pc = (unsigned long)p->ainsn.insn;
+ }
+}
+
static int uprobe_handler(struct pt_regs *regs)
{
kprobe_opcode_t *addr = (kprobe_opcode_t *)(regs->ARM_pc);
struct task_struct *task = current;
pid_t tgid = task->tgid;
- struct kprobe *p;
+ struct uprobe *p;
- p = get_ukprobe(addr, tgid);
+ p = get_uprobe(addr, tgid);
if (p == NULL) {
unsigned long offset_bp = thumb_mode(regs) ?
0x1a :
4 * UPROBES_TRAMP_RET_BREAK_IDX;
void *tramp_addr = (void *)addr - offset_bp;
- p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
+ p = get_uprobe_by_insn_slot(tramp_addr, tgid, regs);
if (p == NULL) {
printk(KERN_INFO "no_uprobe: Not one of ours: let "
"kernel handle it %p\n", addr);
trampoline_uprobe_handler(p, regs);
} else {
if (p->ainsn.insn == NULL) {
- struct uprobe *up = kp2up(p);
- if (make_trampoline(up, regs)) {
+ if (make_trampoline(p, regs)) {
printk(KERN_INFO "no_uprobe live\n");
return 0;
}
}
if (!p->pre_handler || !p->pre_handler(p, regs))
- prepare_singlestep(p, regs);
+ uprobe_prepare_singlestep(p, regs);
}
return 0;
#include <swap-asm/swap_kprobes.h> /* FIXME: for UPROBES_TRAMP_LEN */
-struct kprobe;
struct task_struct;
struct uprobe;
struct uretprobe;
int arch_prepare_uprobe(struct uprobe *up);
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs);
-static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
+static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
{
return 0;
}
int arch_disarm_urp_inst(struct uretprobe_instance *ri,
struct task_struct *task);
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
void arch_remove_uprobe(struct uprobe *up);
*/
struct uprobe_ctlblk {
unsigned long flags; /**< Flags */
- struct kprobe *p; /**< Pointer to the uprobe's kprobe */
+ struct uprobe *p; /**< Pointer to the uprobe */
};
static unsigned long trampoline_addr(struct uprobe *up)
{
- return (unsigned long)(up->kp.ainsn.insn +
+ return (unsigned long)(up->ainsn.insn +
UPROBES_TRAMP_RET_BREAK_IDX);
}
return (struct uprobe_ctlblk *)(end_of_stack(current) + 20);
}
-static struct kprobe *get_current_probe(void)
+static struct uprobe *get_current_probe(void)
{
return current_ucb()->p;
}
-static void set_current_probe(struct kprobe *p)
+static void set_current_probe(struct uprobe *p)
{
current_ucb()->p = p;
}
* @return 0 on success,\n
* -1 on error.
*/
-int arch_prepare_uprobe(struct uprobe *up)
+int arch_prepare_uprobe(struct uprobe *p)
{
- struct kprobe *p = up2kp(up);
- struct task_struct *task = up->task;
- u8 *tramp = up->atramp.tramp;
+ struct task_struct *task = p->task;
+ u8 *tramp = p->atramp.tramp;
enum { call_relative_opcode = 0xe8 };
if (!read_proc_vm_atomic(task, (unsigned long)p->addr,
p->ainsn.boostable = swap_can_boost(tramp) ? 0 : -1;
- p->ainsn.insn = swap_slot_alloc(up->sm);
+ p->ainsn.insn = swap_slot_alloc(p->sm);
if (p->ainsn.insn == NULL) {
printk(KERN_ERR "trampoline out of memory\n");
return -ENOMEM;
}
if (!write_proc_vm_atomic(task, (unsigned long)p->ainsn.insn,
- tramp, sizeof(up->atramp.tramp))) {
- swap_slot_free(up->sm, p->ainsn.insn);
+ tramp, sizeof(p->atramp.tramp))) {
+ swap_slot_free(p->sm, p->ainsn.insn);
printk(KERN_INFO "failed to write memory %p!\n", tramp);
return -EINVAL;
}
/**
* @brief Jump pre-handler.
*
- * @param p Pointer to the uprobe's kprobe.
+ * @param p Pointer to the uprobe.
* @param regs Pointer to CPU register data.
* @return 0.
*/
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs)
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs)
{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct ujprobe *jp = container_of(up, struct ujprobe, up);
- kprobe_pre_entry_handler_t pre_entry =
- (kprobe_pre_entry_handler_t)jp->pre_entry;
+ struct ujprobe *jp = container_of(p, struct ujprobe, up);
+ uprobe_pre_entry_handler_t pre_entry =
+ (uprobe_pre_entry_handler_t)jp->pre_entry;
entry_point_t entry = (entry_point_t)jp->entry;
unsigned long args[6];
if (!read_proc_vm_atomic(current, regs->EREG(sp), &(ri->ret_addr),
sizeof(ri->ret_addr))) {
printk(KERN_ERR "failed to read user space func ra %lx addr=%p!\n",
- regs->EREG(sp), ri->rp->up.kp.addr);
+ regs->EREG(sp), ri->rp->up.addr);
return -EINVAL;
}
/**
* @brief Gets trampoline address.
*
- * @param p Pointer to the uprobe's kprobe.
+ * @param p Pointer to the uprobe.
* @param regs Pointer to CPU register data.
* @return Trampoline address.
*/
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs)
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs)
{
- return trampoline_addr(kp2up(p));
+ return trampoline_addr(p);
}
/**
* @param up Pointer to the target uprobe.
* @return Void.
*/
-void arch_remove_uprobe(struct uprobe *up)
+void arch_remove_uprobe(struct uprobe *p)
{
- struct kprobe *p = up2kp(up);
-
- swap_slot_free(up->sm, p->ainsn.insn);
+ swap_slot_free(p->sm, p->ainsn.insn);
}
static void set_user_jmp_op(void *from, void *to)
"failed to write jump opcode to user space %p\n", from);
}
-static void resume_execution(struct kprobe *p,
+static void resume_execution(struct uprobe *p,
struct pt_regs *regs,
unsigned long flags)
{
return;
}
-static bool prepare_ss_addr(struct kprobe *p, struct pt_regs *regs)
+static bool prepare_ss_addr(struct uprobe *p, struct pt_regs *regs)
{
unsigned long *ss_addr = (long *)&p->ss_addr[smp_processor_id()];
regs->flags &= ~IF_MASK;
}
+/**
+ * @brief Prepares singlestep for current CPU.
+ *
+ * @param p Pointer to uprobe.
+ * @param regs Pointer to CPU registers data.
+ * @return Void.
+ */
+static void uprobe_prepare_singlestep(struct uprobe *p, struct pt_regs *regs)
+{
+ int cpu = smp_processor_id();
+
+ if (p->ss_addr[cpu]) {
+ regs->EREG(ip) = (unsigned long)p->ss_addr[cpu];
+ p->ss_addr[cpu] = NULL;
+ } else {
+ regs->EREG(flags) |= TF_MASK;
+ regs->EREG(flags) &= ~IF_MASK;
+ /* single step inline if the instruction is an int3 */
+ if (p->opcode == BREAKPOINT_INSTRUCTION) {
+ regs->EREG(ip) = (unsigned long) p->addr;
+ /* printk(KERN_INFO "break_insn!!!\n"); */
+ } else
+ regs->EREG(ip) = (unsigned long) p->ainsn.insn;
+ }
+}
+
static int uprobe_handler(struct pt_regs *regs)
{
- struct kprobe *p;
+ struct uprobe *p;
kprobe_opcode_t *addr;
struct task_struct *task = current;
pid_t tgid = task->tgid;
save_current_flags(regs);
addr = (kprobe_opcode_t *)(regs->EREG(ip) - sizeof(kprobe_opcode_t));
- p = get_ukprobe(addr, tgid);
+ p = get_uprobe(addr, tgid);
if (p == NULL) {
void *tramp_addr = (void *)addr - UPROBES_TRAMP_RET_BREAK_IDX;
- p = get_ukprobe_by_insn_slot(tramp_addr, tgid, regs);
+ p = get_uprobe_by_insn_slot(tramp_addr, tgid, regs);
if (p == NULL) {
printk(KERN_INFO "no_uprobe\n");
return 0;
set_current_probe(p);
prepare_ss(regs);
}
+
+ uprobe_prepare_singlestep(p, regs);
}
}
static int post_uprobe_handler(struct pt_regs *regs)
{
- struct kprobe *p = get_current_probe();
+ struct uprobe *p = get_current_probe();
unsigned long flags = current_ucb()->flags;
if (p == NULL) {
}
int arch_prepare_uprobe(struct uprobe *up);
-int setjmp_upre_handler(struct kprobe *p, struct pt_regs *regs);
-static inline int longjmp_break_uhandler(struct kprobe *p, struct pt_regs *regs)
+int setjmp_upre_handler(struct uprobe *p, struct pt_regs *regs);
+static inline int longjmp_break_uhandler(struct uprobe *p, struct pt_regs *regs)
{
return 0;
}
int arch_prepare_uretprobe(struct uretprobe_instance *ri, struct pt_regs *regs);
int arch_disarm_urp_inst(struct uretprobe_instance *ri,
struct task_struct *task);
-unsigned long arch_get_trampoline_addr(struct kprobe *p, struct pt_regs *regs);
+unsigned long arch_get_trampoline_addr(struct uprobe *p, struct pt_regs *regs);
void arch_set_orig_ret_addr(unsigned long orig_ret_addr, struct pt_regs *regs);
void arch_remove_uprobe(struct uprobe *up);
{
int i;
struct hlist_head *head;
- struct kprobe *p;
+ struct uprobe *p;
DECLARE_NODE_PTR_FOR_HLIST(node);
/* print uprobe table */
for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
head = &uprobe_insn_slot_table[i];
- swap_hlist_for_each_entry_rcu(p, node, head, is_hlist_arm) {
- printk(KERN_INFO "####### find U tgid=%u, addr=%x\n",
- p->tgid, p->addr);
+ swap_hlist_for_each_entry_rcu(p, node, head, is_hlist) {
+ printk(KERN_INFO "####### find U tgid=%u, addr=0x%lx\n",
+ p->task->tgid, (unsigned long)p->addr);
}
}
}
/*
* Keep all fields in the uprobe consistent
*/
-static inline void copy_uprobe(struct kprobe *old_p, struct kprobe *p)
+static inline void copy_uprobe(struct uprobe *old_p, struct uprobe *p)
{
memcpy(&p->opcode, &old_p->opcode, sizeof(kprobe_opcode_t));
memcpy(&p->ainsn, &old_p->ainsn, sizeof(struct arch_specific_insn));
* Aggregate handlers for multiple uprobes support - these handlers
* take care of invoking the individual uprobe handlers on p->list
*/
-static int aggr_pre_uhandler(struct kprobe *p, struct pt_regs *regs)
+static int aggr_pre_uhandler(struct uprobe *p, struct pt_regs *regs)
{
- struct kprobe *kp;
+ struct uprobe *up;
int ret;
- list_for_each_entry_rcu(kp, &p->list, list) {
- if (kp->pre_handler) {
- ret = kp->pre_handler(kp, regs);
+ list_for_each_entry_rcu(up, &p->list, list) {
+ if (up->pre_handler) {
+ ret = up->pre_handler(up, regs);
if (ret)
return ret;
}
return 0;
}
-static void aggr_post_uhandler(struct kprobe *p, struct pt_regs *regs,
+static void aggr_post_uhandler(struct uprobe *p, struct pt_regs *regs,
unsigned long flags)
{
- struct kprobe *kp;
+ struct uprobe *up;
- list_for_each_entry_rcu(kp, &p->list, list) {
- if (kp->post_handler)
- kp->post_handler(kp, regs, flags);
+ list_for_each_entry_rcu(up, &p->list, list) {
+ if (up->post_handler)
+ up->post_handler(up, regs, flags);
}
}
-static int aggr_fault_uhandler(struct kprobe *p,
+static int aggr_fault_uhandler(struct uprobe *p,
struct pt_regs *regs,
int trapnr)
{
return 0;
}
-static int aggr_break_uhandler(struct kprobe *p, struct pt_regs *regs)
+static int aggr_break_uhandler(struct uprobe *p, struct pt_regs *regs)
{
return 0;
}
* Add the new probe to old_p->list. Fail if this is the
* second ujprobe at the address - two ujprobes can't coexist
*/
-static int add_new_uprobe(struct kprobe *old_p, struct kprobe *p)
+static int add_new_uprobe(struct uprobe *old_p, struct uprobe *p)
{
if (p->break_handler) {
if (old_p->break_handler)
* Fill in the required fields of the "manager uprobe". Replace the
* earlier uprobe in the hlist with the manager uprobe
*/
-static inline void add_aggr_uprobe(struct kprobe *ap, struct kprobe *p)
+static inline void add_aggr_uprobe(struct uprobe *ap, struct uprobe *p)
{
copy_uprobe(p, ap);
* This is the second or subsequent uprobe at the address - handle
* the intricacies
*/
-static int register_aggr_uprobe(struct kprobe *old_p, struct kprobe *p)
+static int register_aggr_uprobe(struct uprobe *old_p, struct uprobe *p)
{
int ret = 0;
- struct kprobe *ap;
if (old_p->pre_handler == aggr_pre_uhandler) {
copy_uprobe(old_p, p);
if (!uap)
return -ENOMEM;
- uap->task = kp2up(p)->task;
- ap = up2kp(uap);
- add_aggr_uprobe(ap, old_p);
- copy_uprobe(ap, p);
- ret = add_new_uprobe(ap, p);
+ uap->task = p->task;
+ add_aggr_uprobe(uap, old_p);
+ copy_uprobe(uap, p);
+ ret = add_new_uprobe(uap, p);
}
return ret;
static int arm_uprobe(struct uprobe *p)
{
kprobe_opcode_t insn = BREAKPOINT_INSTRUCTION;
- int ret = write_proc_vm_atomic(p->task, (unsigned long)p->kp.addr,
+ int ret = write_proc_vm_atomic(p->task, (unsigned long)p->addr,
&insn, sizeof(insn));
if (!ret) {
printk("arm_uprobe: failed to write memory "
- "tgid=%u addr=%p!\n", p->task->tgid, p->kp.addr);
+ "tgid=%u addr=%p!\n", p->task->tgid, p->addr);
return -EACCES;
}
/**
* @brief Disarms uprobe.
*
- * @param p Pointer to the uprobe's kprobe.
+ * @param p Pointer to the uprobe.
* @param task Pointer to the target task.
* @return Void.
*/
-void disarm_uprobe(struct kprobe *p, struct task_struct *task)
+void disarm_uprobe(struct uprobe *p, struct task_struct *task)
{
int ret = write_proc_vm_atomic(task, (unsigned long)p->addr,
&p->opcode, sizeof(p->opcode));
}
/**
- * @brief Gets uprobe's kprobe.
+ * @brief Gets uprobe.
*
* @param addr Probe's address.
* @param tgid Probes's thread group ID.
- * @return Pointer to the kprobe on success,\n
+ * @return Pointer to the uprobe on success,\n
* NULL otherwise.
*/
-struct kprobe *get_ukprobe(void *addr, pid_t tgid)
+struct uprobe *get_uprobe(void *addr, pid_t tgid)
{
struct hlist_head *head;
- struct kprobe *p;
+ struct uprobe *p;
DECLARE_NODE_PTR_FOR_HLIST(node);
head = &uprobe_table[hash_ptr(addr, UPROBE_HASH_BITS)];
swap_hlist_for_each_entry_rcu(p, node, head, hlist) {
- if (p->addr == addr && kp2up(p)->task->tgid == tgid)
+ if (p->addr == addr && p->task->tgid == tgid)
return p;
}
/**
* @brief Adds uprobe to hlist when trampoline have been made.
*
- * @param p Pointer to the uprobe's kprobe.
+ * @param p Pointer to the uprobe.
* @return Void.
*/
-void add_uprobe_table(struct kprobe *p)
+void add_uprobe_table(struct uprobe *p)
{
write_lock(&st_lock);
hlist_add_head(&p->is_hlist,
write_unlock(&st_lock);
}
-static void del_uprobe_table(struct kprobe *p)
+static void del_uprobe_table(struct uprobe *p)
{
write_lock(&st_lock);
if (!hlist_unhashed(&p->is_hlist))
}
/**
- * @brief Gets kprobe by insn slot.
+ * @brief Gets uprobe by insn slot.
*
* @param addr Probe's address.
* @param tgit Probe's thread group ID.
* @param regs Pointer to CPU registers data.
- * @return Pointer to the kprobe on success,\n
+ * @return Pointer to the uprobe on success,\n
* NULL otherwise.
*/
-struct kprobe *get_ukprobe_by_insn_slot(void *addr,
- pid_t tgid,
- struct pt_regs *regs)
+struct uprobe *get_uprobe_by_insn_slot(void *addr,
+ pid_t tgid,
+ struct pt_regs *regs)
{
struct hlist_head *head;
- struct kprobe *p;
+ struct uprobe *p;
DECLARE_NODE_PTR_FOR_HLIST(node);
read_lock(&st_lock);
head = &slot_table[hash_ptr(addr, UPROBE_HASH_BITS)];
swap_hlist_for_each_entry(p, node, head, is_hlist) {
- if (p->ainsn.insn == addr && kp2up(p)->task->tgid == tgid) {
+ if (p->ainsn.insn == addr && p->task->tgid == tgid) {
read_unlock(&st_lock);
return p;
}
static void remove_uprobe(struct uprobe *up)
{
- del_uprobe_table(&up->kp);
+ del_uprobe_table(up);
arch_remove_uprobe(up);
}
* @return 0 on success,\n
* negative error code on error.
*/
-int swap_register_uprobe(struct uprobe *up)
+int swap_register_uprobe(struct uprobe *p)
{
int ret = 0;
- struct kprobe *p, *old_p;
+ struct uprobe *old_p;
- p = &up->kp;
if (!p->addr)
return -EINVAL;
#endif
p->ainsn.insn = NULL;
- p->mod_refcounted = 0;
- p->nmissed = 0;
INIT_LIST_HEAD(&p->list);
#ifdef KPROBES_PROFILE
p->start_tm.tv_sec = p->start_tm.tv_usec = 0;
#endif
/* get the first item */
- old_p = get_ukprobe(p->addr, kp2up(p)->task->tgid);
+ old_p = get_uprobe(p->addr, p->task->tgid);
if (old_p) {
- struct task_struct *task = up->task;
+ struct task_struct *task = p->task;
/* TODO: add support many uprobes on address */
printk(KERN_INFO "uprobe on task[%u %u %s] vaddr=%p is there\n",
INIT_HLIST_NODE(&p->is_hlist);
- ret = arch_prepare_uprobe(up);
+ ret = arch_prepare_uprobe(p);
if (ret) {
DBPRINTF("goto out\n", ret);
goto out;
hlist_add_head_rcu(&p->hlist,
&uprobe_table[hash_ptr(p->addr, UPROBE_HASH_BITS)]);
- ret = arm_uprobe(up);
+ ret = arm_uprobe(p);
if (ret) {
hlist_del_rcu(&p->hlist);
synchronize_rcu();
- remove_uprobe(up);
+ remove_uprobe(p);
}
out:
* @param disarm Disarm flag. When true uprobe is disarmed.
* @return Void.
*/
-void __swap_unregister_uprobe(struct uprobe *up, int disarm)
+void __swap_unregister_uprobe(struct uprobe *p, int disarm)
{
- struct kprobe *p, *old_p, *list_p;
+ struct uprobe *old_p, *list_p;
int cleanup_p;
- p = &up->kp;
- old_p = get_ukprobe(p->addr, kp2up(p)->task->tgid);
+ old_p = get_uprobe(p->addr, p->task->tgid);
if (unlikely(!old_p))
return;
(p->list.next == &old_p->list) && (p->list.prev == &old_p->list))) {
/* Only probe on the hash list */
if (disarm)
- disarm_uprobe(&up->kp, up->task);
+ disarm_uprobe(p, p->task);
hlist_del_rcu(&old_p->hlist);
cleanup_p = 1;
if (!in_atomic())
synchronize_sched();
- remove_uprobe(up);
+ remove_uprobe(p);
} else {
if (p->break_handler)
old_p->break_handler = NULL;
int ret = 0;
/* Todo: Verify probepoint is a function entry point */
- jp->up.kp.pre_handler = setjmp_upre_handler;
- jp->up.kp.break_handler = longjmp_break_uhandler;
+ jp->up.pre_handler = setjmp_upre_handler;
+ jp->up.break_handler = longjmp_break_uhandler;
ret = swap_register_uprobe(&jp->up);
/**
* @brief Trampoline uprobe handler.
*
- * @param p Pointer to the uprobe's kprobe.
+ * @param p Pointer to the uprobe.
* @param regs Pointer to CPU register data.
* @return 1
*/
-int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs)
+int trampoline_uprobe_handler(struct uprobe *p, struct pt_regs *regs)
{
struct uretprobe_instance *ri = NULL;
- struct kprobe *kp;
+ struct uprobe *up;
struct hlist_head *head;
unsigned long flags, tramp_addr, orig_ret_addr = 0;
struct hlist_node *tmp;
continue;
}
- kp = NULL;
+ up = NULL;
if (ri->rp) {
- kp = up2kp(&ri->rp->up);
+ up = &ri->rp->up;
if (ri->rp->handler)
ri->rp->handler(ri, regs);
orig_ret_addr = (unsigned long)ri->ret_addr;
recycle_urp_inst(ri);
- if ((orig_ret_addr != tramp_addr && kp == p) || kp == NULL) {
+ if ((orig_ret_addr != tramp_addr && up == p) || up == NULL) {
/*
* This is the real return address. Any other
* instances associated with this task are for
return 1;
}
-static int pre_handler_uretprobe(struct kprobe *p, struct pt_regs *regs)
+static int pre_handler_uretprobe(struct uprobe *p, struct pt_regs *regs)
{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct uretprobe *rp = container_of(up, struct uretprobe, up);
+ struct uretprobe *rp = container_of(p, struct uretprobe, up);
#ifdef CONFIG_ARM
int noret = thumb_mode(regs) ? rp->thumb_noret : rp->arm_noret;
#endif
DBPRINTF("START\n");
- rp->up.kp.pre_handler = pre_handler_uretprobe;
- rp->up.kp.post_handler = NULL;
- rp->up.kp.fault_handler = NULL;
- rp->up.kp.break_handler = NULL;
+ rp->up.pre_handler = pre_handler_uretprobe;
+ rp->up.post_handler = NULL;
+ rp->up.fault_handler = NULL;
+ rp->up.break_handler = NULL;
/* Pre-allocate memory for max kretprobe instances */
if (rp->maxactive <= 0) {
if (ri->task == task) {
printk(KERN_INFO "%s (%d/%d): pending urp inst: %08lx\n",
task->comm, task->tgid, task->pid,
- (unsigned long)ri->rp->up.kp.addr);
+ (unsigned long)ri->rp->up.addr);
arch_disarm_urp_inst(ri, task);
recycle_urp_inst(ri);
}
printk(KERN_INFO "%s (%d/%d): "
"cannot disarm urp instance (%08lx)\n",
ri->task->comm, ri->task->tgid, ri->task->pid,
- (unsigned long)rp->up.kp.addr);
+ (unsigned long)rp->up.addr);
recycle_urp_inst(ri);
}
void swap_unregister_all_uprobes(struct task_struct *task)
{
struct hlist_head *head;
- struct kprobe *p;
+ struct uprobe *p;
int i;
struct hlist_node *tnode;
DECLARE_NODE_PTR_FOR_HLIST(node);
for (i = 0; i < UPROBE_TABLE_SIZE; ++i) {
head = &uprobe_table[i];
swap_hlist_for_each_entry_safe(p, node, tnode, head, hlist) {
- if (kp2up(p)->task->tgid == task->tgid) {
- struct uprobe *up =
- container_of(p, struct uprobe, kp);
+ if (p->task->tgid == task->tgid) {
printk(KERN_INFO "%s: delete uprobe at %p[%lx]"
" for %s/%d\n", __func__, p->addr,
(unsigned long)p->opcode,
task->comm, task->pid);
- swap_unregister_uprobe(up);
+ swap_unregister_uprobe(p);
}
}
}
#include <swap-asm/swap_uprobes.h>
+/**
+ * @brief Uprobe pre-handler pointer.
+ */
+typedef int (*uprobe_pre_handler_t) (struct uprobe *, struct pt_regs *);
+
+/**
+ * @brief Uprobe break handler pointer.
+ */
+typedef int (*uprobe_break_handler_t) (struct uprobe *, struct pt_regs *);
+
+/**
+ * @brief Uprobe post handler pointer.
+ */
+typedef void (*uprobe_post_handler_t) (struct uprobe *,
+ struct pt_regs *,
+ unsigned long flags);
+
+/**
+ * @brief Uprobe fault handler pointer.
+ */
+typedef int (*uprobe_fault_handler_t) (struct uprobe *,
+ struct pt_regs *,
+ int trapnr);
/**
* @struct uprobe
- * @brief Stores uprobe data, based on kprobe.
+ * @brief Stores uprobe data.
*/
struct uprobe {
- struct kprobe kp; /**< Kprobe for this uprobe */
- struct task_struct *task; /**< Pointer to the task struct */
- struct slot_manager *sm; /**< Pointer to slot manager */
- struct arch_specific_tramp atramp; /**< Stores trampoline */
+ struct hlist_node hlist; /**< Hash list.*/
+ /** List of probes to search by instruction slot.*/
+ struct hlist_node is_hlist;
+ /** List of uprobes for multi-handler support.*/
+ struct list_head list;
+ /** Location of the probe point. */
+ kprobe_opcode_t *addr;
+ /** Called before addr is executed.*/
+ uprobe_pre_handler_t pre_handler;
+ /** Called after addr is executed, unless...*/
+ uprobe_post_handler_t post_handler;
+ /** ... called if executing addr causes a fault (eg. page fault).*/
+ uprobe_fault_handler_t fault_handler;
+ /** Return 1 if it handled fault, otherwise kernel will see it.*/
+ uprobe_break_handler_t break_handler;
+ /** Saved opcode (which has been replaced with breakpoint).*/
+ kprobe_opcode_t opcode;
+ /** Copy of the original instruction.*/
+ struct arch_specific_insn ainsn;
+ /** Override single-step target address, may be used to redirect
+ * control-flow to arbitrary address after probe point without
+ * invocation of original instruction; useful for functions
+ * replacement. If jprobe.entry should return address of function or
+ * NULL if original function should be called.
+ * Not supported for X86, not tested for MIPS. */
+ kprobe_opcode_t *ss_addr[NR_CPUS];
+#ifdef CONFIG_ARM
+ /** Safe/unsafe to use probe on ARM.*/
+ unsigned safe_arm:1;
+ /** Safe/unsafe to use probe on Thumb.*/
+ unsigned safe_thumb:1;
+#endif
+
+ struct task_struct *task; /**< Pointer to the task struct */
+ struct slot_manager *sm; /**< Pointer to slot manager */
+ struct arch_specific_tramp atramp; /**< Stores trampoline */
};
/**
void swap_discard_pending_uretprobes(struct task_struct *task);
void swap_ujprobe_return(void);
-struct kprobe *get_ukprobe(void *addr, pid_t tgid);
-struct kprobe *get_ukprobe_by_insn_slot(void *addr,
+struct uprobe *get_uprobe(void *addr, pid_t tgid);
+struct uprobe *get_uprobe_by_insn_slot(void *addr,
pid_t tgid,
struct pt_regs *regs);
-static inline struct uprobe *kp2up(struct kprobe *p)
-{
- return container_of(p, struct uprobe, kp);
-}
-
-static inline struct kprobe *up2kp(struct uprobe *p)
-{
- return &p->kp;
-}
-
-void disarm_uprobe(struct kprobe *p, struct task_struct *task);
+void disarm_uprobe(struct uprobe *p, struct task_struct *task);
-int trampoline_uprobe_handler(struct kprobe *p, struct pt_regs *regs);
+int trampoline_uprobe_handler(struct uprobe *p, struct pt_regs *regs);
-void add_uprobe_table(struct kprobe *p);
+void add_uprobe_table(struct uprobe *p);
#endif /* _SWAP_UPROBES_H */
return 0;
}
-static int uprobe_handler(struct kprobe *p, struct pt_regs *regs)
+static int uprobe_handler(struct uprobe *p, struct pt_regs *regs)
{
- struct uprobe *up = container_of(p, struct uprobe, kp);
- struct us_ip *ip = container_of(up, struct us_ip, uprobe);
+ struct us_ip *ip = container_of(p, struct us_ip, uprobe);
struct probe_info_new *info_new;
info_new = probe_info_get_val(ip->info, struct probe_info_new *);
static void up_init(struct us_ip *ip)
{
- ip->uprobe.kp.pre_handler = uprobe_handler;
+ ip->uprobe.pre_handler = uprobe_handler;
}
static void up_uninit(struct us_ip *ip)
enum probe_t type;
union {
struct {
- kprobe_pre_handler_t handler;
+ uprobe_pre_handler_t handler;
} p;
struct {
return -EINVAL;
}
- up->kp.addr = (kprobe_opcode_t *)ip->orig_addr;
+ up->addr = (kprobe_opcode_t *)ip->orig_addr;
up->task = ip->page->file->proc->task;
up->sm = ip->page->file->proc->sm;
if (ret) {
struct sspt_file *file = ip->page->file;
char *name = file->dentry->d_iname;
- unsigned long addr = (unsigned long)up->kp.addr;
+ unsigned long addr = (unsigned long)up->addr;
unsigned long offset = addr - file->vm_start;
printk(KERN_INFO "swap_register_uretprobe() failure %d "
"(%s:%lx|%lx)\n", ret, name, offset,
- (unsigned long)ip->retprobe.up.kp.opcode);
+ (unsigned long)ip->retprobe.up.opcode);
}
return ret;
break;
case US_DISARM:
up = probe_info_get_uprobe(ip->info, ip);
- disarm_uprobe(&up->kp, task);
+ disarm_uprobe(up, task);
break;
case US_UNINSTALL:
probe_info_unregister(ip->info, ip, 0);
printk(KERN_INFO "### addr[%2d]=%lx, R_addr=%lx\n",
i, (unsigned long)ip->offset,
- (unsigned long)rp->up.kp.addr);
+ (unsigned long)rp->up.addr);
print_retprobe(rp);
}
}
/*
* soup_req
*/
-static int soup_req_handle(struct kprobe *p, struct pt_regs *regs)
+static int soup_req_handle(struct uprobe *p, struct pt_regs *regs)
{
enum { max_str_len = 512 };
const char __user *user_s;
/*
* main_res_req
*/
-static int mres_req_handle(struct kprobe *p, struct pt_regs *regs)
+static int mres_req_handle(struct uprobe *p, struct pt_regs *regs)
{
void *ptr = (void *)swap_get_uarg(regs, 0);
struct wsp_res *res;
/*
* main_res_finish
*/
-static int mres_finish_handle(struct kprobe *p, struct pt_regs *regs)
+static int mres_finish_handle(struct uprobe *p, struct pt_regs *regs)
{
void *ptr = (void *)swap_get_uarg(regs, 0);
struct wsp_res *res;
/*
* res_request
*/
-static int res_request_handle(struct kprobe *p, struct pt_regs *regs)
+static int res_request_handle(struct uprobe *p, struct pt_regs *regs)
{
void *ptr = (void *)swap_get_uarg(regs, 0);
struct wsp_res *res;