mdb_whatis.c revision 3b6e0a598869dfc84461624e8699bf51738f68b3
/*
* 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 <mdb/mdb_modapi.h>
#include <mdb/mdb_module.h>
#include <mdb/mdb_string.h>
#include <mdb/mdb_whatis.h>
#include <mdb/mdb_whatis_impl.h>
#include <limits.h>
static int whatis_debug = 0;
/* for bsearch; r is an array of {base, size}, e points into w->w_addrs */
static int
find_range(const void *r, const void *e)
{
return (1);
return (-1);
return (0);
}
/* for qsort; simple uintptr comparator */
static int
uintptr_cmp(const void *l, const void *r)
{
return (-1);
return (1);
return (0);
}
static const uintptr_t *
{
find_range));
}
/*
* Returns non-zero if and only if there is at least one address of interest
* in the range [base, base+size).
*/
int
{
const uintptr_t *f;
"mdb_whatis_overlaps(): bogus mdb_whatis_t pointer\n");
return (0);
}
return (0);
mdb_warn("mdb_whatis_overlaps(): [%p, %p+%p) overflows\n",
return (0);
}
if (f == NULL)
return (0);
/*
* We only return success if there's an address we'll actually
* match in the range. We can quickly check for the ALL flag
* or a non-found address at our match point.
*/
return (1);
/* Search backwards then forwards for a non-found address */
while (cur > 0) {
cur--;
break;
if (!w->w_addrfound[cur])
return (1);
}
break;
if (!w->w_addrfound[cur])
return (1);
}
return (0); /* everything has already been seen */
}
/*
* Iteratively search our list of addresses for matches in [base, base+size).
*/
int
{
if (whatis_debug) {
if (w->w_magic != WHATIS_MAGIC) {
"mdb_whatis_match(): bogus mdb_whatis_t pointer\n");
goto done;
}
}
goto done;
mdb_warn("mdb_whatis_match(): [%p, %p+%x) overflows\n",
return (0);
}
if ((offset = w->w_match_next) != 0 &&
mdb_warn("mdb_whatis_match(): new range [%p, %p+%p) "
"while still searching [%p, %p+%p)\n",
offset = 0;
}
if (offset == 0) {
if (f == NULL)
goto done;
/* Walk backwards until we reach the first match */
offset--;
w->w_match_base = base;
w->w_match_size = size;
}
offset++) {
if (w->w_addrfound[offset]) {
/* if we're not seeing everything, skip it */
if (!(w->w_flags & WHATIS_ALL))
continue;
return (1);
}
/* We haven't seen this address yet. */
w->w_found++;
/* If we've found them all, we're done */
w->w_done = 1;
return (1);
}
done:
w->w_match_next = 0;
w->w_match_base = 0;
w->w_match_size = 0;
return (0);
}
/*
* Report a pointer (addr) in an object beginning at (base) in standard
* whatis-style. (format, ...) are mdb_printf() arguments, to be printed
* after the address information. The caller is responsible for printing
* a newline (either in format or after the call returns)
*/
/*ARGSUSED*/
void
{
if (whatis_debug) {
mdb_warn("mdb_whatis_report_object(): addr "
"%p is not a pointer of interest.\n", addr);
}
mdb_warn("whatis: addr (%p) is less than base (%p)\n",
else
return;
}
/*
* Report an address (addr), with symbolic information if available, in
* standard whatis-style. (format, ...) are mdb_printf() arguments, to be
* printed after the address information. The caller is responsible for
* printing a newline (either in format or after the call returns)
*/
/*ARGSUSED*/
void
const char *format, ...)
{
if (whatis_debug) {
mdb_warn("mdb_whatis_report_adddress(): addr "
"%p is not a pointer of interest.\n", addr);
}
}
}
{
/* Mask out the internal-only flags */
return (w->w_flags & WHATIS_PUBLIC);
}
{
return (w->w_done);
}
/*
* Whatis callback list management
*/
typedef struct whatis_callback {
const char *wcb_modname;
char *wcb_name;
void *wcb_arg;
static whatis_callback_t builtin_whatis[] = {
};
static int
{
int ret;
/* First, handle NULLs; we want them at the end */
return (0);
if (l == NULL)
return (1);
if (r == NULL)
return (-1);
/* Next, compare priorities */
return (-1);
return (1);
/* then module name */
return (ret);
/* and finally insertion order */
return (-1);
return (1);
mdb_warn("whatis_cbcmp(): can't happen: duplicate indices\n");
return (0);
}
static void
whatis_init(void)
{
int idx;
}
}
void
{
mdb_warn("mdb_whatis_register(): can only be called during "
"module load\n");
return;
}
mdb_warn("mdb_whatis_register(): whatis name '%s' contains "
"illegal characters\n");
return;
}
mdb_warn("mdb_whatis_register(): flags (%x) contain unknown "
"flags\n", flags);
return;
}
mdb_warn("mdb_whatis_register(): flags (%x) contains both "
"NO_ID and ID_ONLY.\n", flags);
return;
}
if (prio > WHATIS_PRIO_MIN)
whatis_init();
/*
* See if we need to grow the array; note that at initialization
* time, whatis_cb_count is greater than whatis_cb_size; this clues
* us in to the fact that the array doesn't need to be freed.
*/
if (whatis_cb_count == whatis_cb_size) {
if (whatis_cb != whatis_cb_start)
}
/* add it into the table and re-sort */
}
void
{
int found = 0;
int idx;
return;
found++;
}
}
/* If any were removed, compact the array */
if (found != 0) {
whatis_cb_count -= found;
}
}
int
{
mdb_whatis_t w;
int ret;
int keep = 0;
int list = 0;
if (flags & DCMD_PIPE_OUT) {
mdb_warn("whatis: cannot be output into a pipe\n");
return (DCMD_ERR);
}
mdb_warn("whatis: cannot be called during module load\n");
return (DCMD_ERR);
}
whatis_init();
bzero(&w, sizeof (w));
w.w_magic = WHATIS_MAGIC;
whatis_debug = 0;
return (DCMD_USAGE);
if (list) {
mdb_printf("%<u>%-16s %-12s %4s %?s %?s %8s%</u>",
"NAME", "MODULE", "PRIO", "FUNC", "ARG", "FLAGS");
const char *curfl =
"none";
mdb_printf("%-16s %-12s %4d %-?p %-?p %8s\n",
}
return (DCMD_OK);
}
if (!(flags & DCMD_ADDRSPEC))
return (DCMD_USAGE);
w.w_naddrs = 1;
/* If our input is a pipe, try to slurp it all up. */
mdb_pipe_t p;
mdb_get_pipe(&p);
if (p.pipe_len != 0) {
/* sort the address list */
}
}
if (whatis_debug) {
mdb_printf("Searching for:\n");
}
ret = 0;
/* call in to the registered handlers */
/* Honor the ident flags */
if (w.w_flags & WHATIS_IDSPACE) {
continue;
} else {
continue;
}
if (w.w_flags & WHATIS_VERBOSE)
mdb_printf("Searching %s`%s...\n",
ret = 1;
/* reset the match state for the next callback */
w.w_match_next = 0;
w.w_match_base = 0;
w.w_match_size = 0;
if (w.w_done)
break;
}
/* Report any unexplained pointers */
if (w.w_addrfound[idx])
continue;
}
}
void
whatis_help(void)
{
int idx;
mdb_printf("%s\n",
"Given a virtual address (with -i, an identifier), report where it came\n"
"from.\n"
"\n"
"When fed from a pipeline, ::whatis will not maintain the order the input\n"
"comes in; addresses will be reported as it finds them. (-k prevents this;\n"
"the output will be in the same order as the input)\n");
(void) mdb_dec_indent(2);
mdb_printf("%<b>OPTIONS%</b>\n");
(void) mdb_inc_indent(2);
mdb_printf("%s",
" -a Report all information about each address/identifier. The default\n"
" behavior is to report only the first (most specific) source for each\n"
" address/identifier.\n"
" -i addr is an identifier, not a virtual address.\n"
" -k Do not re-order the input. (may be slower)\n"
" -q Quiet; don't print multi-line reports. (stack traces, etc.)\n"
" -v Verbose output; display information about the progress of the search\n");
return;
(void) mdb_dec_indent(2);
mdb_printf("\n%<b>SOURCES%</b>\n\n");
(void) mdb_inc_indent(2);
mdb_printf("The following information sources will be used:\n\n");
(void) mdb_inc_indent(2);
}
(void) mdb_dec_indent(2);
}