Example #1
0
/*ARGSUSED*/
void
kmdb_kdi_init_isadep(kdi_t *kdi, kmdb_auxv_t *kav)
{
    kdi_dcache_size = kdi_dcache_linesize =
                          kdi_icache_size = kdi_icache_linesize = 0;

    kdi_max_cpu_freq = kdi_sticks_per_usec = 0;

    mdb_dprintf(MDB_DBG_KDI, "Initializing CPUs\n");

    kmdb_prom_walk_cpus(kdi_init_cpus_cb, NULL, NULL);

    /*
     * If we can't find one, guess high.  The CPU frequency is going to be
     * used to determine the length of various delays, such as the mondo
     * interrupt retry delay.  Too long is generally better than too short.
     */
    if (kdi_max_cpu_freq == 0) {
        mdb_dprintf(MDB_DBG_KDI, "No CPU freq found - assuming "
                    "500MHz\n");
        kdi_max_cpu_freq = 500 * MICROSEC;
    }

    kdi_sticks_per_usec =
        MAX((kdi_max_cpu_freq + (MICROSEC - 1)) / MICROSEC, 1);

    mdb.m_kdi->mkdi_cpu_init(kdi_dcache_size, kdi_dcache_linesize,
                             kdi_icache_size, kdi_icache_linesize);

#ifndef sun4v
    kmdb_prom_preserve_kctx_init();
#endif /* sun4v */

}
Example #2
0
static int
dcmd_invoke(mdb_idcmd_t *idcp, uintptr_t addr, uint_t flags,
    int argc, const mdb_arg_t *argv, const mdb_vcb_t *vcbs)
{
	int status;

	mdb_dprintf(MDB_DBG_DCMD, "dcmd %s`%s dot = %lr incr = %llr\n",
	    idcp->idc_modp->mod_name, idcp->idc_name, addr, mdb.m_incr);

	if ((status = idcp->idc_funcp(addr, flags, argc, argv)) == DCMD_USAGE) {
		mdb_dcmd_usage(idcp, mdb.m_err);
		goto done;
	}

	while (status == DCMD_NEXT && (idcp = dcmd_ndef(idcp)) != NULL)
		status = idcp->idc_funcp(addr, flags, argc, argv);

	if (status == DCMD_USAGE)
		mdb_dcmd_usage(idcp, mdb.m_err);

	if (status == DCMD_NEXT)
		status = DCMD_OK;
done:
	/*
	 * If standard output is a pipe and there are vcbs active, we need to
	 * flush standard out and the write-side of the pipe.  The reasons for
	 * this are explained in more detail in mdb_vcb.c.
	 */
	if ((flags & DCMD_PIPE_OUT) && (vcbs != NULL)) {
		mdb_iob_flush(mdb.m_out);
		(void) mdb_iob_ctl(mdb.m_out, I_FLUSH, (void *)FLUSHW);
	}

	return (status);
}
Example #3
0
void
kmdb_dpi_process_work_queue(void)
{
	work_results_t res;

	(void) mdb_nv_create(&res.res_loads, UM_SLEEP);
	(void) mdb_nv_create(&res.res_unloads, UM_SLEEP);

	mdb_dprintf(MDB_DBG_DPI, "processing work queue\n");
	(void) kmdb_wr_debugger_process(kmdb_dbgnotify_cb, &res);

	if (mdb_nv_size(&res.res_loads)) {
		mdb_printf("Loaded modules: [");
		print_modules(&res.res_loads);
		mdb_printf(" ]\n");
	}

	if (mdb_nv_size(&res.res_unloads)) {
		mdb_printf("Unloaded modules: [");
		print_modules(&res.res_unloads);
		mdb_printf(" ]\n");
	}

	mdb_nv_destroy(&res.res_loads);
	mdb_nv_destroy(&res.res_unloads);
}
Example #4
0
/*
 * Called on an individual CPU.  Tries to send it off to the state saver if it
 * hasn't already entered the debugger.  Returns non-zero if it *fails* to stop
 * the CPU.
 */
