Example #1
0
int
mdb_signal_sethandler(int sig, mdb_signal_f *handler, void *data)
{
	struct sigaction act;
	int status;

	ASSERT(sig > 0 && sig < NSIG && sig != SIGKILL && sig != SIGSTOP);

	sig_handlers[sig] = handler;
	sig_data[sig] = data;

	if (handler == SIG_DFL || handler == SIG_IGN) {
		act.sa_handler = handler;
		act.sa_flags = SA_RESTART;
	} else {
		act.sa_handler = sig_stub;
		act.sa_flags = SA_SIGINFO | SA_RESTART | SA_ONSTACK;
	}

	(void) sigemptyset(&act.sa_mask);

	if (sig == SIGWINCH || sig == SIGTSTP) {
		(void) sigaddset(&act.sa_mask, SIGWINCH);
		(void) sigaddset(&act.sa_mask, SIGTSTP);
		(void) sigaddset(&act.sa_mask, SIGHUP);
		(void) sigaddset(&act.sa_mask, SIGTERM);
	}

	if ((status = sigaction(sig, &act, NULL)) == 0)
		(void) mdb_signal_unblock(sig);

	return (status);
}
Example #2
0
void
vfail(const char *format, va_list alist)
{
	extern const char *volatile _mdb_abort_str;
	static char buf[256];
	static int nfail;

	if (_mdb_abort_str == NULL) {
		_mdb_abort_str = buf; /* Do this first so we don't recurse */
		(void) mdb_iob_vsnprintf(buf, sizeof (buf), format, alist);

		nfail = 1;
	}

	/*
	 * We'll try to print failure messages twice.  Any more than that,
	 * and we're probably hitting an assertion or some other problem in
	 * the printing routines, and will recurse until we run out of stack.
	 */
	if (nfail++ < 3) {
		mdb_iob_printf(mdb.m_err, "%s ABORT: ", mdb.m_pname);
		mdb_iob_vprintf(mdb.m_err, format, alist);
		mdb_iob_flush(mdb.m_err);

		(void) mdb_signal_blockall();
		(void) mdb_signal_raise(SIGABRT);
		(void) mdb_signal_unblock(SIGABRT);
	}

	exit(1);
}
Example #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);
}