#include <mdb/mdb_signal.h>
#include <mdb/mdb_err.h>
#include <mdb/mdb.h>
#include <thread_db.h>
#include <rtld_db.h>
#include <libctf.h>
#include <strings.h>
#include <stdlib.h>
static const char *const _mdb_errlist[] = {
"unknown symbol name",
"unknown object file name",
"no mapping for address",
"unknown dcmd name",
"unknown walk name",
"dcmd name already in use",
"walk name already in use",
"no support for platform",
"no process active",
"specified name is too long",
"specified name contains illegal characters",
"failed to allocate needed memory",
"specified module is not loaded",
"cannot unload built-in module",
"no walk is currently active",
"invalid walk state argument",
"walker does not accept starting address",
"walker requires starting address",
"failed to initialize walk",
"walker cannot be layered on itself",
"i/o stream is read-only",
"i/o stream is write-only",
"no symbol corresponds to address",
"unknown disassembler name",
"disassembler name already in use",
"no such software event specifier",
"no such xdata available",
"xdata name already in use",
"operation not supported by target",
"target is not open for writing",
"invalid register name",
"no register set available for thread",
"stack address is not properly aligned",
"no executable file is open",
"failed to evaluate command",
"command cancelled by user",
"only %lu of %lu bytes could be read",
"dcmd failed",
"improper dcmd usage",
"target error",
"invalid system call number",
"invalid signal number",
"invalid fault number",
"target is currently executing",
"target has completed execution",
"target is a core file",
"debugger lost control of target",
"libthread_db call failed unexpectedly",
"failed to dlopen library",
"librtld_db call failed unexpectedly",
"runtime linker data not available",
"invalid thread identifier",
"event specifier disabled",
"unknown link map id",
"failed to determine return address",
"watchpoint size exceeds address space limit",
"conflict with existing watchpoint",
"address not aligned on an instruction boundary",
"library is missing demangler entry point",
"cannot read past current end of file",
"no symbolic debug information available for module",
"libctf call failed unexpectedly",
"thread local storage has not yet been allocated",
"object does not support thread local storage",
"no such member of structure or union",
"inappropriate context for action",
"module incompatible with target",
"operation not supported by target on this platform",
"kmdb is not loaded",
"kmdb is loading",
"kmdb is already loaded",
"kmdb is unloading",
"kmdb could not be loaded",
"boot-loaded kmdb cannot be unloaded",
"too many enabled watchpoints for this machine",
"DTrace is active",
"boot-loaded module cannot be unloaded",
"stack frame pointer is invalid",
"unexpected short write"
};
static const int _mdb_nerr = sizeof (_mdb_errlist) / sizeof (_mdb_errlist[0]);
static size_t errno_rbytes;
static size_t errno_nbytes;
static int errno_libctf;
#ifndef _KMDB
static int errno_rtld_db;
#endif
const char *
mdb_strerror(int err)
{
static char buf[256];
const char *str;
if (err >= EMDB_BASE && (err - EMDB_BASE) < _mdb_nerr)
str = _mdb_errlist[err - EMDB_BASE];
else
str = strerror(err);
switch (err) {
case EMDB_PARTIAL:
(void) mdb_iob_snprintf(buf, sizeof (buf), str,
errno_rbytes, errno_nbytes);
str = buf;
break;
#ifndef _KMDB
case EMDB_RTLD_DB:
if (rd_errstr(errno_rtld_db) != NULL)
str = rd_errstr(errno_rtld_db);
break;
#endif
case EMDB_CTF:
if (ctf_errmsg(errno_libctf) != NULL)
str = ctf_errmsg(errno_libctf);
break;
}
return (str ? str : "unknown error");
}
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));
}
void
vdie(const char *format, va_list alist)
{
vwarn(format, alist);
mdb_destroy();
exit(1);
}
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;
(void) mdb_iob_vsnprintf(buf, sizeof (buf), format, alist);
nfail = 1;
}
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);
}
void
warn(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vwarn(format, alist);
va_end(alist);
}
void
die(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vdie(format, alist);
va_end(alist);
}
void
fail(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vfail(format, alist);
va_end(alist);
}
int
set_errbytes(size_t rbytes, size_t nbytes)
{
errno_rbytes = rbytes;
errno_nbytes = nbytes;
errno = EMDB_PARTIAL;
return (-1);
}
int
set_errno(int err)
{
errno = err;
return (-1);
}
int
ctf_to_errno(int err)
{
errno_libctf = err;
return (EMDB_CTF);
}
#ifndef _KMDB
int
tdb_to_errno(int err)
{
switch (err) {
case TD_OK:
case TD_PARTIALREG:
return (0);
case TD_NOCAPAB:
return (ENOTSUP);
case TD_BADPH:
case TD_BADTH:
case TD_BADSH:
case TD_BADTA:
case TD_BADKEY:
case TD_NOEVENT:
return (EINVAL);
case TD_NOFPREGS:
case TD_NOXREGS:
return (EMDB_NOREGS);
case TD_NOTHR:
return (EMDB_NOTHREAD);
case TD_MALLOC:
return (EMDB_ALLOC);
case TD_TLSDEFER:
return (EMDB_TLS);
case TD_NOTLS:
return (EMDB_NOTLS);
case TD_DBERR:
case TD_ERR:
default:
return (EMDB_TDB);
}
}
int
rdb_to_errno(int err)
{
errno_rtld_db = err;
return (EMDB_RTLD_DB);
}
#endif