void cpu_copy_instr(cpu_core_t *this_cpu, cpu_trap_t *tp, struct pt_regs *regs) { /*dtrace_printf("cpu_copy_instr: inslen=%d %02x %02x %02x %02x\n", tp->ct_tinfo.t_inslen, tp->ct_tinfo.t_opcode, ((unsigned char *) regs->r_pc)[0], ((unsigned char *) regs->r_pc)[1], ((unsigned char *) regs->r_pc)[2]);*/ /***********************************************/ /* Emulate delicate instructions. Without */ /* this we can hit problems in the */ /* syscall/interrupt handlers if we try and */ /* single step the instructions. */ /* Its also faster and less overhead if we */ /* do this here. */ /***********************************************/ switch (tp->ct_tinfo.t_opcode) { case 0xfa: // CLI regs->r_rfl &= ~X86_EFLAGS_IF; this_cpu->cpuc_mode = CPUC_MODE_IDLE; return; case 0xfb: // STI regs->r_rfl |= X86_EFLAGS_IF; this_cpu->cpuc_mode = CPUC_MODE_IDLE; return; } tp->ct_instr_buf[0] = tp->ct_tinfo.t_opcode; dtrace_memcpy(&tp->ct_instr_buf[1], (void *) regs->r_pc, tp->ct_tinfo.t_inslen - 1); /***********************************************/ /* Put a NOP instruction after the */ /* instruction we are going to single step. */ /* Some instructions, like "MOV %CR3,%EAX" */ /* will step the next instruction also. By */ /* doing this, we regain control even if */ /* this happens. 0x90 is a NOP in i386 and */ /* amd64. */ /***********************************************/ tp->ct_instr_buf[tp->ct_tinfo.t_inslen] = 0x90; //printk("step..len=%d %2x %2x\n", this_cpu->cpuc_tinfo.t_inslen, this_cpu->cpuc_instr_buf[0], this_cpu->cpuc_instr_buf[1]); /***********************************************/ /* Set where the next instruction is. The */ /* instruction we hit could be a jump/call, */ /* so we will need to detect that on the */ /* other side of the single-step to ensure */ /* we dont 'undo' the instruction. */ /***********************************************/ tp->ct_orig_pc = (unsigned char *) regs->r_pc + tp->ct_tinfo.t_inslen - 1; /***********************************************/ /* May need to rewrite our copied */ /* instruction if we are doing RIP relative */ /* addressing. */ /***********************************************/ cpu_fix_rel(this_cpu, tp, (unsigned char *) regs->r_pc - 1); /***********************************************/ /* Go into single step mode, and we will */ /* return to our fake buffer. */ /***********************************************/ tp->ct_eflags = regs->r_rfl; //printk("origpc=%p instpc=%p rfl=%p\n", regs->r_pc, tp->cpuc_instr_buf, regs->r_rfl); regs->r_rfl |= X86_EFLAGS_TF; regs->r_rfl &= ~X86_EFLAGS_IF; regs->r_pc = (greg_t) tp->ct_instr_buf; }
static buf_t * create_buf_t(struct file *file, void *uaddr, size_t len, long long offset) { /***********************************************/ /* BUG ALERT! We need per-cpu copies of the */ /* static's below - will fix this later. */ /* Without this, one cpu may overwrite */ /* anothers version of the data. */ /***********************************************/ static buf_t finfo; static char buf[1024]; static char buf2[1024]; static char buf3[1024]; char *name; char *fname; char *mntname = NULL; memset(&finfo, 0, sizeof finfo); finfo.f.fi_offset = offset; finfo.b.b_addr = uaddr; finfo.b.b_bcount = len; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25) fname = d_path(&file->f_path, buf, sizeof buf); #else fname = d_path(file->f_dentry, file->f_vfsmnt, buf, sizeof buf); #endif if (IS_ERR(fname)) { fname = "(unknown)"; } name = strrchr(fname, '/'); dtrace_memcpy(buf2, "<unknown>", 10); if (fname && name) { dtrace_memcpy(buf2, fname, name - fname); buf2[name - fname] = '\0'; } /***********************************************/ /* Problem with older (2.6.9 kernel). */ /***********************************************/ if (dentry_path_fn) { mntname = dentry_path_fn(file->f_vfsmnt->mnt_mountpoint, buf3, sizeof buf3); } finfo.f.fi_dirname = buf2; finfo.f.fi_name = name ? name + 1 : "<none>"; finfo.f.fi_pathname = fname ? fname : "<unknown>"; finfo.f.fi_fs = file->f_vfsmnt->mnt_devname; finfo.f.fi_mount = mntname ? mntname : "<unknown>"; finfo.d.dev_major = -1; finfo.d.dev_minor = -1; finfo.d.dev_instance = -1; if (file->f_mapping && file->f_mapping->host) { finfo.d.dev_major = getmajor(file->f_mapping->host->i_rdev); finfo.d.dev_minor = getminor(file->f_mapping->host->i_rdev); finfo.d.dev_instance = file->f_mapping->host->i_rdev; } finfo.d.dev_pathname = (char *) file->f_vfsmnt->mnt_devname; finfo.d.dev_statname = mntname; return &finfo; }