mdb_main.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/priocntl.h>
#include <sys/rtpriocntl.h>
#include <sys/resource.h>
#include <libproc.h>
#include <libscf.h>
#include <alloca.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <libctf.h>
#include <errno.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_signal.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_target.h>
#include <mdb/mdb_gelf.h>
#include <mdb/mdb_conf.h>
#include <mdb/mdb_io_impl.h>
#include <mdb/mdb_frame.h>
#include <kmdb/kmdb_kctl.h>
#ifndef STACK_BIAS
#define STACK_BIAS 0
#endif
#if defined(__sparc)
#define STACK_REGISTER SP
#else
#define STACK_REGISTER REG_FP
#endif
#ifdef _LP64
#define MDB_DEF_IPATH \
#define MDB_DEF_LPATH \
#else
#define MDB_DEF_IPATH \
#define MDB_DEF_LPATH \
#endif
#define MDB_DEF_PROMPT "> "
/*
* Similar to the panic_* variables in the kernel, we keep some relevant
* information stored in a set of global _mdb_abort_* variables; in the
* event that the debugger dumps core, these will aid core dump analysis.
*/
const char *volatile _mdb_abort_str; /* reason for failure */
int _mdb_abort_rcount; /* number of times resume requested */
static void
{
mdb_destroy();
}
static void
{
} else
}
static int
{
return (0);
}
return (0);
}
return (1);
}
/*ARGSUSED*/
static void
{
};
/*
* If there is no current dcmd, or the current dcmd comes from a
* builtin module, we don't allow resume and always core dump.
*/
goto dump;
char signame[SIG2STR_MAX];
int i = 1;
char c;
"\n*** %s: received signal %d at:\n",
} else {
"\n*** %s: received signal %s at:\n",
}
}
for (;;) {
goto dump;
switch (c) {
case 'c':
case 'C':
goto dump;
case 'q':
case 'Q':
(void) mdb_signal_unblockall();
terminate(1);
/*NOTREACHED*/
case 'r':
case 'R':
(void) mdb_module_unload(
(void) mdb_signal_sethandler(sig,
flt_handler, NULL);
(void) mdb_signal_unblockall();
/*NOTREACHED*/
case 's':
case 'S':
"attempting to stop pid %d ...\n",
/*
* 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);
}
if (_mdb_abort_str == NULL)
_mdb_abort_str = "fatal signal received";
(void) setcontext(ucp);
}
/*ARGSUSED*/
static void
{
else
}
static void
control_kmdb(int start)
{
int fd;
if (start) {
char *state = mdb_get_config();
die("failed to start kmdb");
} else {
die("failed to stop kmdb");
}
}
static void
{
"[-p pid] [-s dist] [-I path] [-L path]\n\t[-P prompt] "
"[-R root] [-V dis-version] [object [core] | core | suffix]\n\n",
"\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-V set disassembler version\n");
}
static char *
mdb_scf_console_term(void)
{
"svc:/system/console-login:default", "ttymon",
"terminal_type")) == NULL)
return (NULL);
return (term);
}
int
{
int tgt_argc = 0;
int status, c;
char *p;
int ttylike;
}
null_io = mdb_nullio_create();
}
/*
* 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.
*/
die("could not allocate signal stack");
die("could not set signal stack");
break;
}
break;
}
}
"fkmo:p:s:uwyACD:FI:KL:MOP:R:SUV:W")) != (int)EOF) {
switch (c) {
case 'f':
break;
case 'k':
break;
case 'm':
break;
case 'o':
terminate(2);
break;
case 'p':
break;
case 's':
warn("expected integer following -s\n");
terminate(2);
}
break;
case 'u':
break;
case 'w':
break;
case 'y':
break;
case 'A':
break;
case 'C':
break;
case 'D':
break;
case 'F':
break;
case 'I':
break;
case 'L':
break;
case 'K':
Kflag++;
break;
case 'M':
break;
case 'O':
Oflag++;
break;
case 'P':
if (!mdb_set_prompt(optarg))
terminate(2);
break;
case 'R':
Rflag++;
break;
case 'S':
Sflag++;
break;
case 'U':
Uflag++;
break;
case 'V':
break;
case 'W':
break;
case '?':
if (optopt == '?')
usage(0);
/* FALLTHROUGH */
default:
usage(2);
}
}
terminate(2);
}
warn("option requires an argument -- "
"%s\n", arg);
terminate(2);
}
terminate(2);
} else
}
}
terminate(0); /* Quit here if we've printed out the tokens */
warn("macro path cannot contain semicolons\n");
terminate(2);
}
warn("module path cannot contain semicolons\n");
terminate(2);
}
char *nm;
warn("neither -f, -k, -p, -u, nor -I "
"may be used with -K\n");
usage(2);
}
/*
* Due to the consequences of typing mdb -K instead of
* -F when starting kmdb from a tty other than
*/
die("-F must also be supplied to start kmdb "
"from non-console tty\n");
}
MDB_FL_TERMGUESS)) {
NULL)
}
} else {
/*
* When on console, $TERM (if set) takes precedence over
* the SMF setting.
*/
mdb_scf_console_term()) != NULL)
}
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.
*/
if (ttylike) {
warn("term init failed: command-line editing "
"and prompt will not be available\n");
}
} else {
}
}
else
} else if (ttylike)
else
if (tgt_ctor == mdb_kvm_tgt_create) {
warn("-p and -k options are mutually exclusive\n");
terminate(2);
}
if (tgt_argc == 0)
else
}
}
if (tgt_argc != 0) {
warn("-p may not be used with other arguments\n");
terminate(2);
}
die("cannot attach to %s: %s\n",
}
else
}
/*
* Find the first argument that is not a special "-" token. If one is
* found, we will examine this file and make some inferences below.
*/
continue;
if (c < tgt_argc) {
/*
* If special "-" tokens preceded an argument, shift the entire
* argument list to the left to remove the leading "-" args.
*/
if (c > 0) {
sizeof (const char *) * (tgt_argc - c));
tgt_argc -= c;
}
/*
* 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.
*/
tgt_argc = 2;
}
/*
* We need to open the object file in order to determine its
* ELF class and potentially re-exec ourself.
*/
/*
* 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 (tgt_ctor != mdb_rawfile_tgt_create &&
terminate(1);
} else
}
if (tgt_ctor == mdb_rawfile_tgt_create)
goto tcreate; /* skip re-exec and just create target */
/*
* 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 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.
*/
}
/*
* 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
#else
#endif
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) putenv("_MDB_EXEC=1");
/*
* 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.
*/
#ifdef _LP64
die("64-bit %s cannot debug 32-bit program %s\n",
#else
die("32-bit %s cannot debug 64-bit program %s\n",
#endif
}
}
/*
* If the debugger state is to be inherited from a previous instance,
* restore it now prior to path evaluation so that %R is updated.
*/
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.
*/
else
else
(void) mdb_set_prompt(MDB_DEF_PROMPT);
die("failed to initialize target");
}
/*
* If the target was successfully constructed and -O was specified,
* we now attempt to enter piggy-mode for debugging jurassic problems.
*/
if (Oflag) {
warn("failed to set RT parameters");
Oflag = 0;
}
} else {
warn("failed to get RT class id");
Oflag = 0;
}
warn("failed to lock address space");
Oflag = 0;
}
if (Oflag)
}
/*
* 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.
*/
char rcpath[MAXPATHLEN];
int fd;
(void) mdb_run();
}
}
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_warn("write to stdout failed, exiting\n");
break;
}
continue;
}
/*NOTREACHED*/
return (0);
}