Exemplo n.º 1
0
int
mdb_eval(const char *s)
{
	mdb_frame_t *ofp = mdb.m_fmark;
	mdb_frame_t *fp = mdb.m_frame;
	int err;

	if (s == NULL)
		return (set_errno(EINVAL));

	/*
	 * Push m_in down onto the input stack, then set m_in to point to the
	 * i/o buffer for our command string, and reset the frame marker.
	 * The mdb_run() function returns when the new m_in iob reaches EOF.
	 */
	mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
	mdb.m_in = mdb_iob_create(mdb_strio_create(s), MDB_IOB_RDONLY);

	mdb.m_fmark = NULL;
	err = mdb_run();
	mdb.m_fmark = ofp;

	/*
	 * Now pop the old standard input stream and restore mdb.m_in and
	 * the parser's saved current line number.
	 */
	mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
	yylineno = mdb_iob_lineno(mdb.m_in);

	/*
	 * If mdb_run() returned an error, propagate this backward
	 * up the stack of debugger environment frames.
	 */
	if (MDB_ERR_IS_FATAL(err))
		longjmp(fp->f_pcb, err);

	if (err == MDB_ERR_PAGER || err == MDB_ERR_SIGINT)
		return (set_errno(EMDB_CANCEL));

	if (err != 0)
		return (set_errno(EMDB_EVAL));

	return (0);
}
Exemplo n.º 2
0
/*
 * Call the current frame's mdb command.  This entry point is used by the
 * MDB parser to actually execute a command once it has successfully parsed
 * a line of input.  The command is waiting for us in the current frame.
 * We loop through each command on the list, executing its dcmd with the
 * appropriate argument.  If the command has a successor, we know it had
 * a | operator after it, and so we need to create a pipe and replace
 * stdout with the pipe's output buffer.
 */
int
mdb_call(uintmax_t addr, uintmax_t count, uint_t flags)
{
	mdb_frame_t *fp = mdb.m_frame;
	mdb_cmd_t *cp, *ncp;
	mdb_iob_t *iobs[2];
	int status, err = 0;
	jmp_buf pcb;

	if (mdb_iob_isapipe(mdb.m_in))
		yyerror("syntax error");

	mdb_intr_disable();
	fp->f_cp = mdb_list_next(&fp->f_cmds);

	if (flags & DCMD_LOOP)
		flags |= DCMD_LOOPFIRST; /* set LOOPFIRST if this is a loop */

	for (cp = mdb_list_next(&fp->f_cmds); cp; cp = mdb_list_next(cp)) {
		if (mdb_list_next(cp) != NULL) {
			mdb_iob_pipe(iobs, rdsvc, wrsvc);

			mdb_iob_stack_push(&fp->f_istk, mdb.m_in, yylineno);
			mdb.m_in = iobs[MDB_IOB_RDIOB];

			mdb_iob_stack_push(&fp->f_ostk, mdb.m_out, 0);
			mdb.m_out = iobs[MDB_IOB_WRIOB];

			ncp = mdb_list_next(cp);
			mdb_vcb_inherit(cp, ncp);

			bcopy(fp->f_pcb, pcb, sizeof (jmp_buf));
			ASSERT(fp->f_pcmd == NULL);
			fp->f_pcmd = ncp;

			mdb_frame_set_pipe(fp);

			if ((err = setjmp(fp->f_pcb)) == 0) {
				status = mdb_call_idcmd(cp->c_dcmd, addr, count,
				    flags | DCMD_PIPE_OUT, &cp->c_argv,
				    &cp->c_addrv, cp->c_vcbs);

				ASSERT(mdb.m_in == iobs[MDB_IOB_RDIOB]);
				ASSERT(mdb.m_out == iobs[MDB_IOB_WRIOB]);
			} else {
				mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught "
				    "error %s from pipeline\n", fp->f_id,
				    mdb_err2str(err));
			}

			if (err != 0 || DCMD_ABORTED(status)) {
				mdb_iob_setflags(mdb.m_in, MDB_IOB_ERR);
				mdb_iob_setflags(mdb.m_out, MDB_IOB_ERR);
			} else {
				mdb_iob_flush(mdb.m_out);
				(void) mdb_iob_ctl(mdb.m_out, I_FLUSH,
				    (void *)FLUSHW);
			}

			mdb_frame_clear_pipe(fp);

			mdb_iob_destroy(mdb.m_out);
			mdb.m_out = mdb_iob_stack_pop(&fp->f_ostk);

			if (mdb.m_in != NULL)
				mdb_iob_destroy(mdb.m_in);

			mdb.m_in = mdb_iob_stack_pop(&fp->f_istk);
			yylineno = mdb_iob_lineno(mdb.m_in);

			fp->f_pcmd = NULL;
			bcopy(pcb, fp->f_pcb, sizeof (jmp_buf));

			if (MDB_ERR_IS_FATAL(err))
				longjmp(fp->f_pcb, err);

			if (err != 0 || DCMD_ABORTED(status) ||
			    mdb_addrvec_length(&ncp->c_addrv) == 0)
				break;

			addr = mdb_nv_get_value(mdb.m_dot);
			count = 1;
			flags = 0;

		} else {
			mdb_intr_enable();
			(void) mdb_call_idcmd(cp->c_dcmd, addr, count, flags,
			    &cp->c_argv, &cp->c_addrv, cp->c_vcbs);
			mdb_intr_disable();
		}

		fp->f_cp = mdb_list_next(cp);
		mdb_cmd_reset(cp);
	}

	/*
	 * If our last-command list is non-empty, destroy it.  Then copy the
	 * current frame's cmd list to the m_lastc list and reset the frame.
	 */
	while ((cp = mdb_list_next(&mdb.m_lastc)) != NULL) {
		mdb_list_delete(&mdb.m_lastc, cp);
		mdb_cmd_destroy(cp);
	}

	mdb_list_move(&fp->f_cmds, &mdb.m_lastc);
	mdb_frame_reset(fp);
	mdb_intr_enable();
	return (err == 0);
}
Exemplo n.º 3
0
/*
 * The real main loop of the debugger: create a new execution frame on the
 * debugger stack, and while we have input available, call into the parser.
 */
