예제 #1
0
void
mdb_dcmd_usage(const mdb_idcmd_t *idcp, mdb_iob_t *iob)
{
	const char *prefix = "", *usage = "";
	char name0 = idcp->idc_name[0];

	if (idcp->idc_usage != NULL) {
		if (idcp->idc_usage[0] == ':') {
			if (name0 != ':' && name0 != '$')
				prefix = "address::";
			else
				prefix = "address";
			usage = &idcp->idc_usage[1];

		} else if (idcp->idc_usage[0] == '?') {
			if (name0 != ':' && name0 != '$')
				prefix = "[address]::";
			else
				prefix = "[address]";
			usage = &idcp->idc_usage[1];

		} else
			usage = idcp->idc_usage;
	}

	mdb_iob_printf(iob, "Usage: %s%s %s\n", prefix, idcp->idc_name, usage);

	if (idcp->idc_help != NULL) {
		mdb_iob_printf(iob, "%s: try '::help %s' for more "
		    "information\n", mdb.m_pname, idcp->idc_name);
	}
}
예제 #2
0
void
vwarn(const char *format, va_list alist)
{
	int err = errno;

	mdb_iob_printf(mdb.m_err, "%s: ", mdb.m_pname);
	mdb_iob_vprintf(mdb.m_err, format, alist);

	if (strchr(format, '\n') == NULL)
		mdb_iob_printf(mdb.m_err, ": %s\n", mdb_strerror(err));
}
예제 #3
0
파일: mdb_main.c 프로젝트: kele/illumos-fsd
static void
print_frame(uintptr_t pc, int fnum)
{
	Dl_info dli;

	if (dladdr((void *)pc, &dli)) {
		mdb_iob_printf(mdb.m_err, "    [%d] %s`%s+0x%lx()\n", fnum,
		    strbasename(dli.dli_fname), dli.dli_sname,
		    pc - (uintptr_t)dli.dli_saddr);
	} else
		mdb_iob_printf(mdb.m_err, "    [%d] %p()\n", fnum, pc);
}
예제 #4
0
char
kmdb_getchar(void)
{
	char c;

	while (IOP_READ(mdb.m_term, &c, 1) != 1)
		continue;
	if (isprint(c) && c != '\n')
		mdb_iob_printf(mdb.m_out, "%c", c);
	mdb_iob_printf(mdb.m_out, "\n");

	return (c);
}
예제 #5
0
/*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
}
예제 #6
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);
}
예제 #7
0
파일: mdb_main.c 프로젝트: kele/illumos-fsd
static void
usage(int status)
{
	mdb_iob_printf(mdb.m_err, "Usage: %s [-fkmuwyAFKMSUW] [+/-o option] "
	    "[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
	    "[-R root] [-V dis-version] [object [core] | core | suffix]\n\n",
	    mdb.m_pname);

	mdb_iob_puts(mdb.m_err,
	    "\t-f force raw file debugging mode\n"
	    "\t-k force kernel debugging mode\n"
	    "\t-m disable demand-loading of module symbols\n"
	    "\t-o set specified debugger option (+o to unset)\n"
	    "\t-p attach to specified process-id\n"
	    "\t-s set symbol matching distance\n"
	    "\t-u force user program debugging mode\n"
	    "\t-w enable write mode\n"
	    "\t-y send terminal initialization sequences for tty mode\n"
	    "\t-A disable automatic loading of mdb modules\n"
	    "\t-F enable forcible takeover mode\n"
	    "\t-K stop operating system and enter live kernel debugger\n"
	    "\t-M preload all module symbols\n"
	    "\t-I set initial path for macro files\n"
	    "\t-L set initial path for module libs\n"
	    "\t-P set command-line prompt\n"
	    "\t-R set root directory for pathname expansion\n"
	    "\t-S suppress processing of ~/.mdbrc file\n"
	    "\t-U unload live kernel debugger\n"
	    "\t-W enable I/O-mapped memory access (kernel only)\n"
	    "\t-V set disassembler version\n");

	terminate(status);
}
예제 #8
0
파일: mdb_main.c 프로젝트: kele/illumos-fsd
static int
valid_frame(struct frame *fr)
{
	static struct frame fake;
	uintptr_t addr = (uintptr_t)fr;

	if (pread(_mdb_self_fd, &fake, sizeof (fake), addr) != sizeof (fake)) {
		mdb_iob_printf(mdb.m_err, "    invalid frame (%p)\n", fr);
		return (0);
	}

	if (addr & (STACK_ALIGN - 1)) {
		mdb_iob_printf(mdb.m_err, "    mis-aligned frame (%p)\n", fr);
		return (0);
	}

	return (1);
}
예제 #9
0
int
cmd_nmadd(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
{
	uintptr_t opt_e = 0, opt_s = 0;
	uint_t opt_f = FALSE, opt_o = FALSE;

	GElf_Sym sym;
	int i;

	if (!(flags & DCMD_ADDRSPEC))
		return (DCMD_USAGE);

	i = mdb_getopts(argc, argv,
	    'f', MDB_OPT_SETBITS, TRUE, &opt_f,
	    'o', MDB_OPT_SETBITS, TRUE, &opt_o,
	    'e', MDB_OPT_UINTPTR, &opt_e,
	    's', MDB_OPT_UINTPTR, &opt_s, NULL);

	if (i != (argc - 1) || argv[i].a_type != MDB_TYPE_STRING ||
	    argv[i].a_un.a_str[0] == '-' || argv[i].a_un.a_str[0] == '+')
		return (DCMD_USAGE);

	if (opt_e && opt_e < addr) {
		mdb_warn("end (%p) is less than start address (%p)\n",
		    (void *)opt_e, (void *)addr);
		return (DCMD_USAGE);
	}

	if (mdb_gelf_symtab_lookup_by_name(mdb.m_prsym,
	    argv[i].a_un.a_str, &sym, NULL) == -1) {
		bzero(&sym, sizeof (sym));
		sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_NOTYPE);
	}

	if (opt_f)
		sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_FUNC);
	if (opt_o)
		sym.st_info = GELF_ST_INFO(STB_GLOBAL, STT_OBJECT);
	if (opt_e)
		sym.st_size = (GElf_Xword)(opt_e - addr);
	if (opt_s)
		sym.st_size = (GElf_Xword)(opt_s);
	sym.st_value = (GElf_Addr)addr;

	mdb_gelf_symtab_insert(mdb.m_prsym, argv[i].a_un.a_str, &sym);

	mdb_iob_printf(mdb.m_out, "added %s, value=%llr size=%llr\n",
	    argv[i].a_un.a_str, sym.st_value, sym.st_size);

	return (DCMD_OK);
}
예제 #10
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();
		}
	}
}
예제 #11
0
파일: mdb_kvm.c 프로젝트: andreiw/polaris
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);
}
예제 #12
0
파일: mdb_main.c 프로젝트: kele/illumos-fsd
int
main(int argc, char *argv[], char *envp[])
{
	extern int mdb_kvm_is_compressed_dump(mdb_io_t *);
	mdb_tgt_ctor_f *tgt_ctor = NULL;
	const char **tgt_argv = alloca(argc * sizeof (char *));
	int tgt_argc = 0;
	mdb_tgt_t *tgt;

	char object[MAXPATHLEN], execname[MAXPATHLEN];
	mdb_io_t *in_io, *out_io, *err_io, *null_io;
	struct termios tios;
	int status, c;
	char *p;

	const char *Iflag = NULL, *Lflag = NULL, *Vflag = NULL, *pidarg = NULL;
	int fflag = 0, Kflag = 0, Rflag = 0, Sflag = 0, Oflag = 0, Uflag = 0;

	int ttylike;
	int longmode = 0;

	stack_t sigstack;

	if (realpath(getexecname(), execname) == NULL) {
		(void) strncpy(execname, argv[0], MAXPATHLEN);
		execname[MAXPATHLEN - 1] = '\0';
	}

	mdb_create(execname, argv[0]);
	bzero(tgt_argv, argc * sizeof (char *));
	argv[0] = (char *)mdb.m_pname;
	_mdb_self_fd = open("/proc/self/as", O_RDONLY);

	mdb.m_env = envp;

	out_io = mdb_fdio_create(STDOUT_FILENO);
	mdb.m_out = mdb_iob_create(out_io, MDB_IOB_WRONLY);

	err_io = mdb_fdio_create(STDERR_FILENO);
	mdb.m_err = mdb_iob_create(err_io, MDB_IOB_WRONLY);
	mdb_iob_clrflags(mdb.m_err, MDB_IOB_AUTOWRAP);

	null_io = mdb_nullio_create();
	mdb.m_null = mdb_iob_create(null_io, MDB_IOB_WRONLY);

	in_io = mdb_fdio_create(STDIN_FILENO);
	if ((mdb.m_termtype = getenv("TERM")) != NULL) {
		mdb.m_termtype = strdup(mdb.m_termtype);
		mdb.m_flags |= MDB_FL_TERMGUESS;
	}
	mdb.m_term = NULL;

	mdb_dmode(mdb_dstr2mode(getenv("MDB_DEBUG")));
	mdb.m_pgid = getpgrp();

	if (getenv("_MDB_EXEC") != NULL)
		mdb.m_flags |= MDB_FL_EXEC;

	/*
	 * Setup an alternate signal stack.  When tearing down pipelines in
	 * terminate(), we may have to destroy the stack of the context in
	 * which we are currently executing the signal handler.
	 */
	sigstack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
	    MAP_PRIVATE | MAP_ANON, -1, 0);
	if (sigstack.ss_sp == MAP_FAILED)
		die("could not allocate signal stack");
	sigstack.ss_size = SIGSTKSZ;
	sigstack.ss_flags = 0;
	if (sigaltstack(&sigstack, NULL) != 0)
		die("could not set signal stack");

	(void) mdb_signal_sethandler(SIGPIPE, SIG_IGN, NULL);
	(void) mdb_signal_sethandler(SIGQUIT, SIG_IGN, NULL);

	(void) mdb_signal_sethandler(SIGILL, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGTRAP, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGIOT, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGEMT, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGFPE, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGBUS, flt_handler, NULL);
	(void) mdb_signal_sethandler(SIGSEGV, flt_handler, NULL);

	(void) mdb_signal_sethandler(SIGHUP, (mdb_signal_f *)terminate, NULL);
	(void) mdb_signal_sethandler(SIGTERM, (mdb_signal_f *)terminate, NULL);

	for (mdb.m_rdvers = RD_VERSION; mdb.m_rdvers > 0; mdb.m_rdvers--) {
		if (rd_init(mdb.m_rdvers) == RD_OK)
			break;
	}

	for (mdb.m_ctfvers = CTF_VERSION; mdb.m_ctfvers > 0; mdb.m_ctfvers--) {
		if (ctf_version(mdb.m_ctfvers) != -1)
			break;
	}

	if ((p = getenv("HISTSIZE")) != NULL && strisnum(p)) {
		mdb.m_histlen = strtoi(p);
		if (mdb.m_histlen < 1)
			mdb.m_histlen = 1;
	}

	while (optind < argc) {
		while ((c = getopt(argc, argv,
		    "fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
			switch (c) {
			case 'f':
				fflag++;
				tgt_ctor = mdb_rawfile_tgt_create;
				break;
			case 'k':
				tgt_ctor = mdb_kvm_tgt_create;
				break;
			case 'm':
				mdb.m_tgtflags |= MDB_TGT_F_NOLOAD;
				mdb.m_tgtflags &= ~MDB_TGT_F_PRELOAD;
				break;
			case 'o':
				if (!mdb_set_options(optarg, TRUE))
					terminate(2);
				break;
			case 'p':
				tgt_ctor = mdb_proc_tgt_create;
				pidarg = optarg;
				break;
			case 's':
				if (!strisnum(optarg)) {
					warn("expected integer following -s\n");
					terminate(2);
				}
				mdb.m_symdist = (size_t)(uint_t)strtoi(optarg);
				break;
			case 'u':
				tgt_ctor = mdb_proc_tgt_create;
				break;
			case 'w':
				mdb.m_tgtflags |= MDB_TGT_F_RDWR;
				break;
			case 'y':
				mdb.m_flags |= MDB_FL_USECUP;
				break;
			case 'A':
				(void) mdb_set_options("nomods", TRUE);
				break;
			case 'C':
				(void) mdb_set_options("noctf", TRUE);
				break;
			case 'D':
				mdb_dmode(mdb_dstr2mode(optarg));
				break;
			case 'F':
				mdb.m_tgtflags |= MDB_TGT_F_FORCE;
				break;
			case 'I':
				Iflag = optarg;
				break;
			case 'L':
				Lflag = optarg;
				break;
			case 'K':
				Kflag++;
				break;
			case 'M':
				mdb.m_tgtflags |= MDB_TGT_F_PRELOAD;
				mdb.m_tgtflags &= ~MDB_TGT_F_NOLOAD;
				break;
			case 'O':
				Oflag++;
				break;
			case 'P':
				if (!mdb_set_prompt(optarg))
					terminate(2);
				break;
			case 'R':
				(void) strncpy(mdb.m_root, optarg, MAXPATHLEN);
				mdb.m_root[MAXPATHLEN - 1] = '\0';
				Rflag++;
				break;
			case 'S':
				Sflag++;
				break;
			case 'U':
				Uflag++;
				break;
			case 'V':
				Vflag = optarg;
				break;
			case 'W':
				mdb.m_tgtflags |= MDB_TGT_F_ALLOWIO;
				break;
			case '?':
				if (optopt == '?')
					usage(0);
				/* FALLTHROUGH */
			default:
				usage(2);
			}
		}

		if (optind < argc) {
			const char *arg = argv[optind++];

			if (arg[0] == '+' && strlen(arg) == 2) {
				if (arg[1] != 'o') {
					warn("illegal option -- %s\n", arg);
					terminate(2);
				}
				if (optind >= argc) {
					warn("option requires an argument -- "
					    "%s\n", arg);
					terminate(2);
				}
				if (!mdb_set_options(argv[optind++], FALSE))
					terminate(2);
			} else
				tgt_argv[tgt_argc++] = arg;
		}
	}

	if (rd_ctl(RD_CTL_SET_HELPPATH, (void *)mdb.m_root) != RD_OK) {
		warn("cannot set librtld_db helper path to %s\n", mdb.m_root);
		terminate(2);
	}

	if (mdb.m_debug & MDB_DBG_HELP)
		terminate(0); /* Quit here if we've printed out the tokens */


	if (Iflag != NULL && strchr(Iflag, ';') != NULL) {
		warn("macro path cannot contain semicolons\n");
		terminate(2);
	}

	if (Lflag != NULL && strchr(Lflag, ';') != NULL) {
		warn("module path cannot contain semicolons\n");
		terminate(2);
	}

	if (Kflag || Uflag) {
		char *nm;

		if (tgt_ctor != NULL || Iflag != NULL) {
			warn("neither -f, -k, -p, -u, nor -I "
			    "may be used with -K\n");
			usage(2);
		}

		if (Lflag != NULL)
			mdb_set_lpath(Lflag);

		if ((nm = ttyname(STDIN_FILENO)) == NULL ||
		    strcmp(nm, "/dev/console") != 0) {
			/*
			 * Due to the consequences of typing mdb -K instead of
			 * mdb -k on a tty other than /dev/console, we require
			 * -F when starting kmdb from a tty other than
			 * /dev/console.
			 */
			if (!(mdb.m_tgtflags & MDB_TGT_F_FORCE)) {
				die("-F must also be supplied to start kmdb "
				    "from non-console tty\n");
			}

			if (mdb.m_termtype == NULL || (mdb.m_flags &
			    MDB_FL_TERMGUESS)) {
				if (mdb.m_termtype != NULL)
					strfree(mdb.m_termtype);

				if ((mdb.m_termtype = mdb_scf_console_term()) !=
				    NULL)
					mdb.m_flags |= MDB_FL_TERMGUESS;
			}
		} else {
			/*
			 * When on console, $TERM (if set) takes precedence over
			 * the SMF setting.
			 */
			if (mdb.m_termtype == NULL && (mdb.m_termtype =
			    mdb_scf_console_term()) != NULL)
				mdb.m_flags |= MDB_FL_TERMGUESS;
		}

		control_kmdb(Kflag);
		terminate(0);
		/*NOTREACHED*/
	}

	/*
	 * If standard input appears to have tty attributes, attempt to
	 * initialize a terminal i/o backend on top of stdin and stdout.
	 */
	ttylike = (IOP_CTL(in_io, TCGETS, &tios) == 0);
	if (ttylike) {
		if ((mdb.m_term = mdb_termio_create(mdb.m_termtype,
		    in_io, out_io)) == NULL) {
			if (!(mdb.m_flags & MDB_FL_EXEC)) {
				warn("term init failed: command-line editing "
				    "and prompt will not be available\n");
			}
		} else {
			in_io = mdb.m_term;
		}
	}

	mdb.m_in = mdb_iob_create(in_io, MDB_IOB_RDONLY);
	if (mdb.m_term != NULL) {
		mdb_iob_setpager(mdb.m_out, mdb.m_term);
		if (mdb.m_flags & MDB_FL_PAGER)
			mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE);
		else
			mdb_iob_clrflags(mdb.m_out, MDB_IOB_PGENABLE);
	} else if (ttylike)
		mdb_iob_setflags(mdb.m_in, MDB_IOB_TTYLIKE);
	else
		mdb_iob_setbuf(mdb.m_in, mdb_alloc(1, UM_SLEEP), 1);

	mdb_pservice_init();
	mdb_lex_reset();

	if ((mdb.m_shell = getenv("SHELL")) == NULL)
		mdb.m_shell = "/bin/sh";

	/*
	 * If the debugger state is to be inherited from a previous instance,
	 * restore it now prior to path evaluation so that %R is updated.
	 */
	if ((p = getenv(MDB_CONFIG_ENV_VAR)) != NULL) {
		mdb_set_config(p);
		(void) unsetenv(MDB_CONFIG_ENV_VAR);
	}

	/*
	 * Path evaluation part 1: Create the initial module path to allow
	 * the target constructor to load a support module.  Then expand
	 * any command-line arguments that modify the paths.
	 */
	if (Iflag != NULL)
		mdb_set_ipath(Iflag);
	else
		mdb_set_ipath(MDB_DEF_IPATH);

	if (Lflag != NULL)
		mdb_set_lpath(Lflag);
	else
		mdb_set_lpath(MDB_DEF_LPATH);

	if (mdb_get_prompt() == NULL && !(mdb.m_flags & MDB_FL_ADB))
		(void) mdb_set_prompt(MDB_DEF_PROMPT);

	if (tgt_ctor == mdb_kvm_tgt_create) {
		if (pidarg != NULL) {
			warn("-p and -k options are mutually exclusive\n");
			terminate(2);
		}

		if (tgt_argc == 0)
			tgt_argv[tgt_argc++] = "/dev/ksyms";
		if (tgt_argc == 1 && strisnum(tgt_argv[0]) == 0) {
			if (mdb.m_tgtflags & MDB_TGT_F_ALLOWIO)
				tgt_argv[tgt_argc++] = "/dev/allkmem";
			else
				tgt_argv[tgt_argc++] = "/dev/kmem";
		}
	}

	if (pidarg != NULL) {
		if (tgt_argc != 0) {
			warn("-p may not be used with other arguments\n");
			terminate(2);
		}
		if (proc_arg_psinfo(pidarg, PR_ARG_PIDS, NULL, &status) == -1) {
			die("cannot attach to %s: %s\n",
			    pidarg, Pgrab_error(status));
		}
		if (strchr(pidarg, '/') != NULL)
			(void) mdb_iob_snprintf(object, MAXPATHLEN,
			    "%s/object/a.out", pidarg);
		else
			(void) mdb_iob_snprintf(object, MAXPATHLEN,
			    "/proc/%s/object/a.out", pidarg);
		tgt_argv[tgt_argc++] = object;
		tgt_argv[tgt_argc++] = pidarg;
	}

	/*
	 * Find the first argument that is not a special "-" token.  If one is
	 * found, we will examine this file and make some inferences below.
	 */
	for (c = 0; c < tgt_argc && strcmp(tgt_argv[c], "-") == 0; c++)
		continue;

	if (c < tgt_argc) {
		Elf32_Ehdr ehdr;
		mdb_io_t *io;

		/*
		 * If special "-" tokens preceded an argument, shift the entire
		 * argument list to the left to remove the leading "-" args.
		 */
		if (c > 0) {
			bcopy(&tgt_argv[c], tgt_argv,
			    sizeof (const char *) * (tgt_argc - c));
			tgt_argc -= c;
		}

		if (fflag)
			goto tcreate; /* skip re-exec and just create target */

		/*
		 * If we just have an object file name, and that file doesn't
		 * exist, and it's a string of digits, infer it to be a
		 * sequence number referring to a pair of crash dump files.
		 */
		if (tgt_argc == 1 && access(tgt_argv[0], F_OK) == -1 &&
		    strisnum(tgt_argv[0])) {

			size_t len = strlen(tgt_argv[0]) + 8;
			const char *object = tgt_argv[0];

			tgt_argv[0] = mdb_alloc(len, UM_SLEEP);
			tgt_argv[1] = mdb_alloc(len, UM_SLEEP);

			(void) strcpy((char *)tgt_argv[0], "unix.");
			(void) strcat((char *)tgt_argv[0], object);
			(void) strcpy((char *)tgt_argv[1], "vmcore.");
			(void) strcat((char *)tgt_argv[1], object);

			if (access(tgt_argv[0], F_OK) == -1 &&
			    access(tgt_argv[1], F_OK) == -1) {
				(void) strcpy((char *)tgt_argv[1], "vmdump.");
				(void) strcat((char *)tgt_argv[1], object);
				if (access(tgt_argv[1], F_OK) == 0) {
					mdb_iob_printf(mdb.m_err,
					    "cannot open compressed dump; "
					    "decompress using savecore -f %s\n",
					    tgt_argv[1]);
					terminate(0);
				}
			}

			tgt_argc = 2;
		}

		/*
		 * We need to open the object file in order to determine its
		 * ELF class and potentially re-exec ourself.
		 */
		if ((io = mdb_fdio_create_path(NULL, tgt_argv[0],
		    O_RDONLY, 0)) == NULL)
			die("failed to open %s", tgt_argv[0]);

		/*
		 * Check for a single vmdump.N compressed dump file,
		 * and give a helpful message.
		 */
		if (tgt_argc == 1) {
			if (mdb_kvm_is_compressed_dump(io)) {
				mdb_iob_printf(mdb.m_err,
				    "cannot open compressed dump; "
				    "decompress using savecore -f %s\n",
				    tgt_argv[0]);
				terminate(0);
			}
		}

		/*
		 * If the target is unknown or is not the rawfile target, do
		 * a gelf_check to determine if the file is an ELF file.  If
		 * it is not and the target is unknown, use the rawfile tgt.
		 * Otherwise an ELF-based target is needed, so we must abort.
		 */
		if (mdb_gelf_check(io, &ehdr, ET_NONE) == -1) {
			if (tgt_ctor != NULL) {
				(void) mdb_gelf_check(io, &ehdr, ET_EXEC);
				mdb_io_destroy(io);
				terminate(1);
			} else
				tgt_ctor = mdb_rawfile_tgt_create;
		}

		mdb_io_destroy(io);

		if (identify_xvm_file(tgt_argv[0], &longmode) == 1) {
#ifdef _LP64
			if (!longmode)
				goto reexec;
#else
			if (longmode)
				goto reexec;
#endif
			tgt_ctor = mdb_kvm_tgt_create;
			goto tcreate;
		}

		/*
		 * The object file turned out to be a user core file (ET_CORE),
		 * and no other arguments were specified, swap 0 and 1.  The
		 * proc target will infer the executable for us.
		 */
		if (ehdr.e_type == ET_CORE) {
			tgt_argv[tgt_argc++] = tgt_argv[0];
			tgt_argv[0] = NULL;
			tgt_ctor = mdb_proc_tgt_create;
		}

		/*
		 * If tgt_argv[1] is filled in, open it up and determine if it
		 * is a vmcore file.  If it is, gelf_check will fail and we
		 * set tgt_ctor to 'kvm'; otherwise we use the default.
		 */
		if (tgt_argc > 1 && strcmp(tgt_argv[1], "-") != 0 &&
		    tgt_argv[0] != NULL && pidarg == NULL) {
			Elf32_Ehdr chdr;

			if (access(tgt_argv[1], F_OK) == -1)
				die("failed to access %s", tgt_argv[1]);

			/* *.N case: drop vmdump.N from the list */
			if (tgt_argc == 3) {
				if ((io = mdb_fdio_create_path(NULL,
				    tgt_argv[2], O_RDONLY, 0)) == NULL)
					die("failed to open %s", tgt_argv[2]);
				if (mdb_kvm_is_compressed_dump(io))
					tgt_argv[--tgt_argc] = NULL;
				mdb_io_destroy(io);
			}

			if ((io = mdb_fdio_create_path(NULL, tgt_argv[1],
			    O_RDONLY, 0)) == NULL)
				die("failed to open %s", tgt_argv[1]);

			if (mdb_gelf_check(io, &chdr, ET_NONE) == -1)
				tgt_ctor = mdb_kvm_tgt_create;

			mdb_io_destroy(io);
		}

		/*
		 * At this point, we've read the ELF header for either an
		 * object file or core into ehdr.  If the class does not match
		 * ours, attempt to exec the mdb of the appropriate class.
		 */
#ifdef _LP64
		if (ehdr.e_ident[EI_CLASS] == ELFCLASS32)
			goto reexec;
#else
		if (ehdr.e_ident[EI_CLASS] == ELFCLASS64)
			goto reexec;
#endif
	}

tcreate:
	if (tgt_ctor == NULL)
		tgt_ctor = mdb_proc_tgt_create;

	tgt = mdb_tgt_create(tgt_ctor, mdb.m_tgtflags, tgt_argc, tgt_argv);

	if (tgt == NULL) {
		if (errno == EINVAL)
			usage(2); /* target can return EINVAL to get usage */
		if (errno == EMDB_TGT)
			terminate(1); /* target already printed error msg */
		die("failed to initialize target");
	}

	mdb_tgt_activate(tgt);

	mdb_create_loadable_disasms();

	if (Vflag != NULL && mdb_dis_select(Vflag) == -1)
		warn("invalid disassembler mode -- %s\n", Vflag);


	if (Rflag && mdb.m_term != NULL)
		warn("Using proto area %s\n", mdb.m_root);

	/*
	 * If the target was successfully constructed and -O was specified,
	 * we now attempt to enter piggy-mode for debugging jurassic problems.
	 */
	if (Oflag) {
		pcinfo_t pci;

		(void) strcpy(pci.pc_clname, "RT");

		if (priocntl(P_LWPID, P_MYID, PC_GETCID, (caddr_t)&pci) != -1) {
			pcparms_t pcp;
			rtparms_t *rtp = (rtparms_t *)pcp.pc_clparms;

			rtp->rt_pri = 35;
			rtp->rt_tqsecs = 0;
			rtp->rt_tqnsecs = RT_TQDEF;

			pcp.pc_cid = pci.pc_cid;

			if (priocntl(P_LWPID, P_MYID, PC_SETPARMS,
			    (caddr_t)&pcp) == -1) {
				warn("failed to set RT parameters");
				Oflag = 0;
			}
		} else {
			warn("failed to get RT class id");
			Oflag = 0;
		}

		if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) {
			warn("failed to lock address space");
			Oflag = 0;
		}

		if (Oflag)
			mdb_printf("%s: oink, oink!\n", mdb.m_pname);
	}

	/*
	 * Path evaluation part 2: Re-evaluate the path now that the target
	 * is ready (and thus we have access to the real platform string).
	 * Do this before reading ~/.mdbrc to allow path modifications prior
	 * to performing module auto-loading.
	 */
	mdb_set_ipath(mdb.m_ipathstr);
	mdb_set_lpath(mdb.m_lpathstr);

	if (!Sflag && (p = getenv("HOME")) != NULL) {
		char rcpath[MAXPATHLEN];
		mdb_io_t *rc_io;
		int fd;

		(void) mdb_iob_snprintf(rcpath, MAXPATHLEN, "%s/.mdbrc", p);
		fd = open64(rcpath, O_RDONLY);

		if (fd >= 0 && (rc_io = mdb_fdio_create_named(fd, rcpath))) {
			mdb_iob_t *iob = mdb_iob_create(rc_io, MDB_IOB_RDONLY);
			mdb_iob_t *old = mdb.m_in;

			mdb.m_in = iob;
			(void) mdb_run();
			mdb.m_in = old;
		}
	}

	if (!(mdb.m_flags & MDB_FL_NOMODS))
		mdb_module_load_all(0);

	(void) mdb_signal_sethandler(SIGINT, int_handler, NULL);
	while ((status = mdb_run()) == MDB_ERR_ABORT ||
	    status == MDB_ERR_OUTPUT) {
		/*
		 * If a write failed on stdout, give up.  A more informative
		 * error message will already have been printed by mdb_run().
		 */
		if (status == MDB_ERR_OUTPUT &&
		    mdb_iob_getflags(mdb.m_out) & MDB_IOB_ERR) {
			mdb_warn("write to stdout failed, exiting\n");
			break;
		}
		continue;
	}

	terminate((status == MDB_ERR_QUIT || status == 0) ? 0 : 1);
	/*NOTREACHED*/
	return (0);

