mdb_err.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
* or http://www.opensolaris.org/os/licensing.
* 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 <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", /* EMDB_NOSYM */
"unknown object file name", /* EMDB_NOOBJ */
"no mapping for address", /* EMDB_NOMAP */
"unknown dcmd name", /* EMDB_NODCMD */
"unknown walk name", /* EMDB_NOWALK */
"dcmd name already in use", /* EMDB_DCMDEXISTS */
"walk name already in use", /* EMDB_WALKEXISTS */
"no support for platform", /* EMDB_NOPLAT */
"no process active", /* EMDB_NOPROC */
"specified name is too long", /* EMDB_NAME2BIG */
"specified name contains illegal characters", /* EMDB_NAMEBAD */
"failed to allocate needed memory", /* EMDB_ALLOC */
"specified module is not loaded", /* EMDB_NOMOD */
"cannot unload built-in module", /* EMDB_BUILTINMOD */
"no walk is currently active", /* EMDB_NOWCB */
"invalid walk state argument", /* EMDB_BADWCB */
"walker does not accept starting address", /* EMDB_NOWALKLOC */
"walker requires starting address", /* EMDB_NOWALKGLOB */
"failed to initialize walk", /* EMDB_WALKINIT */
"walker cannot be layered on itself", /* EMDB_WALKLOOP */
"i/o stream is read-only", /* EMDB_IORO */
"i/o stream is write-only", /* EMDB_IOWO */
"no symbol corresponds to address", /* EMDB_NOSYMADDR */
"unknown disassembler name", /* EMDB_NODIS */
"disassembler name already in use", /* EMDB_DISEXISTS */
"no such software event specifier", /* EMDB_NOSESPEC */
"no such xdata available", /* EMDB_NOXD */
"xdata name already in use", /* EMDB_XDEXISTS */
"operation not supported by target", /* EMDB_TGTNOTSUP */
"target is not open for writing", /* EMDB_TGTRDONLY */
"invalid register name", /* EMDB_BADREG */
"no register set available for thread", /* EMDB_NOREGS */
"stack address is not properly aligned", /* EMDB_STKALIGN */
"no executable file is open", /* EMDB_NOEXEC */
"failed to evaluate command", /* EMDB_EVAL */
"command cancelled by user", /* EMDB_CANCEL */
"only %lu of %lu bytes could be read", /* EMDB_PARTIAL */
"dcmd failed", /* EMDB_DCFAIL */
"improper dcmd usage", /* EMDB_DCUSAGE */
"target error", /* EMDB_TGT */
"invalid system call number", /* EMDB_BADSYSNUM */
"invalid signal number", /* EMDB_BADSIGNUM */
"invalid fault number", /* EMDB_BADFLTNUM */
"target is currently executing", /* EMDB_TGTBUSY */
"target has completed execution", /* EMDB_TGTZOMB */
"target is a core file", /* EMDB_TGTCORE */
"debugger lost control of target", /* EMDB_TGTLOST */
"libthread_db call failed unexpectedly", /* EMDB_TDB */
"failed to dlopen library", /* EMDB_RTLD */
"librtld_db call failed unexpectedly", /* EMDB_RTLD_DB */
"runtime linker data not available", /* EMDB_NORTLD */
"invalid thread identifier", /* EMDB_NOTHREAD */
"event specifier disabled", /* EMDB_SPECDIS */
"unknown link map id", /* EMDB_NOLMID */
"failed to determine return address", /* EMDB_NORETADDR */
"watchpoint size exceeds address space limit", /* EMDB_WPRANGE */
"conflict with existing watchpoint", /* EMDB_WPDUP */
"address not aligned on an instruction boundary", /* EMDB_BPALIGN */
"library is missing demangler entry point", /* EMDB_NODEM */
"cannot read past current end of file", /* EMDB_EOF */
"no symbolic debug information available for module", /* EMDB_NOCTF */
"libctf call failed unexpectedly", /* EMDB_CTF */
"thread local storage has not yet been allocated", /* EMDB_TLS */
"object does not support thread local storage", /* EMDB_NOTLS */
"no such member of structure or union", /* EMDB_CTFNOMEMB */
"inappropriate context for action", /* EMDB_CTX */
"module incompatible with target", /* EMDB_INCOMPAT */
"operation not supported by target on this platform",
/* EMDB_TGTHWNOTSUP */
"kmdb is not loaded", /* EMDB_KINACTIVE */
"kmdb is loading", /* EMDB_KACTIVATING */
"kmdb is already loaded", /* EMDB_KACTIVE */
"kmdb is unloading", /* EMDB_KDEACTIVATING */
"kmdb could not be loaded", /* EMDB_KNOLOAD */
"boot-loaded kmdb cannot be unloaded", /* EMDB_KNOUNLOAD */
"too many enabled watchpoints for this machine", /* EMDB_WPTOOMANY */
"DTrace is active", /* EMDB_DTACTIVE */
"boot-loaded module cannot be unloaded" /* EMDB_KMODNOUNLOAD */
};
static const int _mdb_nerr = sizeof (_mdb_errlist) / sizeof (_mdb_errlist[0]);
static size_t errno_rbytes; /* EMDB_PARTIAL actual bytes read */
static size_t errno_nbytes; /* EMDB_PARTIAL total bytes requested */
static int errno_libctf; /* EMDB_CTF underlying error code */
#ifndef _KMDB
static int errno_rtld_db; /* EMDB_RTLD_DB underlying error code */
#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; /* 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);
}
/*PRINTFLIKE1*/
void
warn(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vwarn(format, alist);
va_end(alist);
}
/*PRINTFLIKE1*/
void
die(const char *format, ...)
{
va_list alist;
va_start(alist, format);
vdie(format, alist);
va_end(alist);
}
/*PRINTFLIKE1*/
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
/*
* The libthread_db interface is a superfund site and provides no strerror
* equivalent for us to call: we try to provide some sensible handling for its
* garbage bin of error return codes here. First of all, we don't bother
* interpreting all of the possibilities, since many of them aren't even used
* in the implementation anymore. We try to map thread_db errors we may see
* to UNIX errnos or mdb errnos as appropriate.
*/
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 /* _KMDB */