int
mdb_run(void)
{
	volatile int err;
	mdb_frame_t f;

	mdb_intr_disable();
	mdb_frame_push(&f);

	/*
	 * This is a fresh mdb context, so ignore any pipe command we may have
	 * inherited from the previous frame.
	 */
	f.f_pcmd = NULL;

	if ((err = setjmp(f.f_pcb)) != 0) {
		int pop = (mdb.m_in != NULL &&
		    (mdb_iob_isapipe(mdb.m_in) || mdb_iob_isastr(mdb.m_in)));
		int fromcmd = (f.f_cp != NULL);

		mdb_dprintf(MDB_DBG_DSTK, "frame <%u> caught event %s\n",
		    f.f_id, mdb_err2str(err));

		/*
		 * If a syntax error or other failure has occurred, pop all
		 * input buffers pushed by commands executed in this frame.
		 */
		while (mdb_iob_stack_size(&f.f_istk) != 0) {
			if (mdb.m_in != NULL)
				mdb_iob_destroy(mdb.m_in);
			mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
			yylineno = mdb_iob_lineno(mdb.m_in);
		}

		/*
		 * Reset standard output and the current frame to a known,
		 * clean state, so we can continue execution.
		 */
		mdb_iob_margin(mdb.m_out, MDB_IOB_DEFMARGIN);
		mdb_iob_clrflags(mdb.m_out, MDB_IOB_INDENT);
		mdb_iob_discard(mdb.m_out);
		mdb_frame_reset(&f);

		/*
		 * If there was an error writing to output, display a warning
		 * message if this is the topmost frame.
		 */
		if (err == MDB_ERR_OUTPUT && mdb.m_depth == 1 && errno != EPIPE)
			mdb_warn("write failed");

		/*
		 * If an interrupt or quit signal is reported, we may have been
		 * in the middle of typing or processing the command line:
		 * print a newline and discard everything in the parser's iob.
		 * Note that we do this after m_out has been reset, otherwise
		 * we could trigger a pipe context switch or cause a write
		 * to a broken pipe (in the case of a shell command) when
		 * writing the newline.
		 */
		if (err == MDB_ERR_SIGINT || err == MDB_ERR_QUIT) {
			mdb_iob_nl(mdb.m_out);
			yydiscard();
		}

		/*
		 * If we quit or abort using the output pager, reset the
		 * line count on standard output back to zero.
		 */
		if (err == MDB_ERR_PAGER || MDB_ERR_IS_FATAL(err))
			mdb_iob_clearlines(mdb.m_out);

		/*
		 * If the user requested the debugger quit or abort back to
		 * the top, or if standard input is a pipe or mdb_eval("..."),
		 * then propagate the error up the debugger stack.
		 */
		if (MDB_ERR_IS_FATAL(err) || pop != 0 ||
		    (err == MDB_ERR_PAGER && mdb.m_fmark != &f) ||
		    (err == MDB_ERR_NOMEM && !fromcmd)) {
			mdb_frame_pop(&f, err);
			return (err);
		}

		/*
		 * If we've returned here from a context where signals were
		 * blocked (e.g. a signal handler), we can now unblock them.
		 */
		if (err == MDB_ERR_SIGINT)
			(void) mdb_signal_unblock(SIGINT);
	} else
		mdb_intr_enable();

	for (;;) {
		while (mdb.m_in != NULL && (mdb_iob_getflags(mdb.m_in) &
		    (MDB_IOB_ERR | MDB_IOB_EOF)) == 0) {
			if (mdb.m_depth == 1 &&
			    mdb_iob_stack_size(&f.f_istk) == 0) {
				mdb_iob_clearlines(mdb.m_out);
				mdb_tgt_periodic(mdb.m_target);
			}

			(void) yyparse();
		}

		if (mdb.m_in != NULL) {
			if (mdb_iob_err(mdb.m_in)) {
				warn("error reading input stream %s\n",
				    mdb_iob_name(mdb.m_in));
			}
			mdb_iob_destroy(mdb.m_in);
			mdb.m_in = NULL;
		}

		if (mdb_iob_stack_size(&f.f_istk) == 0)
			break; /* return when we're out of input */

		mdb.m_in = mdb_iob_stack_pop(&f.f_istk);
		yylineno = mdb_iob_lineno(mdb.m_in);
	}

	mdb_frame_pop(&f, 0);

	/*
	 * The value of '.' is a per-frame attribute, to preserve it properly
	 * when switching frames.  But in the case of calling mdb_run()
	 * explicitly (such as through mdb_eval), we want to propagate the value
	 * of '.' to the parent.
	 */
	mdb_nv_set_value(mdb.m_dot, f.f_dot);

	return (0);
}