static int
kdi_halt_cpu(int cpuid, void *state_saverp)
{
    void (*state_saver)(void) = (void (*)(void))state_saverp;
    int state = kmdb_dpi_get_cpu_state(cpuid);
    const char *msg;
    int rc = 0;
    int res;

    if (state != DPI_CPU_STATE_MASTER && state != DPI_CPU_STATE_SLAVE) {
        res = kdi_xc_one(cpuid, state_saver);
        rc = 1;

        if (res == KDI_XC_RES_OK)
            msg = "accepted the";
        else {
            if (res == KDI_XC_RES_BUSY)
                msg = "too busy for";
            else if (res == KDI_XC_RES_NACK)
                msg = "NACKED the";
            else
                msg = "errored the";
        }
        mdb_dprintf(MDB_DBG_KDI, "CPU %d %s halt\n", cpuid, msg);
    }

    return (rc);
}
Example #5
0
int
kmdb_dpi_reenter(void)
{
	int cmd;

	kmdb_kdi_system_claim();

	if ((cmd = setjmp(kmdb_dpi_entry_pcb)) == 0) {
		/* Direct entry from the driver */
		if (kmdb_dpi_resume_requested)
			longjmp(kmdb_dpi_resume_pcb, 1);

		kmdb_first_start();

		fail("kmdb_first_start returned");
		/*NOTREACHED*/
	}

	mdb_dprintf(MDB_DBG_DPI, "returning to driver - cmd %d%s\n", cmd,
	    (kmdb_dpi_work_required() ? " (work required)" : ""));

	kmdb_kdi_system_release();

	membar_producer();

	/*
	 * The debugger wants us to do something - it returned a command
	 * via the setjmp().  The driver will know what to do with the
	 * command.
	 */
	return (cmd);
}
Example #6
0
void
kmdb_dpi_wapt_disarm(kmdb_wapt_t *wp)
{
	mdb.m_dpi->dpo_wapt_disarm(wp);

	mdb_dprintf(MDB_DBG_DPI, "wapt disarmed at %p (type %d, priv %p)\n",
	    (void *)wp->wp_addr, wp->wp_type, wp->wp_priv);
}
Example #7
0
void
mdb_vcb_destroy(mdb_vcb_t *vcb)
{
	mdb_dprintf(MDB_DBG_DSTK, "delete vcb %p (%s)\n", (void *)vcb,
	    mdb_nv_get_name(vcb->vc_var));

	mdb_addrvec_destroy(&vcb->vc_addrv);
	mdb_free(vcb, sizeof (mdb_vcb_t));
}
Example #8
0
static int
kp_iter_mapping(const rd_loadobj_t *rlp, mdb_tgt_t *t)
{
	kp_data_t *kp = t->t_data;
	kp_file_t *kpf;
	kp_map_t *kpm;

	char name[MDB_TGT_MAPSZ];

	if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT, name,
	    sizeof (name), (mdb_tgt_addr_t)rlp->rl_nameaddr) <= 0) {
		mdb_dprintf(MDB_DBG_TGT, "failed to read name %p",
		    (void *)rlp->rl_nameaddr);
		return (1); /* Keep going; forget this if we can't read name */
	}

	mdb_dprintf(MDB_DBG_TGT, "rd_loadobj name = \"%s\" rl_base = %p\n",
	    name, (void *)rlp->rl_base);

	if ((kpm = kp_addr_to_kpmap(kp, rlp->rl_base)) == NULL)
		return (1); /* Keep going; no mapping at this address */

	(void) strncpy(kpm->kpm_map.map_name, name, MDB_TGT_MAPSZ);
	kpm->kpm_map.map_name[MDB_TGT_MAPSZ - 1] = '\0';

	if ((kpf = kpm->kpm_file) == NULL) {
		if (kpm == kp->kp_map_exec)
			kpf = kp_file_create(t, kpm, ET_EXEC);
		else
			kpf = kp_file_create(t, kpm, ET_DYN);

		if (kpf == NULL)
			return (1); /* Keep going; failed to build ELF file */
	} else
		kpf->kpf_basename = strbasename(kpm->kpm_map.map_name);

	if ((kpm = kp_find_data(kp, kpf, rlp)) != NULL) {
		mdb_dprintf(MDB_DBG_TGT, "found data for %s at %p\n",
		    kpf->kpf_basename, (void *)kpm->kpm_map.map_base);
		kpm->kpm_file = kpf;
	}

	return (1);
}
Example #9
0
void
kmdb_dpi_set_state(int state, int why)
{
	if (kmdb_dpi_state != DPI_STATE_LOST) {
		mdb_dprintf(MDB_DBG_DPI, "dpi_set_state %d why %d\n",
		    state, why);

		kmdb_dpi_state = state;
		kmdb_dpi_state_why = why;
	}
}
Example #10
0
int
kmdb_dpi_wapt_reserve(kmdb_wapt_t *wp)
{
	if (mdb.m_dpi->dpo_wapt_reserve(wp) < 0)
		return (-1); /* errno is set for us */

	mdb_dprintf(MDB_DBG_DPI, "wapt reserve type %d at %p, priv %p\n",
	    wp->wp_type, (void *)wp->wp_addr, wp->wp_priv);

	return (0);
}
Example #11
0
void
mdb_intr_enable(void)
{
	ASSERT(mdb.m_intr >= 1);
	if (mdb.m_intr == 1 && mdb.m_pend != 0) {
		(void) mdb_signal_block(SIGINT);
		mdb.m_intr = mdb.m_pend = 0;
		mdb_dprintf(MDB_DBG_DSTK, "delivering pending INT\n");
		longjmp(mdb.m_frame->f_pcb, MDB_ERR_SIGINT);
	} else
		mdb.m_intr--;
}
Example #12
0
static kp_file_t *
kp_file_create(mdb_tgt_t *t, kp_map_t *kpm, GElf_Half etype)
{
	kp_file_t *kpf = mdb_zalloc(sizeof (kp_file_t), UM_SLEEP);
	kp_data_t *kp = t->t_data;
	size_t dyns_sz;
	void *dyns;

	kpf->kpf_fio = kp_io_create(t, kpm);
	kpf->kpf_map = kpm;
	kpf->kpf_basename = strbasename(kpm->kpm_map.map_name);
	kpf->kpf_file = mdb_gelf_create(kpf->kpf_fio, etype, GF_PROGRAM);
	kpf->kpf_text_base = kpm->kpm_map.map_base;

	if (kpm != kp->kp_map_exec)
		kpf->kpf_dyn_base = kpf->kpf_text_base;

	if (kpf->kpf_file == NULL)
		goto err; /* Failed to create ELF file */

	mdb_dprintf(MDB_DBG_TGT, "loading symbols for %s\n",
	    kpm->kpm_map.map_name);

	if ((kp->kp_rap != NULL) && (rd_get_dyns(kp->kp_rap,
	    kpf->kpf_text_base, &dyns, &dyns_sz) == RD_OK))
		mdb_gelf_dyns_set(kpf->kpf_file, dyns, dyns_sz);

	kpf->kpf_dynsym = mdb_gelf_symtab_create_dynamic(kpf->kpf_file,
	    MDB_TGT_DYNSYM);

	if (kpf->kpf_dynsym == NULL)
		goto err; /* Failed to create symbol table */

	kpm->kpm_file = kpf;

	if (kp->kp_file_tail != NULL)
		kp->kp_file_tail->kpf_next = kpf;
	else
		kp->kp_file_head = kpf;

	kp->kp_file_tail = kpf;
	kp->kp_num_files++;

	return (kpf);

err:
	if (kpf->kpf_file != NULL)
		mdb_gelf_destroy(kpf->kpf_file);
	else
		mdb_io_destroy(kpf->kpf_fio);
	mdb_free(kpf, sizeof (kp_file_t));
	return (NULL);
}
Example #13
0
int
kmdb_dpi_brkpt_arm(uintptr_t addr, mdb_instr_t *instrp)
{
	int rc;

	if ((rc = mdb.m_dpi->dpo_brkpt_arm(addr, instrp)) < 0)
		mdb_warn("failed to arm breakpoint at %a", addr);

	mdb_dprintf(MDB_DBG_DPI, "brkpt armed at %p %A\n", (void *)addr, addr);

	return (rc);
}
Example #14
0
/*
 * The read-side of the pipe executes this service routine.  We simply call
 * mdb_run to create a new frame on the execution stack and run the MDB parser,
 * and then propagate any error code back to the previous frame.
 */
