#include <sys/types.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/termios.h>
#include <sys/param.h>
#include <sys/salib.h>
#include <alloca.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <libctf.h>
#include <errno.h>
#include <ctype.h>
#include <kmdb/kmdb_promif.h>
#include <kmdb/kmdb_dpi.h>
#include <kmdb/kmdb_umemglue.h>
#include <kmdb/kmdb_io.h>
#include <kmdb/kmdb_dpi.h>
#include <kmdb/kmdb_wr.h>
#include <kmdb/kmdb_start.h>
#include <kmdb/kmdb_kdi.h>
#include <kmdb/kmdb_kvm.h>
#include <mdb/mdb_lex.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_err.h>
#include <mdb/mdb_io_impl.h>
#include <mdb/mdb_frame.h>
#include <mdb/mdb_set.h>
#include <mdb/mdb.h>
#ifdef __sparc
#define KMDB_STACK_SIZE (384 * 1024)
#else
#define KMDB_STACK_SIZE (192 * 1024)
#endif
caddr_t kmdb_main_stack;
size_t kmdb_main_stack_size;
#define KMDB_DEF_IPATH "internal"
#if defined(_LP64)
#define KMDB_DEF_LPATH \
"%r/platform/%p/kernel/kmdb/%i:" \
"%r/platform/%m/kernel/kmdb/%i:" \
"%r/kernel/kmdb/%i"
#else
#define KMDB_DEF_LPATH \
"%r/platform/%m/kernel/kmdb:" \
"%r/kernel/kmdb"
#endif
#define MDB_DEF_PROMPT "[%<_cpuid>]> "
#define KMDB_DEF_TERM_TYPE "vt100"
const char *volatile _mdb_abort_str;
static char *
kmdb_modpath2lpath(const char *modpath)
{
#ifdef _LP64
static const char suffix[] = "/kmdb/%i:";
#else
static const char suffix[] = "/kmdb:";
#endif
const char *c;
char *lpath, *lpend, *nlpath;
size_t lpsz, lpres;
if (strchr(modpath, ':') != NULL) {
warn("invalid kernel module path\n");
return (NULL);
}
lpres = lpsz = strlen(modpath) + MAXPATHLEN;
lpend = lpath = mdb_zalloc(lpsz, UM_SLEEP);
while (isspace(*modpath))
modpath++;
for (; *modpath != '\0'; modpath = c) {
size_t sz;
for (c = modpath; !isspace(*c) && *c != '\0'; c++)
continue;
sz = (c - modpath) + sizeof (suffix) - 1;
if (sz >= lpres)
continue;
(void) strncpy(lpend, modpath, c - modpath);
(void) strcpy(lpend + (c - modpath), suffix);
lpend += sz;
lpres -= sz;
while (isspace(*c))
c++;
}
if (lpend != lpath)
lpend[-1] = '\0';
nlpath = strdup(lpath);
mdb_free(lpath, lpsz);
return (nlpath);
}
int
kmdb_init(const char *execname, kmdb_auxv_t *kav)
{
mdb_io_t *in_io, *out_io, *err_io, *null_io;
mdb_tgt_ctor_f *tgt_ctor = kmdb_kvm_create;
mdb_tgt_t *tgt;
int i;
kmdb_prom_init_begin("kmdb", kav);
mdb_umem_startup(kav->kav_dseg, kav->kav_dseg_size,
kav->kav_pagesize);
mdb_create(execname, "kmdb");
kmdb_prom_init_finish(kav);
mdb.m_dseg = kav->kav_dseg;
mdb.m_dsegsz = kav->kav_dseg_size;
out_io = kmdb_promio_create("stdout");
mdb.m_out = mdb_iob_create(out_io, MDB_IOB_WRONLY);
err_io = kmdb_promio_create("stderr");
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 = kmdb_promio_create("stdin");
mdb.m_term = NULL;
if (kav->kav_config != NULL)
mdb_set_config(kav->kav_config);
if (kav->kav_argv != NULL) {
for (i = 0; kav->kav_argv[i] != NULL; i++) {
if (!mdb_set_options(kav->kav_argv[i], TRUE))
return (-1);
}
}
if (kav->kav_flags & KMDB_AUXV_FL_NOUNLOAD)
mdb.m_flags |= MDB_FL_NOUNLOAD;
mdb.m_in = mdb_iob_create(in_io, MDB_IOB_RDONLY);
mdb_iob_setflags(mdb.m_in, MDB_IOB_TTYLIKE);
mdb_lex_reset();
kmdb_kdi_init(kav->kav_kdi, kav);
if (kmdb_dpi_init(kav) < 0) {
warn("Couldn't initialize kernel/PROM interface\n");
return (-1);
}
mdb_set_ipath(KMDB_DEF_IPATH);
if (strlen(mdb.m_lpathstr) > 0) {
mdb_set_lpath(mdb.m_lpathstr);
} else {
char *lpath;
if (kav->kav_modpath != NULL && *kav->kav_modpath != '\0' &&
(lpath = kmdb_modpath2lpath(kav->kav_modpath)) != NULL) {
mdb_set_lpath(lpath);
strfree(lpath);
} else {
mdb_set_lpath(KMDB_DEF_LPATH);
}
}
if (mdb_get_prompt() == NULL)
(void) mdb_set_prompt(MDB_DEF_PROMPT);
tgt = mdb_tgt_create(tgt_ctor, mdb.m_tgtflags, 0, NULL);
if (tgt == NULL) {
warn("failed to initialize target");
return (-1);
}
mdb_tgt_activate(tgt);
mdb_create_loadable_disasms();
mdb_set_ipath(mdb.m_ipathstr);
mdb_set_lpath(mdb.m_lpathstr);
if (!(mdb.m_flags & MDB_FL_NOMODS))
mdb_module_load_all(MDB_MOD_DEFER);
kmdb_main_stack = mdb_alloc(KMDB_STACK_SIZE, UM_SLEEP);
kmdb_main_stack_size = KMDB_STACK_SIZE;
kmdb_kdi_end_init();
return (0);
}
#ifdef sun4v
void
kmdb_init_promif(char *pgmname, kmdb_auxv_t *kav)
{
kmdb_prom_init_promif(pgmname, kav);
}
#else
void
kmdb_init_promif(char *pgmname, kmdb_auxv_t *kav)
{
ASSERT(0);
}
#endif
static void
kmdb_startup(void)
{
mdb_io_t *inio, *outio;
if (mdb.m_termtype == NULL) {
const char *ttype;
if ((ttype = kmdb_prom_term_type()) == NULL) {
ttype = KMDB_DEF_TERM_TYPE;
warn("unable to determine terminal type: "
"assuming `%s'\n", ttype);
}
mdb.m_flags |= MDB_FL_TERMGUESS;
mdb.m_termtype = strdup(ttype);
} else if (mdb.m_flags & MDB_FL_TERMGUESS) {
char *promttype;
if ((promttype = kmdb_prom_term_type()) != NULL) {
strfree(mdb.m_termtype);
mdb.m_termtype = strdup(promttype);
}
}
inio = kmdb_promio_create("stdin");
outio = kmdb_promio_create("stdout");
if ((mdb.m_term = mdb_termio_create(mdb.m_termtype, inio, outio)) ==
NULL && strcmp(mdb.m_termtype, KMDB_DEF_TERM_TYPE) != 0) {
warn("failed to set terminal type to `%s', using `"
KMDB_DEF_TERM_TYPE "'\n", mdb.m_termtype);
strfree(mdb.m_termtype);
mdb.m_termtype = strdup(KMDB_DEF_TERM_TYPE);
if ((mdb.m_term = mdb_termio_create(mdb.m_termtype, inio,
outio)) == NULL) {
fail("failed to set terminal type to `"
KMDB_DEF_TERM_TYPE "'\n");
}
}
mdb_iob_destroy(mdb.m_in);
mdb.m_in = mdb_iob_create(mdb.m_term, MDB_IOB_RDONLY);
mdb_iob_setpager(mdb.m_out, mdb.m_term);
mdb_iob_setflags(mdb.m_out, MDB_IOB_PGENABLE);
kmdb_kvm_startup();
kmdb_dpi_process_work_queue();
kmdb_kvm_poststartup();
}
void
kmdb_main(void)
{
int status;
kmdb_dpi_set_state(DPI_STATE_STOPPED, 0);
mdb_printf("\nWelcome to kmdb\n");
kmdb_startup();
for (;;) {
status = mdb_run();
if (status == MDB_ERR_QUIT && kmdb_kdi_get_unload_request()) {
break;
} else if (status == MDB_ERR_QUIT || status == 0) {
kmdb_dpi_enter_mon();
} else if (status == MDB_ERR_OUTPUT) {
if (mdb_iob_getflags(mdb.m_out) & MDB_IOB_ERR)
fail("write to stdout failed, exiting\n");
} else if (status != MDB_ERR_ABORT) {
fail("debugger exited abnormally (status = %s)\n",
mdb_err2str(status));
}
}
mdb_destroy();
kmdb_dpi_resume_unload();
}