Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}