static int
runsvc(void)
{
	int err = mdb_run();

	if (err != 0) {
		mdb_dprintf(MDB_DBG_DSTK, "forwarding error %s from pipeline\n",
		    mdb_err2str(err));
		longjmp(mdb.m_frame->f_pcb, err);
	}

	return (err);
}
Example #15
0
void
mdb_vcb_insert(mdb_vcb_t *vcb, mdb_frame_t *fp)
{
	if (fp->f_pcmd != NULL) {
		mdb_cmd_t *cp = fp->f_pcmd;

		mdb_dprintf(MDB_DBG_DSTK, "insert vcb %p (%s)\n",
		    (void *)vcb, mdb_nv_get_name(vcb->vc_var));

		ASSERT(vcb->vc_link == NULL);
		vcb->vc_link = cp->c_vcbs;
		cp->c_vcbs = vcb;
	}
}
Example #16
0
void
mdb_recycle(mdb_mblk_t **blkpp)
{
	mdb_mblk_t *blkp, *nblkp;

	for (blkp = *blkpp; blkp != NULL; blkp = nblkp) {
		mdb_dprintf(MDB_DBG_UMEM,
		    "garbage collect %p size %lu bytes\n", blkp->blk_addr,
		    (ulong_t)blkp->blk_size);

		nblkp = blkp->blk_next;
		mdb_free(blkp->blk_addr, blkp->blk_size);
		mdb_free(blkp, sizeof (mdb_mblk_t));
	}

	*blkpp = NULL;
}
/*ARGSUSED*/
int
kmdb_prom_translate_virt(uintptr_t virt, physaddr_t *pap)
{
	extern int prom_translate_virt(caddr_t, int *, u_longlong_t *, int *);

	int valid, mode;
	uintptr_t vabase = virt & ~(mdb.m_pagesize - 1);
	uintptr_t off = virt - vabase;
	u_longlong_t pa;

	mdb_dprintf(MDB_DBG_DPI, "using OBP for vtop of %p\n", (void *)virt);

	if (prom_translate_virt((caddr_t)vabase, &valid, &pa, &mode) != 0)
		return (set_errno(EMDB_NOMAP));

	*pap = pa + off;
	return (0);
}
Example #18
0
static int
kmdb_dbgnotify_cb(kmdb_wr_t *wn, void *arg)
{
	work_results_t *res = arg;

	switch (WR_TASK(wn)) {
	case WNTASK_DMOD_LOAD: {
		/*
		 * If this is an ack, the driver finished processing a load we
		 * requested.  We process it and free the message.  If this
		 * isn't an ack, then it's a driver-initiated load.  We process
		 * the message, and send it back as an ack so the driver can
		 * free it.
		 */
		kmdb_wr_load_t *dlr = (kmdb_wr_load_t *)wn;

		mdb_dprintf(MDB_DBG_DPI, "received module load message\n");

		if (kmdb_module_loaded(dlr) && res != NULL) {
			(void) mdb_nv_insert(&res->res_loads,
			    strbasename(dlr->dlr_fname), NULL, 0, 0);
		}

		if (WR_ISACK(dlr)) {
			kmdb_module_load_ack(dlr);
			return (0);
		}

		/* Send it back as an ack */
		mdb_dprintf(MDB_DBG_DPI, "Sending load request for %s back "
		    "as an ack\n", dlr->dlr_fname);
		WR_ACK(wn);
		kmdb_wr_driver_notify(wn);
		return (0);
	}

	case WNTASK_DMOD_LOAD_ALL:
		/*
		 * We initiated the load-all, so this must be an ack.  The
		 * individual module load messages will arrive separately -
		 * there's no need to do anything further with this message.
		 */
		ASSERT(WR_ISACK(wn));

		mdb_dprintf(MDB_DBG_DPI, "received module load all ack\n");

		kmdb_module_load_all_ack(wn);
		return (0);

	case WNTASK_DMOD_UNLOAD: {
		/*
		 * The debugger received an unload message.  The driver isn't
		 * supposed to initiate unloads, so we shouldn't see anything
		 * but acks.  We tell the dmod subsystem that the module has
		 * been unloaded, and we free the message.
		 */
		kmdb_wr_unload_t *dur = (kmdb_wr_unload_t *)wn;

		ASSERT(WR_ISACK(dur));

		mdb_dprintf(MDB_DBG_DPI, "received module unload ack\n");

		if (kmdb_module_unloaded(dur) && res != NULL) {
			(void) mdb_nv_insert(&res->res_unloads,
			    dur->dur_modname, NULL, 0, 0);
		}

		/* Done with message */
		kmdb_module_unload_ack(dur);
		return (0);
	}

	case WNTASK_DMOD_PATH_CHANGE: {
		/*
		 * The debugger received a path change message.  The driver
		 * can't initiate these, so it must be an acknowledgement.
		 * There's no processing to be done, so just free the message.
		 */
		kmdb_wr_path_t *dpth = (kmdb_wr_path_t *)wn;

		ASSERT(WR_ISACK(dpth));

		mdb_dprintf(MDB_DBG_DPI, "received path change ack\n");

		kmdb_module_path_ack(dpth);
		return (0);
	}

	default:
		mdb_warn("Received unknown message type %d from driver\n",
		    wn->wn_task);
		/* Ignore it */
		return (0);
	}
}
Example #19
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);
}
Example #20
0
static int
pio_ctl(mdb_io_t *io, int req, void *arg)
{
	pio_data_t *pdp = io->io_data;

	if (io->io_next != NULL)
		return (IOP_CTL(io->io_next, req, arg));

	switch (req) {
	case TIOCGWINSZ:
		return (kmdb_prom_term_ctl(TIOCGWINSZ, arg));

	case TCGETS: {
		struct termios *ti = arg;

		if (!(pdp->pio_flags & PIO_FL_TIO_READ)) {
			(void) kmdb_prom_term_ctl(TCGETS, &pdp->pio_ti);
			pdp->pio_flags |= PIO_FL_TIO_READ;
		}

		bcopy(&pdp->pio_ti, ti, sizeof (struct termios));

		mdb_dprintf(MDB_DBG_CMDBUF, "pio_ctl: gets: i: 0%o o: 0%o c: "
		    "0%o l: 0%o\n", ti->c_iflag, ti->c_oflag, ti->c_cflag,
		    ti->c_lflag);
		return (0);
	}

	case TCSETSW: {
		struct termios *ti = arg;

		mdb_dprintf(MDB_DBG_CMDBUF, "pio_ctl: setsw: i: 0%o o: 0%o c: "
		    "0%o l: 0%o\n", ti->c_iflag, ti->c_oflag, ti->c_cflag,
		    ti->c_lflag);

		bcopy(ti, &pdp->pio_ti, sizeof (struct termios));

		return (0);
	}

	case TIOCSPGRP:
		pio_pgrp = *(pid_t *)arg;
		mdb_dprintf(MDB_DBG_CMDBUF, "pio_ctl: spgrp: %ld\n",
		    (long)pio_pgrp);
		return (0);

	case TIOCGPGRP:
		mdb_dprintf(MDB_DBG_CMDBUF, "pio_ctl: gpgrp: %ld\n",
		    (long)pio_pgrp);
		*(pid_t *)arg = pio_pgrp;
		return (0);

	case MDB_IOC_CTTY:
		mdb_dprintf(MDB_DBG_CMDBUF, "pio_ctl: ignoring MDB_IOC_CTTY\n");
		return (0);

	case MDB_IOC_GETFD:
		return (set_errno(ENOTSUP));

	default:
		warn("Unknown ioctl %d\n", req);
		return (set_errno(EINVAL));
	}
}
Example #21
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);
}
Example #22
0
static void
kt_load_modules(kt_data_t *kt, mdb_tgt_t *t)
{
	char name[MAXNAMELEN];
	uintptr_t addr, head;

	struct module kmod;
	struct modctl ctl;
	Shdr symhdr, strhdr;
	GElf_Sym sym;

	kt_module_t *km;

	if (mdb_tgt_lookup_by_name(t, MDB_TGT_OBJ_EXEC,
	    "modules", &sym, NULL) == -1) {
		warn("failed to get 'modules' symbol");
		return;
	}

	if (mdb_tgt_readsym(t, MDB_TGT_AS_VIRT, &ctl, sizeof (ctl),
	    MDB_TGT_OBJ_EXEC, "modules") != sizeof (ctl)) {
		warn("failed to read 'modules' struct");
		return;
	}

	addr = head = (uintptr_t)sym.st_value;

	do {
		if (addr == NULL)
			break; /* Avoid spurious NULL pointers in list */

		if (mdb_tgt_vread(t, &ctl, sizeof (ctl), addr) == -1) {
			warn("failed to read modctl at %p", (void *)addr);
			return;
		}

		if (ctl.mod_mp == NULL)
			continue; /* No associated krtld structure */

		if (mdb_tgt_readstr(t, MDB_TGT_AS_VIRT, name, MAXNAMELEN,
		    (uintptr_t)ctl.mod_modname) <= 0) {
			warn("failed to read module name at %p",
			    (void *)ctl.mod_modname);
			continue;
		}

		mdb_dprintf(MDB_DBG_KMOD, "reading mod %s (%p)\n",
		    name, (void *)addr);

		if (mdb_nv_lookup(&kt->k_modules, name) != NULL) {
			warn("skipping duplicate module '%s', id=%d\n",
			    name, ctl.mod_id);
			continue;
		}

		if (mdb_tgt_vread(t, &kmod, sizeof (kmod),
		    (uintptr_t)ctl.mod_mp) == -1) {
			warn("failed to read module at %p\n",
			    (void *)ctl.mod_mp);
			continue;
		}

		if (kmod.symspace == NULL || kmod.symhdr == NULL ||
		    kmod.strhdr == NULL) {
			/*
			 * If no buffer for the symbols has been allocated,
			 * or the shdrs for .symtab and .strtab are missing,
			 * then we're out of luck.
			 */
			continue;
		}

		if (mdb_tgt_vread(t, &symhdr, sizeof (Shdr),
		    (uintptr_t)kmod.symhdr) == -1) {
			warn("failed to read .symtab header for '%s', id=%d",
			    name, ctl.mod_id);
			continue;
		}

		if (mdb_tgt_vread(t, &strhdr, sizeof (Shdr),
		    (uintptr_t)kmod.strhdr) == -1) {
			warn("failed to read .strtab header for '%s', id=%d",
			    name, ctl.mod_id);
			continue;
		}

		/*
		 * Now get clever: f(*^ing krtld didn't used to bother updating
		 * its own kmod.symsize value.  We know that prior to this bug
		 * being fixed, symspace was a contiguous buffer containing
		 * .symtab, .strtab, and the symbol hash table in that order.
		 * So if symsize is zero, recompute it as the size of .symtab
		 * plus the size of .strtab.  We don't need to load the hash
		 * table anyway since we re-hash all the symbols internally.
		 */
		if (kmod.symsize == 0)
			kmod.symsize = symhdr.sh_size + strhdr.sh_size;

		/*
		 * Similar logic can be used to make educated guesses
		 * at the values of kmod.symtbl and kmod.strings.
		 */
		if (kmod.symtbl == NULL)
			kmod.symtbl = kmod.symspace;
		if (kmod.strings == NULL)
			kmod.strings = kmod.symspace + symhdr.sh_size;

		/*
		 * Make sure things seem reasonable before we proceed
		 * to actually read and decipher the symspace.
		 */
		if (KT_BAD_BUF(kmod.symtbl, kmod.symspace, kmod.symsize) ||
		    KT_BAD_BUF(kmod.strings, kmod.symspace, kmod.symsize)) {
			warn("skipping module '%s', id=%d (corrupt symspace)\n",
			    name, ctl.mod_id);
			continue;
		}

		km = mdb_zalloc(sizeof (kt_module_t), UM_SLEEP);
		km->km_name = strdup(name);

		(void) mdb_nv_insert(&kt->k_modules, km->km_name, NULL,
		    (uintptr_t)km, MDB_NV_EXTNAME);

		km->km_datasz = kmod.symsize;
		km->km_symspace_va = (uintptr_t)kmod.symspace;
		km->km_symtab_va = (uintptr_t)kmod.symtbl;
		km->km_strtab_va = (uintptr_t)kmod.strings;
		km->km_symtab_hdr = symhdr;
		km->km_strtab_hdr = strhdr;
		km->km_text_va = (uintptr_t)kmod.text;
		km->km_text_size = kmod.text_size;
		km->km_data_va = (uintptr_t)kmod.data;
		km->km_data_size = kmod.data_size;
		km->km_bss_va = (uintptr_t)kmod.bss;
		km->km_bss_size = kmod.bss_size;

		if (kt->k_ctfvalid) {
			km->km_ctf_va = (uintptr_t)kmod.ctfdata;
			km->km_ctf_size = kmod.ctfsize;
		}

		/*
		 * Add the module to the end of the list of modules in load-
		 * dependency order.  This is needed to load the corresponding
		 * debugger modules in the same order for layering purposes.
		 */
		mdb_list_append(&kt->k_modlist, km);

		if (t->t_flags & MDB_TGT_F_PRELOAD) {
			mdb_iob_printf(mdb.m_out, " %s", name);
			mdb_iob_flush(mdb.m_out);
			kt_load_module(kt, t, km);
		}

	} while ((addr = (uintptr_t)ctl.mod_next) != head);
}
Example #23
0
/*ARGSUSED*/
int
mdb_module_unload(const char *name, int mode)
{
    kmdb_modctl_t *kmc = NULL;
    const char *basename;
    mdb_var_t *v;

    /*
     * We may have been called with the name from the module itself
     * if the caller is iterating through the module list, so we need
     * to make a copy of the name.  If we don't, we can't use it after
     * the call to unload_common(), which frees the module.
     */
    name = strdup(name);
    basename = strbasename(name);

    /*
     * Make sure the module is in the proper state for unloading.  Modules
     * may only be unloaded if they have properly completed loading.
     */
    if ((v = mdb_nv_lookup(&mdb.m_dmodctl, basename)) != NULL) {
        kmc = MDB_NV_COOKIE(v);
        switch (kmc->kmc_state) {
        case KMDB_MC_STATE_LOADING:
            warn("%s is in the process of loading\n", basename);
            return (set_errno(EMDB_NOMOD));
        case KMDB_MC_STATE_UNLOADING:
            warn("%s is already being unloaded\n", basename);
            return (set_errno(EMDB_NOMOD));
        default:
            ASSERT(kmc->kmc_state == KMDB_MC_STATE_LOADED);
        }

        if (kmc->kmc_flags & KMDB_MC_FL_NOUNLOAD)
            return (set_errno(EMDB_KMODNOUNLOAD));
    }

    if (mdb_module_unload_common(name) < 0) {
        if (!(mode & MDB_MOD_SILENT)) {
            mdb_dprintf(MDB_DBG_MODULE, "unload of %s failed\n",
                        name);
        }
        return (-1); /* errno is set for us */
    }

    /*
     * Any modules legitimately not listed in dmodctl (builtins, for
     * example) will be handled by mdb_module_unload_common.  If any of
     * them get here, we've got a problem.
     */
    if (v == NULL) {
        warn("unload of unregistered module %s\n", basename);
        return (set_errno(EMDB_NOMOD));
    }

    ASSERT(kmc->kmc_dlrefcnt == 0);

    mdb_gelf_symtab_destroy(kmc->kmc_symtab);

    kmdb_module_request_unload(kmc, basename, mode);
    return (0);
}