Пример #1
0
static int
kaif_brkpt_disarm(uintptr_t addr, mdb_instr_t instrp)
{
	if (mdb_tgt_vwrite(mdb.m_target, &instrp, sizeof (mdb_instr_t), addr) !=
	    sizeof (mdb_instr_t))
		return (-1); /* errno is set for us */

	return (0);
}
Пример #2
0
ssize_t
mdb_writevar(const void *buf, const char *name)
{
	GElf_Sym sym;

	if (mdb_tgt_lookup_by_name(mdb.m_target, MDB_TGT_OBJ_EXEC,
	    name, &sym, NULL))
		return (-1);

	if (mdb_tgt_vwrite(mdb.m_target, buf, sym.st_size,
	    (uintptr_t)sym.st_value) == sym.st_size)
		return ((ssize_t)sym.st_size);

	return (-1);
}
Пример #3
0
static int
kaif_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
{
	mdb_instr_t bkpt = KAIF_BREAKPOINT_INSTR;

	if (kaif_toxic_text(addr)) {
		warn("%a cannot be a breakpoint target\n", addr);
		return (set_errno(EMDB_TGTNOTSUP));
	}

	if (mdb_tgt_vread(mdb.m_target, instrp, sizeof (mdb_instr_t), addr) !=
	    sizeof (mdb_instr_t))
		return (-1); /* errno is set for us */

	if (mdb_tgt_vwrite(mdb.m_target, &bkpt, sizeof (mdb_instr_t), addr) !=
	    sizeof (mdb_instr_t))
		return (-1); /* errno is set for us */

	return (0);
}
Пример #4
0
ssize_t
mdb_vwrite(const void *buf, size_t nbytes, uintptr_t addr)
{
	return (mdb_tgt_vwrite(mdb.m_target, buf, nbytes, addr));
}
Пример #5
0
static int
kaif_step(void)
{
	kreg_t pc, fl, oldfl, newfl, sp;
	mdb_tgt_addr_t npc;
	mdb_instr_t instr;
	int emulated = 0, rchk = 0;
	size_t pcoff = 0;

	(void) kmdb_dpi_get_register("pc", &pc);

	if (kaif_toxic_text(pc)) {
		warn("%a cannot be stepped\n", pc);
		return (set_errno(EMDB_TGTNOTSUP));
	}

	if ((npc = mdb_dis_nextins(mdb.m_disasm, mdb.m_target,
	    MDB_TGT_AS_VIRT, pc)) == pc) {
		warn("failed to decode instruction at %a for step\n", pc);
		return (set_errno(EINVAL));
	}

	/*
	 * Stepping behavior depends on the type of instruction.  It does not
	 * depend on the presence of a REX prefix, as the action we take for a
	 * given instruction doesn't currently vary for 32-bit instructions
	 * versus their 64-bit counterparts.
	 */
	do {
		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
		    pc + pcoff) != sizeof (mdb_instr_t)) {
			warn("failed to read at %p for step",
			    (void *)(pc + pcoff));
			return (-1);
		}
	} while (pcoff++, (instr >= M_REX_LO && instr <= M_REX_HI && !rchk++));

	switch (instr) {
	case M_IRET:
		warn("iret cannot be stepped\n");
		return (set_errno(EMDB_TGTNOTSUP));

	case M_INT3:
	case M_INTX:
	case M_INTO:
		warn("int cannot be stepped\n");
		return (set_errno(EMDB_TGTNOTSUP));

	case M_ESC:
		if (mdb_tgt_vread(mdb.m_target, &instr, sizeof (mdb_instr_t),
		    pc + pcoff) != sizeof (mdb_instr_t)) {
			warn("failed to read at %p for step",
			    (void *)(pc + pcoff));
			return (-1);
		}

		switch (instr) {
		case M_SYSRET:
			warn("sysret cannot be stepped\n");
			return (set_errno(EMDB_TGTNOTSUP));
		case M_SYSEXIT:
			warn("sysexit cannot be stepped\n");
			return (set_errno(EMDB_TGTNOTSUP));
		}
		break;

	/*
	 * Some instructions need to be emulated.  We need to prevent direct
	 * manipulations of EFLAGS, so we'll emulate cli, sti.  pushfl and
	 * popfl also receive special handling, as they manipulate both EFLAGS
	 * and %esp.
	 */
	case M_CLI:
		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
		fl &= ~KREG_EFLAGS_IF_MASK;
		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);

		emulated = 1;
		break;

	case M_STI:
		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
		fl |= (1 << KREG_EFLAGS_IF_SHIFT);
		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, fl);

		emulated = 1;
		break;

	case M_POPF:
		/*
		 * popfl will restore a pushed EFLAGS from the stack, and could
		 * in so doing cause IF to be turned on, if only for a brief
		 * period.  To avoid this, we'll secretly replace the stack's
		 * EFLAGS with our decaffeinated brand.  We'll then manually
		 * load our EFLAGS copy with the real verion after the step.
		 */
		(void) kmdb_dpi_get_register("sp", &sp);
		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);

		if (mdb_tgt_vread(mdb.m_target, &newfl, sizeof (kreg_t),
		    sp) != sizeof (kreg_t)) {
			warn("failed to read " FLAGS_REG_NAME
			    " at %p for popfl step\n", (void *)sp);
			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
		}

		fl = (fl & ~KREG_EFLAGS_IF_MASK) | KREG_EFLAGS_TF_MASK;

		if (mdb_tgt_vwrite(mdb.m_target, &fl, sizeof (kreg_t),
		    sp) != sizeof (kreg_t)) {
			warn("failed to update " FLAGS_REG_NAME
			    " at %p for popfl step\n", (void *)sp);
			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
		}
		break;
	}

	if (emulated) {
		(void) kmdb_dpi_set_register("pc", npc);
		return (0);
	}

	/* Do the step with IF off, and TF (step) on */
	(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &oldfl);
	(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
	    ((oldfl | (1 << KREG_EFLAGS_TF_SHIFT)) & ~KREG_EFLAGS_IF_MASK));

	kmdb_dpi_resume_master(); /* ... there and back again ... */

	/* EFLAGS has now changed, and may require tuning */

	switch (instr) {
	case M_POPF:
		/*
		 * Use the EFLAGS we grabbed before the pop - see the pre-step
		 * M_POPFL comment.
		 */
		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, newfl);
		return (0);

	case M_PUSHF:
		/*
		 * We pushed our modified EFLAGS (with IF and TF turned off)
		 * onto the stack.  Replace the pushed version with our
		 * unmodified one.
		 */
		(void) kmdb_dpi_get_register("sp", &sp);

		if (mdb_tgt_vwrite(mdb.m_target, &oldfl, sizeof (kreg_t),
		    sp) != sizeof (kreg_t)) {
			warn("failed to update pushed " FLAGS_REG_NAME
			    " at %p after pushfl step\n", (void *)sp);
			return (set_errno(EMDB_TGTNOTSUP)); /* XXX ? */
		}

		/* Go back to using the EFLAGS we were using before the step */
		(void) kmdb_dpi_set_register(FLAGS_REG_NAME, oldfl);
		return (0);

	default:
		/*
		 * The stepped instruction may have altered EFLAGS.  We only
		 * really care about the value of IF, and we know the stepped
		 * instruction didn't alter it, so we can simply copy the
		 * pre-step value.  We'll also need to turn TF back off.
		 */
		(void) kmdb_dpi_get_register(FLAGS_REG_NAME, &fl);
		(void) kmdb_dpi_set_register(FLAGS_REG_NAME,
		    ((fl & ~(KREG_EFLAGS_TF_MASK|KREG_EFLAGS_IF_MASK)) |
		    (oldfl & KREG_EFLAGS_IF_MASK)));
		return (0);
	}
}