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); }
/* * 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); }
/* * 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); }