reexec:
	if ((p = strrchr(execname, '/')) == NULL)
		die("cannot determine absolute pathname\n");
#ifdef _LP64
#ifdef __sparc
	(void) strcpy(p, "/../sparcv7/");
#else
	(void) strcpy(p, "/../i86/");
#endif
#else
#ifdef __sparc
	(void) strcpy(p, "/../sparcv9/");
#else
	(void) strcpy(p, "/../amd64/");
#endif
#endif
	(void) strcat(p, mdb.m_pname);

	if (mdb.m_term != NULL)
		(void) IOP_CTL(in_io, TCSETSW, &tios);

	(void) putenv("_MDB_EXEC=1");
	(void) execv(execname, argv);

	/*
	 * If execv fails, suppress ENOEXEC.  Experience shows the most common
	 * reason is that the machine is booted under a 32-bit kernel, in which
	 * case it is clearer to only print the message below.
	 */
	if (errno != ENOEXEC)
		warn("failed to exec %s", execname);
#ifdef _LP64
	die("64-bit %s cannot debug 32-bit program %s\n",
	    mdb.m_pname, tgt_argv[0] ?
	    tgt_argv[0] : tgt_argv[1]);
#else
	die("32-bit %s cannot debug 64-bit program %s\n",
	    mdb.m_pname, tgt_argv[0] ?
	    tgt_argv[0] : tgt_argv[1]);
#endif

	goto tcreate;
}
예제 #13
0
파일: mdb_main.c 프로젝트: kele/illumos-fsd
/*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);
}