/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2012 Joyent, Inc. All rights reserved.
*/
#include <unistd.h>
#include <strings.h>
#include <dlfcn.h>
#include <link.h>
#include <mdb/mdb_module.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_debug.h>
#include <mdb/mdb_callb.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_frame.h>
#include <mdb/mdb_whatis_impl.h>
/*
* The format of an mdb dcmd changed between MDB_API_VERSION 3 and 4, with an
* addition of a new field to the public interface. To maintain backwards
* compatibility with older versions, we know to keep around the old version of
* the structure so we can correctly read the set of dcmds passed in.
*/
typedef struct mdb_dcmd_v3 {
/*
* For builtin modules, we set mod_init to this function, which just
* returns a constant modinfo struct with no dcmds and walkers.
*/
static const mdb_modinfo_t *
builtin_init(void)
{
return (&info);
}
int
{
*errmsgp = "no module name was specified\n";
return (0);
}
*errmsgp = "module name '%s' exceeds name length limit\n";
return (0);
}
*errmsgp = "module name '%s' contains illegal characters\n";
return (0);
}
*errmsgp = "%s module is already loaded\n";
return (0);
}
return (1);
}
int
mdb_module_t **mpp)
{
if (!(mode & MDB_MOD_BUILTIN)) {
goto err;
}
} else {
#ifdef _KMDB
/*
* mdb_ks is a special case - a builtin with _mdb_init and
* _mdb_fini routines. If we don't hack it in here, we'll have
* to duplicate most of the module creation code elsewhere.
*/
else
#endif
}
goto err;
}
goto err;
}
/*
* Reject modules compiled for a newer version of the debugger.
*/
warn("%s module requires newer mdb API version (%hu) than "
goto err;
}
/*
* Load modules compiled for the current API version.
*/
case MDB_API_VERSION:
case 3:
case 2:
case 1:
/*
* Current API version -- copy entire modinfo
* structure into our own private storage.
*/
break;
default:
/*
* Too old to be compatible -- abort the load.
*/
warn("%s module is compiled for obsolete mdb API "
goto err;
}
/*
* In MDB_API_VERSION 4, the size of the mdb_dcmd_t struct changed. If
* our module is from an earlier version, we need to walk it in the old
* structure and convert it to the new one.
*
* Note that we purposefully don't predicate on whether or not we have
* the empty list case and duplicate it anyways. That case is rare and
* it makes our logic simpler when we need to unload the module.
*/
int ii = 0;
ii++;
/* Don't forget null terminated one at the end */
ii = 0;
}
}
/*
* Before we actually go ahead with the load, we need to check
* each dcmd and walk structure for any invalid values:
*/
warn("dcmd name '%s' contains illegal characters\n",
goto err;
}
warn("dcmd '%s' must have a description\n",
goto err;
}
warn("dcmd '%s' has a NULL function pointer\n",
goto err;
}
}
warn("walk name '%s' contains illegal characters\n",
goto err;
}
warn("walk '%s' must have a description\n",
goto err;
}
warn("walk '%s' has a NULL walk_step function\n",
goto err;
}
}
/*
* Now that we've established that there are no problems,
* we can go ahead and hash the module, and its dcmds and walks:
*/
}
}
/*
* Add the module to the end of the list of modules in load-dependency
* order. We maintain this list so we can unload in reverse order.
*/
} else {
}
return (0);
err:
return (-1);
}
{
return (NULL);
return (mp);
}
int
{
if (v == NULL)
return (set_errno(EMDB_NOMOD));
mod = mdb_nv_get_cookie(v);
return (set_errno(EMDB_BUILTINMOD));
}
} else
} else
}
}
int ii = 0;
dcp++)
ii++;
}
return (0);
}
int
{
if (flags & MDB_MOD_FORCE)
nflag |= MDB_NV_INTERPOS;
if (v != NULL)
return (set_errno(EMDB_DCMDEXISTS));
return (0);
}
int
{
if (v == NULL)
return (set_errno(EMDB_NODCMD));
idcp = mdb_nv_get_cookie(v);
/*
* If we're removing a dcmd that is part of the most recent command,
* we need to free mdb.m_lastcp so we don't attempt to execute some
* text we've removed from our address space if -o repeatlast is set.
*/
}
break;
}
}
return (0);
}
/*ARGSUSED*/
static int
{
return (WALK_NEXT);
}
/*ARGSUSED*/
static void
{
/* Nothing to do here */
}
int
{
if (flags & MDB_MOD_FORCE)
nflag |= MDB_NV_INTERPOS;
if (v != NULL)
return (set_errno(EMDB_WALKEXISTS));
return (0);
}
int
{
if (v == NULL)
return (set_errno(EMDB_NOWALK));
iwp = mdb_nv_get_cookie(v);
return (0);
}
void
{
/*
* We unload modules in the reverse order in which they were loaded
* so as to allow _mdb_fini routines to invoke code which may be
* present in a previously-loaded module (such as mdb_ks, etc.).
*/
}
}