Beispiel #1
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);
}
/*ARGSUSED*/
void
exit(int status)
{
#ifdef __sparc
	extern void kmdb_prom_exit_to_mon(void) __NORETURN;

	kmdb_prom_exit_to_mon();
#else
	extern void kmdb_dpi_reboot(void) __NORETURN;
	static int recurse = 0;

	if (!recurse) {

		recurse = 1;

		mdb_iob_printf(mdb.m_out, "Press any key to reboot\n");
		mdb_iob_flush(mdb.m_out);
		mdb_iob_clearlines(mdb.m_out);

		(void) kmdb_getchar();
	}

	kmdb_dpi_reboot();
#endif
}
Beispiel #3
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);
}
Beispiel #4
0
/*
 * Called during normal debugger operation and during debugger faults.
 */
static void
kaif_enter_mon(void)
{
	char c;

	for (;;) {
		mdb_iob_printf(mdb.m_out,
		    "%s: Do you really want to reboot? (y/n) ",
		    mdb.m_pname);
		mdb_iob_flush(mdb.m_out);
		mdb_iob_clearlines(mdb.m_out);

		c = kmdb_getchar();

		if (c == 'n' || c == 'N' || c == CTRL('c'))
			return;
		else if (c == 'y' || c == 'Y') {
			mdb_iob_printf(mdb.m_out, "Rebooting...\n");

			kmdb_dpi_reboot();
		}
	}
}
Beispiel #5
0
void
mdb_flush(void)
{
	mdb_iob_flush(mdb.m_out);
}
Beispiel #6
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);
}
Beispiel #7
0
void
kt_activate(mdb_tgt_t *t)
{
	static const mdb_nv_disc_t reg_disc = { NULL, reg_disc_get };
	kt_data_t *kt = t->t_data;
	void *sym;

	int oflag;

	mdb_prop_postmortem = (kt->k_dumphdr != NULL);
	mdb_prop_kernel = TRUE;
	mdb_prop_datamodel = MDB_TGT_MODEL_NATIVE;

	if (kt->k_activated == FALSE) {
		struct utsname u1, u2;
		/*
		 * If we're examining a crash dump, root is /, and uname(2)
		 * does not match the utsname in the dump, issue a warning.
		 * Note that we are assuming that the modules and macros in
		 * /usr/lib are compiled against the kernel from uname -rv.
		 */
		if (mdb_prop_postmortem && strcmp(mdb.m_root, "/") == 0 &&
		    uname(&u1) >= 0 && kt_uname(t, &u2) >= 0 &&
		    (strcmp(u1.release, u2.release) ||
		    strcmp(u1.version, u2.version))) {
			mdb_warn("warning: dump is from %s %s %s; dcmds and "
			    "macros may not match kernel implementation\n",
			    u2.sysname, u2.release, u2.version);
		}

		if (mdb_module_load(KT_MODULE, MDB_MOD_GLOBAL) < 0) {
			warn("failed to load kernel support module -- "
			    "some modules may not load\n");
		}

		if (mdb_prop_postmortem) {
			sym = dlsym(RTLD_NEXT, "mdb_dump_print_content");
			if (sym != NULL)
				kt->k_dump_print_content = (void (*)())sym;

			sym = dlsym(RTLD_NEXT, "mdb_dump_find_curproc");
			if (sym != NULL)
				kt->k_dump_find_curproc = (int (*)())sym;

			kt->k_dumpcontent = kt_find_dump_contents(kt);
		}

		if (t->t_flags & MDB_TGT_F_PRELOAD) {
			oflag = mdb_iob_getflags(mdb.m_out) & MDB_IOB_PGENABLE;

			mdb_iob_clrflags(mdb.m_out, oflag);
			mdb_iob_puts(mdb.m_out, "Preloading module symbols: [");
			mdb_iob_flush(mdb.m_out);
		}

		if (!(t->t_flags & MDB_TGT_F_NOLOAD))
			kt_load_modules(kt, t);

		if (t->t_flags & MDB_TGT_F_PRELOAD) {
			mdb_iob_puts(mdb.m_out, " ]\n");
			mdb_iob_setflags(mdb.m_out, oflag);
		}

		kt->k_activated = TRUE;
	}

	(void) mdb_tgt_register_dcmds(t, &kt_dcmds[0], MDB_MOD_FORCE);

	/* Export some of our registers as named variables */
	mdb_tgt_register_regvars(t, kt->k_rds, &reg_disc, MDB_NV_RDONLY);

	mdb_tgt_elf_export(kt->k_file);
}
Beispiel #8
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);
}
Beispiel #9
0
/*ARGSUSED*/
static void
flt_handler(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
{
	static const struct rlimit rl = {
		(rlim_t)RLIM_INFINITY, (rlim_t)RLIM_INFINITY
	};

	const mdb_idcmd_t *idcp = NULL;

	if (mdb.m_frame != NULL && mdb.m_frame->f_cp != NULL)
		idcp = mdb.m_frame->f_cp->c_dcmd;

	if (sip != NULL)
		bcopy(sip, &_mdb_abort_info, sizeof (_mdb_abort_info));
	if (ucp != NULL)
		bcopy(ucp, &_mdb_abort_ctx, sizeof (_mdb_abort_ctx));

	_mdb_abort_info.si_signo = sig;
	(void) mdb_signal_sethandler(sig, SIG_DFL, NULL);

	/*
	 * If there is no current dcmd, or the current dcmd comes from a
	 * builtin module, we don't allow resume and always core dump.
	 */
	if (idcp == NULL || idcp->idc_modp == NULL ||
	    idcp->idc_modp == &mdb.m_rmod || idcp->idc_modp->mod_hdl == NULL)
		goto dump;

	if (mdb.m_term != NULL) {
		struct frame *fr = (struct frame *)
		    (ucp->uc_mcontext.gregs[STACK_REGISTER] + STACK_BIAS);

		char signame[SIG2STR_MAX];
		int i = 1;
		char c;

		if (sig2str(sig, signame) == -1) {
			mdb_iob_printf(mdb.m_err,
			    "\n*** %s: received signal %d at:\n",
			    mdb.m_pname, sig);
		} else {
			mdb_iob_printf(mdb.m_err,
			    "\n*** %s: received signal %s at:\n",
			    mdb.m_pname, signame);
		}

		if (ucp->uc_mcontext.gregs[REG_PC] != 0)
			print_frame(ucp->uc_mcontext.gregs[REG_PC], i++);

		while (fr != NULL && valid_frame(fr) && fr->fr_savpc != 0) {
			print_frame(fr->fr_savpc, i++);
			fr = (struct frame *)
			    ((uintptr_t)fr->fr_savfp + STACK_BIAS);
		}

query:
		mdb_iob_printf(mdb.m_err, "\n%s: (c)ore dump, (q)uit, "
		    "(r)ecover, or (s)top for debugger [cqrs]? ", mdb.m_pname);

		mdb_iob_flush(mdb.m_err);

		for (;;) {
			if (IOP_READ(mdb.m_term, &c, sizeof (c)) != sizeof (c))
				goto dump;

			switch (c) {
			case 'c':
			case 'C':
				(void) setrlimit(RLIMIT_CORE, &rl);
				mdb_iob_printf(mdb.m_err, "\n%s: attempting "
				    "to dump core ...\n", mdb.m_pname);
				goto dump;

			case 'q':
			case 'Q':
				mdb_iob_discard(mdb.m_out);
				mdb_iob_nl(mdb.m_err);
				(void) mdb_signal_unblockall();
				terminate(1);
				/*NOTREACHED*/

			case 'r':
			case 'R':
				mdb_iob_printf(mdb.m_err, "\n%s: unloading "
				    "module '%s' ...\n", mdb.m_pname,
				    idcp->idc_modp->mod_name);

				(void) mdb_module_unload(
				    idcp->idc_modp->mod_name, 0);

				(void) mdb_signal_sethandler(sig,
				    flt_handler, NULL);

				_mdb_abort_rcount++;
				mdb.m_intr = 0;
				mdb.m_pend = 0;

				(void) mdb_signal_unblockall();
				longjmp(mdb.m_frame->f_pcb, MDB_ERR_ABORT);
				/*NOTREACHED*/

			case 's':
			case 'S':
				mdb_iob_printf(mdb.m_err, "\n%s: "
				    "attempting to stop pid %d ...\n",
				    mdb.m_pname, (int)getpid());

				/*
				 * Stop ourself; if this fails or we are
				 * subsequently continued, ask again.
				 */
				(void) mdb_signal_raise(SIGSTOP);
				(void) mdb_signal_unblockall();
				goto query;
			}
		}
	}

dump:
	if (SI_FROMUSER(sip)) {
		(void) mdb_signal_block(sig);
		(void) mdb_signal_raise(sig);
	}

	(void) sigfillset(&ucp->uc_sigmask);
	(void) sigdelset(&ucp->uc_sigmask, sig);

	if (_mdb_abort_str == NULL)
		_mdb_abort_str = "fatal signal received";

	ucp->uc_flags |= UC_SIGMASK;
	(void) setcontext(ucp);
}
Beispiel #10
0
/*ARGSUSED*/
static void *
mdb_umem_handler(size_t nbytes, size_t align, uint_t flags)
{
#ifdef _KMDB

	/*
	 * kmdb has a fixed, dedicated VA range in which to play.  This range
	 * won't change size while the debugger is running, regardless of how
	 * long we wait.  As a result, the only sensible course of action is
	 * to fail the request.  If we're here, however, the request was made
	 * with UM_SLEEP.  The caller is thus not expecting a NULL back.  We'll
	 * have to fail the current dcmd set.
	 */
	if (mdb.m_depth > 0) {
		warn("failed to allocate %lu bytes -- recovering\n",
		    (ulong_t)nbytes);

		kmdb_print_stack();

		longjmp(mdb.m_frame->f_pcb, MDB_ERR_NOMEM);
	}

#else

	/*
	 * mdb, on the other hand, can afford to wait, as someone may actually
	 * free something.
	 */
	if (errno == EAGAIN) {
		void *ptr = NULL;
		char buf[64];

		(void) mdb_iob_snprintf(buf, sizeof (buf),
		    "[ sleeping for %lu bytes of free memory ... ]",
		    (ulong_t)nbytes);

		(void) mdb_iob_puts(mdb.m_err, buf);
		(void) mdb_iob_flush(mdb.m_err);

		do {
			(void) poll(NULL, 0, 1000);
			if (align != 0)
				ptr = memalign(align, nbytes);
			else
				ptr = malloc(nbytes);
		} while (ptr == NULL && errno == EAGAIN);

		if (ptr != NULL)
			return (ptr);

		(void) memset(buf, '\b', strlen(buf));
		(void) mdb_iob_puts(mdb.m_err, buf);
		(void) mdb_iob_flush(mdb.m_err);

		(void) memset(buf, ' ', strlen(buf));
		(void) mdb_iob_puts(mdb.m_err, buf);
		(void) mdb_iob_flush(mdb.m_err);

		(void) memset(buf, '\b', strlen(buf));
		(void) mdb_iob_puts(mdb.m_err, buf);
		(void) mdb_iob_flush(mdb.m_err);
	}
#endif

	die("failed to allocate %lu bytes -- terminating\n", (ulong_t)nbytes);

	/*NOTREACHED*/

	return (NULL);
}