--- a/usr/src/cmd/mdb/Makefile.kmdb Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/Makefile.kmdb Tue Sep 22 13:42:17 2009 -0700
@@ -101,6 +101,16 @@
MAPFILE = mapfile
MAPFILE_INTERMEDIATE = $(MAPFILE).i
MAPFILE_TEMPLATE = ../../../common/kmdb/mapfile_skel
+MAPFILE_SOURCES_COMMON = \
+ ../../../common/kmdb/kmdb_dpi.h \
+ ../../../common/kmdb/kmdb_kctl.h \
+ ../../../common/kmdb/kmdb_kdi.h \
+ ../../../common/kmdb/kmdb_wr.h \
+ ../../../common/mdb/mdb_ctf.h \
+ ../../../common/mdb/mdb_ks.h \
+ ../../../common/mdb/mdb_modapi.h \
+ ../../../common/mdb/mdb_param.h \
+ ../../../common/mdb/mdb_whatis.h
mdb_lex.o mdb_grammar.o := CCVERBOSE =
--- a/usr/src/cmd/mdb/Makefile.kmdb.files Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/Makefile.kmdb.files Tue Sep 22 13:42:17 2009 -0700
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
KMDBSRCS += \
ffs.c \
@@ -85,6 +83,7 @@
mdb_value.c \
mdb_vcb.c \
mdb_wcb.c \
+ mdb_whatis.c \
kmdb_wr.c
KMDBML +=
--- a/usr/src/cmd/mdb/Makefile.mdb Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/Makefile.mdb Tue Sep 22 13:42:17 2009 -0700
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -81,7 +81,8 @@
mdb_umem.c \
mdb_value.c \
mdb_vcb.c \
- mdb_wcb.c
+ mdb_wcb.c \
+ mdb_whatis.c
$(NOT_RELEASE_BUILD)CPPFLAGS += -DDEBUG
CPPFLAGS += -D_MDB -I. -I../.. -I../../../common
--- a/usr/src/cmd/mdb/common/mdb/mdb_cmds.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_cmds.c Tue Sep 22 13:42:17 2009 -0700
@@ -20,12 +20,10 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/elf.h>
#include <sys/elf_SPARC.h>
@@ -60,6 +58,8 @@
#include <mdb/mdb_set.h>
#include <mdb/mdb_demangle.h>
#include <mdb/mdb_ctf.h>
+#include <mdb/mdb_whatis.h>
+#include <mdb/mdb_whatis_impl.h>
#include <mdb/mdb_macalias.h>
#ifdef _KMDB
#include <kmdb/kmdb_kdi.h>
@@ -1406,23 +1406,33 @@
return (DCMD_OK);
}
+static const char *
+map_name(const mdb_map_t *map, const char *name)
+{
+ if (map->map_flags & MDB_TGT_MAP_HEAP)
+ return ("[ heap ]");
+ if (name != NULL && name[0] != 0)
+ return (name);
+
+ if (map->map_flags & MDB_TGT_MAP_SHMEM)
+ return ("[ shmem ]");
+ if (map->map_flags & MDB_TGT_MAP_STACK)
+ return ("[ stack ]");
+ if (map->map_flags & MDB_TGT_MAP_ANON)
+ return ("[ anon ]");
+ if (map->map_name != NULL)
+ return (map->map_name);
+ return ("[ unknown ]");
+}
+
/*ARGSUSED*/
static int
print_map(void *ignored, const mdb_map_t *map, const char *name)
{
- if (name == NULL || *name == '\0') {
- if (map->map_flags & MDB_TGT_MAP_SHMEM)
- name = "[ shmem ]";
- else if (map->map_flags & MDB_TGT_MAP_STACK)
- name = "[ stack ]";
- else if (map->map_flags & MDB_TGT_MAP_HEAP)
- name = "[ heap ]";
- else if (map->map_flags & MDB_TGT_MAP_ANON)
- name = "[ anon ]";
- }
-
- mdb_printf("%?p %?p %?lx %s\n", map->map_base, map->map_base +
- map->map_size, map->map_size, name ? name : map->map_name);
+ name = map_name(map, name);
+
+ mdb_printf("%?p %?p %?lx %s\n", map->map_base,
+ map->map_base + map->map_size, map->map_size, name);
return (0);
}
@@ -1460,6 +1470,29 @@
return (DCMD_OK);
}
+static int
+whatis_map_callback(void *wp, const mdb_map_t *map, const char *name)
+{
+ mdb_whatis_t *w = wp;
+ uintptr_t cur;
+
+ name = map_name(map, name);
+
+ while (mdb_whatis_match(w, map->map_base, map->map_size, &cur))
+ mdb_whatis_report_address(w, cur, "in %s [%p,%p)\n",
+ name, map->map_base, map->map_base + map->map_size);
+
+ return (0);
+}
+
+/*ARGSUSED*/
+int
+whatis_run_mappings(mdb_whatis_t *w, void *ignored)
+{
+ (void) mdb_tgt_mapping_iter(mdb.m_target, whatis_map_callback, w);
+ return (0);
+}
+
/*ARGSUSED*/
static int
objects_printversion(void *ignored, const mdb_map_t *map, const char *name)
@@ -2922,6 +2955,8 @@
cmd_vtop },
{ "walk", "?name [variable]", "walk data structure", cmd_walk },
{ "walkers", NULL, "list available walkers", cmd_walkers },
+ { "whatis", ":[-aikqv]", "given an address, return information",
+ cmd_whatis, whatis_help },
{ "whence", "[-v] name ...", "show source of walk or dcmd", cmd_which },
{ "which", "[-v] name ...", "show source of walk or dcmd", cmd_which },
{ "xdata", NULL, "print list of external data buffers", cmd_xdata },
--- a/usr/src/cmd/mdb/common/mdb/mdb_module.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/mdb/mdb_module.c Tue Sep 22 13:42:17 2009 -0700
@@ -2,9 +2,8 @@
* 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.
+ * 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
* or http://www.opensolaris.org/os/licensing.
@@ -20,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/param.h>
#include <unistd.h>
#include <strings.h>
@@ -42,6 +39,7 @@
#include <mdb/mdb_err.h>
#include <mdb/mdb_io.h>
#include <mdb/mdb_frame.h>
+#include <mdb/mdb_whatis_impl.h>
#include <mdb/mdb.h>
/*
@@ -268,6 +266,8 @@
return (0);
err:
+ mdb_whatis_unregister_module(mod);
+
if (mod->mod_ctfp != NULL)
ctf_close(mod->mod_ctfp);
@@ -316,6 +316,8 @@
mod->mod_fini();
}
+ mdb_whatis_unregister_module(mod);
+
if (mod->mod_ctfp != NULL)
ctf_close(mod->mod_ctfp);
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/mdb/mdb_whatis.c Tue Sep 22 13:42:17 2009 -0700
@@ -0,0 +1,653 @@
+/*
+ * 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
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <sys/mdb_modapi.h>
+#include <mdb/mdb.h>
+#include <mdb/mdb_io.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)
+{
+ const uintptr_t *range = r;
+ uintptr_t el = *(const uintptr_t *)e;
+
+ if (el < range[0])
+ return (1);
+
+ if ((el - range[0]) >= range[1])
+ return (-1);
+
+ return (0);
+}
+
+/* for qsort; simple uintptr comparator */
+static int
+uintptr_cmp(const void *l, const void *r)
+{
+ uintptr_t lhs = *(const uintptr_t *)l;
+ uintptr_t rhs = *(const uintptr_t *)r;
+
+ if (lhs < rhs)
+ return (-1);
+ if (lhs > rhs)
+ return (1);
+ return (0);
+}
+
+static const uintptr_t *
+mdb_whatis_search(mdb_whatis_t *w, uintptr_t base, size_t size)
+{
+ uintptr_t range[2];
+
+ range[0] = base;
+ range[1] = size;
+
+ return (bsearch(range, w->w_addrs, w->w_naddrs, sizeof (*w->w_addrs),
+ find_range));
+}
+
+/*
+ * Returns non-zero if and only if there is at least one address of interest
+ * in the range [base, base+size).
+ */
+int
+mdb_whatis_overlaps(mdb_whatis_t *w, uintptr_t base, size_t size)
+{
+ const uintptr_t *f;
+ uint_t offset, cur;
+
+ if (whatis_debug && w->w_magic != WHATIS_MAGIC) {
+ mdb_warn(
+ "mdb_whatis_overlaps(): bogus mdb_whatis_t pointer\n");
+ return (0);
+ }
+
+ if (w->w_done || size == 0)
+ return (0);
+
+ if (base + size - 1 < base) {
+ mdb_warn("mdb_whatis_overlaps(): [%p, %p+%p) overflows\n",
+ base, base, size);
+ return (0);
+ }
+
+ f = mdb_whatis_search(w, base, size);
+ if (f == NULL)
+ return (0);
+
+ cur = offset = f - w->w_addrs;
+
+ /*
+ * 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.
+ */
+ if ((w->w_flags & WHATIS_ALL) || !w->w_addrfound[cur])
+ return (1);
+
+ /* Search backwards then forwards for a non-found address */
+ while (cur > 0) {
+ cur--;
+
+ if (w->w_addrs[cur] < base)
+ break;
+
+ if (!w->w_addrfound[cur])
+ return (1);
+ }
+
+ for (cur = offset + 1; cur < w->w_naddrs; cur++) {
+ if ((w->w_addrs[cur] - base) >= size)
+ 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
+mdb_whatis_match(mdb_whatis_t *w, uintptr_t base, size_t size, uintptr_t *out)
+{
+ size_t offset;
+
+ if (whatis_debug) {
+ if (w->w_magic != WHATIS_MAGIC) {
+ mdb_warn(
+ "mdb_whatis_match(): bogus mdb_whatis_t pointer\n");
+ goto done;
+ }
+ }
+
+ if (w->w_done || size == 0)
+ goto done;
+
+ if (base + size - 1 < base) {
+ mdb_warn("mdb_whatis_match(): [%p, %p+%x) overflows\n",
+ base, base, size);
+ return (0);
+ }
+
+ if ((offset = w->w_match_next) != 0 &&
+ (base != w->w_match_base || size != w->w_match_size)) {
+ mdb_warn("mdb_whatis_match(): new range [%p, %p+%p) "
+ "while still searching [%p, %p+%p)\n",
+ base, base, size,
+ w->w_match_base, w->w_match_base, w->w_match_size);
+ offset = 0;
+ }
+
+ if (offset == 0) {
+ const uintptr_t *f = mdb_whatis_search(w, base, size);
+
+ if (f == NULL)
+ goto done;
+
+ offset = (f - w->w_addrs);
+
+ /* Walk backwards until we reach the first match */
+ while (offset > 0 && w->w_addrs[offset - 1] >= base)
+ offset--;
+
+ w->w_match_base = base;
+ w->w_match_size = size;
+ }
+
+ for (; offset < w->w_naddrs && ((w->w_addrs[offset] - base) < size);
+ offset++) {
+
+ *out = w->w_addrs[offset];
+ w->w_match_next = offset + 1;
+
+ 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++;
+ w->w_addrfound[offset] = 1;
+
+ /* If we've found them all, we're done */
+ if (w->w_found == w->w_naddrs && !(w->w_flags & WHATIS_ALL))
+ 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
+mdb_whatis_report_object(mdb_whatis_t *w,
+ uintptr_t addr, uintptr_t base, const char *format, ...)
+{
+ va_list alist;
+
+ if (whatis_debug) {
+ if (mdb_whatis_search(w, addr, 1) == NULL)
+ mdb_warn("mdb_whatis_report_object(): addr "
+ "%p is not a pointer of interest.\n", addr);
+ }
+
+ if (addr < base)
+ mdb_warn("whatis: addr (%p) is less than base (%p)\n",
+ addr, base);
+
+ if (addr == base)
+ mdb_printf("%p is ", addr);
+ else
+ mdb_printf("%p is %p+%p, ", addr, base, addr - base);
+
+ if (format == NULL)
+ return;
+
+ va_start(alist, format);
+ mdb_iob_vprintf(mdb.m_out, format, alist);
+ va_end(alist);
+}
+
+/*
+ * 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
+mdb_whatis_report_address(mdb_whatis_t *w, uintptr_t addr,
+ const char *format, ...)
+{
+ GElf_Sym sym;
+ va_list alist;
+
+ if (whatis_debug) {
+ if (mdb_whatis_search(w, addr, 1) == NULL)
+ mdb_warn("mdb_whatis_report_adddress(): addr "
+ "%p is not a pointer of interest.\n", addr);
+ }
+
+ mdb_printf("%p is ", addr);
+
+ if (mdb_lookup_by_addr(addr, MDB_SYM_FUZZY, NULL, 0, &sym) != -1 &&
+ (addr - (uintptr_t)sym.st_value) < sym.st_size) {
+ mdb_printf("%a, ", addr);
+ }
+
+ va_start(alist, format);
+ mdb_iob_vprintf(mdb.m_out, format, alist);
+ va_end(alist);
+}
+
+uint_t
+mdb_whatis_flags(mdb_whatis_t *w)
+{
+ /* Mask out the internal-only flags */
+ return (w->w_flags & WHATIS_PUBLIC);
+}
+
+uint_t
+mdb_whatis_done(mdb_whatis_t *w)
+{
+ return (w->w_done);
+}
+
+/*
+ * Whatis callback list management
+ */
+typedef struct whatis_callback {
+ uint64_t wcb_index;
+ mdb_module_t *wcb_module;
+ const char *wcb_modname;
+ char *wcb_name;
+ mdb_whatis_cb_f *wcb_func;
+ void *wcb_arg;
+ uint_t wcb_prio;
+ uint_t wcb_flags;
+} whatis_callback_t;
+
+static whatis_callback_t builtin_whatis[] = {
+ { 0, NULL, "mdb", "mappings", whatis_run_mappings, NULL,
+ WHATIS_PRIO_MIN, WHATIS_REG_NO_ID }
+};
+#define NBUILTINS (sizeof (builtin_whatis) / sizeof (*builtin_whatis))
+
+static whatis_callback_t *whatis_cb_start[NBUILTINS];
+static whatis_callback_t **whatis_cb = NULL; /* callback array */
+static size_t whatis_cb_count; /* count of callbacks */
+static size_t whatis_cb_size; /* size of whatis_cb array */
+static uint64_t whatis_cb_index; /* global count */
+
+#define WHATIS_CB_SIZE_MIN 8 /* initial allocation size */
+
+static int
+whatis_cbcmp(const void *lhs, const void *rhs)
+{
+ whatis_callback_t *l = *(whatis_callback_t * const *)lhs;
+ whatis_callback_t *r = *(whatis_callback_t * const *)rhs;
+ int ret;
+
+ /* First, handle NULLs; we want them at the end */
+ if (l == NULL && r == NULL)
+ return (0);
+ if (l == NULL)
+ return (1);
+ if (r == NULL)
+ return (-1);
+
+ /* Next, compare priorities */
+ if (l->wcb_prio < r->wcb_prio)
+ return (-1);
+ if (l->wcb_prio > r->wcb_prio)
+ return (1);
+
+ /* then module name */
+ if ((ret = strcmp(l->wcb_modname, r->wcb_modname)) != 0)
+ return (ret);
+
+ /* and finally insertion order */
+ if (l->wcb_index < r->wcb_index)
+ return (-1);
+ if (l->wcb_index > r->wcb_index)
+ return (1);
+
+ mdb_warn("whatis_cbcmp(): can't happen: duplicate indices\n");
+ return (0);
+}
+
+static void
+whatis_init(void)
+{
+ int idx;
+
+ for (idx = 0; idx < NBUILTINS; idx++) {
+ whatis_cb_start[idx] = &builtin_whatis[idx];
+ whatis_cb_start[idx]->wcb_index = idx;
+ }
+ whatis_cb_index = idx;
+
+ whatis_cb = whatis_cb_start;
+ whatis_cb_count = whatis_cb_size = NBUILTINS;
+
+ qsort(whatis_cb, whatis_cb_count, sizeof (*whatis_cb), whatis_cbcmp);
+}
+
+void
+mdb_whatis_register(const char *name, mdb_whatis_cb_f *func, void *arg,
+ uint_t prio, uint_t flags)
+{
+ whatis_callback_t *wcp;
+
+ if (mdb.m_lmod == NULL) {
+ mdb_warn("mdb_whatis_register(): can only be called during "
+ "module load\n");
+ return;
+ }
+
+ if (strbadid(name)) {
+ mdb_warn("mdb_whatis_register(): whatis name '%s' contains "
+ "illegal characters\n");
+ return;
+ }
+
+ if ((flags & ~(WHATIS_REG_NO_ID|WHATIS_REG_ID_ONLY)) != 0) {
+ mdb_warn("mdb_whatis_register(): flags (%x) contain unknown "
+ "flags\n", flags);
+ return;
+ }
+ if ((flags & WHATIS_REG_NO_ID) && (flags & WHATIS_REG_ID_ONLY)) {
+ mdb_warn("mdb_whatis_register(): flags (%x) contains both "
+ "NO_ID and ID_ONLY.\n", flags);
+ return;
+ }
+
+ if (prio > WHATIS_PRIO_MIN)
+ prio = WHATIS_PRIO_MIN;
+
+ if (whatis_cb == NULL)
+ whatis_init();
+
+ wcp = mdb_zalloc(sizeof (*wcp), UM_SLEEP);
+
+ wcp->wcb_index = whatis_cb_index++;
+ wcp->wcb_prio = prio;
+ wcp->wcb_module = mdb.m_lmod;
+ wcp->wcb_modname = mdb.m_lmod->mod_name;
+ wcp->wcb_name = strdup(name);
+ wcp->wcb_func = func;
+ wcp->wcb_arg = arg;
+ wcp->wcb_flags = flags;
+
+ /*
+ * 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) {
+ size_t nsize = MAX(2 * whatis_cb_size, WHATIS_CB_SIZE_MIN);
+
+ size_t obytes = sizeof (*whatis_cb) * whatis_cb_size;
+ size_t nbytes = sizeof (*whatis_cb) * nsize;
+
+ whatis_callback_t **narray = mdb_zalloc(nbytes, UM_SLEEP);
+
+ bcopy(whatis_cb, narray, obytes);
+
+ if (whatis_cb != whatis_cb_start)
+ mdb_free(whatis_cb, obytes);
+ whatis_cb = narray;
+ whatis_cb_size = nsize;
+ }
+
+ /* add it into the table and re-sort */
+ whatis_cb[whatis_cb_count++] = wcp;
+ qsort(whatis_cb, whatis_cb_count, sizeof (*whatis_cb), whatis_cbcmp);
+}
+
+void
+mdb_whatis_unregister_module(mdb_module_t *mod)
+{
+ int found = 0;
+ int idx;
+
+ if (mod == NULL)
+ return;
+
+ for (idx = 0; idx < whatis_cb_count; idx++) {
+ whatis_callback_t *cur = whatis_cb[idx];
+
+ if (cur->wcb_module == mod) {
+ found++;
+ whatis_cb[idx] = NULL;
+
+ strfree(cur->wcb_name);
+ mdb_free(cur, sizeof (*cur));
+ }
+ }
+ /* If any were removed, compact the array */
+ if (found != 0) {
+ qsort(whatis_cb, whatis_cb_count, sizeof (*whatis_cb),
+ whatis_cbcmp);
+ whatis_cb_count -= found;
+ }
+}
+
+int
+cmd_whatis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+{
+ mdb_whatis_t w;
+ size_t idx;
+ 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);
+ }
+
+ if (mdb.m_lmod != NULL) {
+ mdb_warn("whatis: cannot be called during module load\n");
+ return (DCMD_ERR);
+ }
+
+ if (whatis_cb == NULL)
+ whatis_init();
+
+ bzero(&w, sizeof (w));
+ w.w_magic = WHATIS_MAGIC;
+
+ whatis_debug = 0;
+
+ if (mdb_getopts(argc, argv,
+ 'D', MDB_OPT_SETBITS, TRUE, &whatis_debug, /* hidden */
+ 'b', MDB_OPT_SETBITS, WHATIS_BUFCTL, &w.w_flags, /* hidden */
+ 'l', MDB_OPT_SETBITS, TRUE, &list, /* hidden */
+ 'a', MDB_OPT_SETBITS, WHATIS_ALL, &w.w_flags,
+ 'i', MDB_OPT_SETBITS, WHATIS_IDSPACE, &w.w_flags,
+ 'k', MDB_OPT_SETBITS, TRUE, &keep,
+ 'q', MDB_OPT_SETBITS, WHATIS_QUIET, &w.w_flags,
+ 'v', MDB_OPT_SETBITS, WHATIS_VERBOSE, &w.w_flags,
+ NULL) != argc)
+ return (DCMD_USAGE);
+
+ if (list) {
+ mdb_printf("%<u>%-16s %-12s %4s %?s %?s %8s%</u>",
+ "NAME", "MODULE", "PRIO", "FUNC", "ARG", "FLAGS");
+
+ for (idx = 0; idx < whatis_cb_count; idx++) {
+ whatis_callback_t *cur = whatis_cb[idx];
+
+ const char *curfl =
+ (cur->wcb_flags & WHATIS_REG_NO_ID) ? "NO_ID" :
+ (cur->wcb_flags & WHATIS_REG_ID_ONLY) ? "ID_ONLY" :
+ "none";
+
+ mdb_printf("%-16s %-12s %4d %-?p %-?p %8s\n",
+ cur->wcb_name, cur->wcb_modname, cur->wcb_prio,
+ cur->wcb_func, cur->wcb_arg, curfl);
+ }
+ return (DCMD_OK);
+ }
+
+ if (!(flags & DCMD_ADDRSPEC))
+ return (DCMD_USAGE);
+
+ w.w_addrs = &addr;
+ w.w_naddrs = 1;
+
+ /* If our input is a pipe, try to slurp it all up. */
+ if (!keep && (flags & DCMD_PIPE)) {
+ mdb_pipe_t p;
+ mdb_get_pipe(&p);
+
+ if (p.pipe_len != 0) {
+ w.w_addrs = p.pipe_data;
+ w.w_naddrs = p.pipe_len;
+
+ /* sort the address list */
+ qsort(w.w_addrs, w.w_naddrs, sizeof (*w.w_addrs),
+ uintptr_cmp);
+ }
+ }
+ w.w_addrfound = mdb_zalloc(w.w_naddrs * sizeof (*w.w_addrfound),
+ UM_SLEEP | UM_GC);
+
+ if (whatis_debug) {
+ mdb_printf("Searching for:\n");
+ for (idx = 0; idx < w.w_naddrs; idx++)
+ mdb_printf(" %p", w.w_addrs[idx]);
+ }
+
+ ret = 0;
+
+ /* call in to the registered handlers */
+ for (idx = 0; idx < whatis_cb_count; idx++) {
+ whatis_callback_t *cur = whatis_cb[idx];
+
+ /* Honor the ident flags */
+ if (w.w_flags & WHATIS_IDSPACE) {
+ if (cur->wcb_flags & WHATIS_REG_NO_ID)
+ continue;
+ } else {
+ if (cur->wcb_flags & WHATIS_REG_ID_ONLY)
+ continue;
+ }
+
+ if (w.w_flags & WHATIS_VERBOSE)
+ mdb_printf("Searching %s`%s...\n",
+ cur->wcb_modname, cur->wcb_name);
+
+ if (cur->wcb_func(&w, cur->wcb_arg) != 0)
+ 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 */
+ for (idx = 0; idx < w.w_naddrs; idx++) {
+ uintptr_t addr = w.w_addrs[idx];
+
+ if (w.w_addrfound[idx])
+ continue;
+
+ mdb_whatis_report_object(&w, addr, addr, "unknown\n");
+ }
+
+ return ((ret != 0) ? DCMD_ERR : DCMD_OK);
+}
+
+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");
+
+ if (mdb.m_lmod != NULL)
+ 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);
+ for (idx = 0; idx < whatis_cb_count; idx++) {
+ whatis_callback_t *cur = whatis_cb[idx];
+
+ mdb_printf("%s`%s\n", cur->wcb_modname, cur->wcb_name);
+ }
+ (void) mdb_dec_indent(2);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/mdb/mdb_whatis.h Tue Sep 22 13:42:17 2009 -0700
@@ -0,0 +1,158 @@
+/*
+ * 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
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MDB_WHATIS_H
+#define _MDB_WHATIS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mdb_whatis;
+typedef struct mdb_whatis mdb_whatis_t;
+
+/*
+ * int mdb_whatis_overlaps(mdb_whatis_t *w, uintptr_t base, size_t size):
+ *
+ * Returns non-zero if and only if a call to
+ *
+ * mdb_whatis_match(w, base, size, ...)
+ *
+ * will succeed; that is, there is an address of interest in the
+ * range [base, base+size).
+ */
+extern int mdb_whatis_overlaps(mdb_whatis_t *, uintptr_t, size_t);
+
+/*
+ * int mdb_whatis_match(mdb_whatis_t *w, uintptr_t base, size_t size,
+ * uintptr_t *out)
+ *
+ * Perform an iterative search for an address of interest in [base, base+size).
+ * Each call returning a non-zero value returns the next interesting address
+ * in the range. This must be called repeatedly until it returns a zero
+ * value, indicating that the search is complete.
+ *
+ * For example:
+ * uintptr_t cur;
+ *
+ * while (mdb_whatis_match(w, base, size, &cur))
+ * mdb_whatis_report_object(w, cur, base, "allocated from ...");
+ */
+extern int mdb_whatis_match(mdb_whatis_t *, uintptr_t, size_t, uintptr_t *);
+
+/*
+ * void mdb_whatis_report_address(mdb_whatis_t *w, uintptr_t addr,
+ * uintptr_t base, const char *format, ...)
+ *
+ * Reports addr (an address from mdb_whatis_match()). If addr is inside
+ * a symbol, that will be reported. (format, ...) is an mdb_printf()
+ * format string and associated arguments, and will follow a string like
+ * "addr is ". For example, it could be "in libfoo's text segment\n":
+ *
+ * addr is in libfoo's text segment
+ *
+ * The caller should make sure to output a newline, either in format or in a
+ * separate mdb_printf() call.
+ */
+extern void mdb_whatis_report_address(mdb_whatis_t *, uintptr_t,
+ const char *, ...);
+
+/*
+ * void mdb_whatis_report_object(mdb_whatis_t *w, uintptr_t addr,
+ * uintptr_t base, const char *format, ...)
+ *
+ * Reports addr (an address from mdb_whatis_match()) as being part of an
+ * object beginning at base. (format, ...) is an mdb_printf() format
+ * string and associated arguments, and will follow a string like
+ * "addr is base+offset, ". For example, it could be "allocated from foo\n":
+ *
+ * addr is base+offset, allocated from foo
+ *
+ * The caller should make sure to output a newline, either in format or in a
+ * separate mdb_printf() call.
+ */
+extern void mdb_whatis_report_object(mdb_whatis_t *, uintptr_t, uintptr_t,
+ const char *, ...);
+
+/*
+ * uint_t mdb_whatis_flags(mdb_whatis_t *w)
+ *
+ * Reports which flags were passed to ::whatis. See the flag definitions
+ * for more details.
+ */
+extern uint_t mdb_whatis_flags(mdb_whatis_t *);
+
+#define WHATIS_BUFCTL 0x1 /* -b, the caller requested bufctls */
+#define WHATIS_IDSPACE 0x2 /* -i, only search identifiers */
+#define WHATIS_QUIET 0x4 /* -q, single-line reports only */
+#define WHATIS_VERBOSE 0x8 /* -v, report information about the search */
+
+/*
+ * uint_t mdb_whatis_done(mdb_whatis_t *w)
+ *
+ * Returns non-zero if and only if all addresses have been reported, and it
+ * is time to get out of the callback as quickly as possible.
+ */
+extern uint_t mdb_whatis_done(mdb_whatis_t *);
+
+/* Macro for returning from a walker callback */
+#define WHATIS_WALKRET(w) (mdb_whatis_done(w) ? WALK_DONE : WALK_NEXT)
+
+typedef int mdb_whatis_cb_f(mdb_whatis_t *, void *);
+
+/*
+ * void mdb_whatis_register(const char *name, mdb_whatis_cb_f *cb, void *arg,
+ * uint_t prio, uint_t flags)
+ *
+ * May only be called from _mdb_init() for a module.
+ *
+ * Registers a whatis callback named "name" (which must be an MDB identifier),
+ * with a callback function cb and argument arg. prio determines when the
+ * callback will be invoked, compared to other registered ones, and flags
+ * determines when the callback will be invoked (see below).
+ *
+ * Callbacks with the same priority registered by the same module will be
+ * executed in the order they were added. The callbacks will be invoked as:
+ *
+ * int ret = (*cb)(w, arg)
+ *
+ * Where w is an opaque mdb_whatis_t pointer which is to be passed to the API
+ * routines, above. The function should return 0 unless an error occurs.
+ */
+extern void mdb_whatis_register(const char *,
+ mdb_whatis_cb_f *, void *, uint_t, uint_t);
+
+#define WHATIS_PRIO_EARLY 10 /* execute before allocator callbacks */
+#define WHATIS_PRIO_ALLOCATOR 20
+#define WHATIS_PRIO_LATE 30 /* execute after allocator callbacks */
+
+#define WHATIS_REG_ID_ONLY 0x1 /* only invoke for '-i' */
+#define WHATIS_REG_NO_ID 0x2 /* don't invoke for '-i' */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MDB_WHATIS_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/mdb/common/mdb/mdb_whatis_impl.h Tue Sep 22 13:42:17 2009 -0700
@@ -0,0 +1,75 @@
+/*
+ * 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
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef _MDB_WHATIS_IMPL_H
+#define _MDB_WHATIS_IMPL_H
+
+#include <mdb/mdb_module.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define WHATIS_MS(c, s) (((uint64_t)(c)) << (s))
+
+#define WHATIS_MAGIC /* whatis 0x2009 */ \
+ (WHATIS_MS('w', 56) | WHATIS_MS('h', 48) | WHATIS_MS('a', 40) | \
+ WHATIS_MS('t', 32) | WHATIS_MS('i', 24) | WHATIS_MS('s', 16) | \
+ WHATIS_MS(0x2009, 0))
+
+struct mdb_whatis {
+ uint64_t w_magic; /* just for sanity */
+ uintptr_t *w_addrs; /* w_naddr sorted addresses */
+ char *w_addrfound; /* array of w_naddr "found" flags */
+ size_t w_naddrs;
+ size_t w_match_next; /* next match offset, or 0 if no active match */
+ uintptr_t w_match_base; /* base of current match */
+ size_t w_match_size; /* size of current match */
+ size_t w_found; /* count of set entries in w_addrfound */
+ uint_t w_flags; /* see WHATIS_* for details */
+ uint8_t w_done; /* set when no more processing is needed */
+};
+
+#define WHATIS_PUBLIC 0x0ffff
+
+/* flags which aren't part of the public interface */
+#define WHATIS_ALL 0x10000 /* -a, report all matches */
+
+#define WHATIS_PRIO_MIN 99
+
+extern int cmd_whatis(uintptr_t, uint_t, int, const mdb_arg_t *);
+extern void whatis_help(void);
+
+/* built-in callbacks */
+extern int whatis_run_mappings(struct mdb_whatis *, void *);
+
+/* callback at module unload time */
+extern void mdb_whatis_unregister_module(mdb_module_t *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _MDB_WHATIS_IMPL_H */
--- a/usr/src/cmd/mdb/common/modules/conf/mapfile-extern Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/conf/mapfile-extern Tue Sep 22 13:42:17 2009 -0700
@@ -144,6 +144,13 @@
mdb_walk = EXTERN;
mdb_walk_dcmd = EXTERN;
mdb_warn = EXTERN;
+ mdb_whatis_done = EXTERN;
+ mdb_whatis_flags = EXTERN;
+ mdb_whatis_match = EXTERN;
+ mdb_whatis_overlaps = EXTERN;
+ mdb_whatis_register = EXTERN;
+ mdb_whatis_report_address = EXTERN;
+ mdb_whatis_report_object = EXTERN;
mdb_writevar = EXTERN;
mdb_writestr = EXTERN;
mdb_writesym = EXTERN;
--- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c Tue Sep 22 13:42:17 2009 -0700
@@ -4437,8 +4437,6 @@
{ "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
"[-m minsize] [-M maxsize] [-t thread] [-T type]",
"print or filter a vmem_seg", vmem_seg, vmem_seg_help },
- { "whatis", ":[-abiqv]", "given an address, return information", whatis,
- whatis_help },
{ "whatthread", ":[-v]", "print threads whose stack contains the "
"given address", whatthread },
--- a/usr/src/cmd/mdb/common/modules/genunix/kmem.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/genunix/kmem.c Tue Sep 22 13:42:17 2009 -0700
@@ -26,6 +26,7 @@
#include <mdb/mdb_param.h>
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
+#include <mdb/mdb_whatis.h>
#include <sys/cpuvar.h>
#include <sys/kmem_impl.h>
#include <sys/vmem_impl.h>
@@ -2089,33 +2090,19 @@
return (" (below sp)");
}
-typedef struct whatis {
- uintptr_t w_addr;
- const kmem_cache_t *w_cache;
- const vmem_t *w_vmem;
- size_t w_slab_align;
- int w_slab_found;
- int w_found;
- int w_kmem_lite_count;
- uint_t w_all;
- uint_t w_bufctl;
- uint_t w_freemem;
- uint_t w_idspace;
- uint_t w_quiet;
- uint_t w_verbose;
-} whatis_t;
-
-/* nicely report pointers as offsets from a base */
-static void
-whatis_report_pointer(uintptr_t addr, uintptr_t base, const char *description)
-{
- if (addr == base)
- mdb_printf("%p is %s",
- addr, description);
- else
- mdb_printf("%p is %p+%p, %s",
- addr, base, addr - base, description);
-}
+/*
+ * Additional state for the kmem and vmem ::whatis handlers
+ */
+typedef struct whatis_info {
+ mdb_whatis_t *wi_w;
+ const kmem_cache_t *wi_cache;
+ const vmem_t *wi_vmem;
+ vmem_t *wi_msb_arena;
+ size_t wi_slab_size;
+ uint_t wi_slab_found;
+ uint_t wi_kmem_lite_count;
+ uint_t wi_freemem;
+} whatis_info_t;
/* call one of our dcmd functions with "-v" and the provided address */
static void
@@ -2125,206 +2112,220 @@
a.a_type = MDB_TYPE_STRING;
a.a_un.a_str = "-v";
+ mdb_printf(":\n");
(void) (*dcmd)(addr, DCMD_ADDRSPEC, 1, &a);
}
static void
-whatis_print_kmem(uintptr_t addr, uintptr_t baddr, whatis_t *w)
+whatis_print_kmf_lite(uintptr_t btaddr, size_t count)
{
- const kmem_cache_t *cp = w->w_cache;
+#define KMEM_LITE_MAX 16
+ pc_t callers[KMEM_LITE_MAX];
+ pc_t uninit = (pc_t)KMEM_UNINITIALIZED_PATTERN;
+
+ kmem_buftag_t bt;
+ intptr_t stat;
+ const char *plural = "";
+ int i;
+
+ /* validate our arguments and read in the buftag */
+ if (count == 0 || count > KMEM_LITE_MAX ||
+ mdb_vread(&bt, sizeof (bt), btaddr) == -1)
+ return;
+
+ /* validate the buffer state and read in the callers */
+ stat = (intptr_t)bt.bt_bufctl ^ bt.bt_bxstat;
+
+ if (stat != KMEM_BUFTAG_ALLOC || stat != KMEM_BUFTAG_FREE ||
+ mdb_vread(callers, count * sizeof (pc_t),
+ btaddr + offsetof(kmem_buftag_lite_t, bt_history)) == -1)
+ return;
+
+ /* If there aren't any filled in callers, bail */
+ if (callers[0] == uninit)
+ return;
+
+ plural = (callers[1] == uninit) ? "" : "s";
+
+ /* Everything's done and checked; print them out */
+ mdb_printf(":\n");
+
+ mdb_inc_indent(8);
+ mdb_printf("recent caller%s: %a", plural, callers[0]);
+ for (i = 1; i < count; i++) {
+ if (callers[i] == uninit)
+ break;
+ mdb_printf(", %a", callers[i]);
+ }
+ mdb_dec_indent(8);
+}
+
+static void
+whatis_print_kmem(whatis_info_t *wi, uintptr_t maddr, uintptr_t addr,
+ uintptr_t baddr)
+{
+ mdb_whatis_t *w = wi->wi_w;
+
+ const kmem_cache_t *cp = wi->wi_cache;
/* LINTED pointer cast may result in improper alignment */
uintptr_t btaddr = (uintptr_t)KMEM_BUFTAG(cp, addr);
- intptr_t stat;
- int call_printer;
- int count = 0;
- int i;
- pc_t callers[16];
-
- if (cp->cache_flags & KMF_REDZONE) {
- kmem_buftag_t bt;
-
- if (mdb_vread(&bt, sizeof (bt), btaddr) == -1)
- goto done;
-
- stat = (intptr_t)bt.bt_bufctl ^ bt.bt_bxstat;
-
- if (stat != KMEM_BUFTAG_ALLOC && stat != KMEM_BUFTAG_FREE)
- goto done;
-
- /*
- * provide the bufctl ptr if it has useful information
- */
- if (baddr == 0 && (cp->cache_flags & KMF_AUDIT))
- baddr = (uintptr_t)bt.bt_bufctl;
-
- if (cp->cache_flags & KMF_LITE) {
- count = w->w_kmem_lite_count;
-
- if (count * sizeof (pc_t) > sizeof (callers))
- count = 0;
-
- if (count > 0 &&
- mdb_vread(callers, count * sizeof (pc_t),
- btaddr +
- offsetof(kmem_buftag_lite_t, bt_history)) == -1)
- count = 0;
-
- /*
- * skip unused callers
- */
- while (count > 0 && callers[count - 1] ==
- (pc_t)KMEM_UNINITIALIZED_PATTERN)
- count--;
- }
- }
-
-done:
- call_printer =
- (!w->w_quiet && baddr != 0 && (cp->cache_flags & KMF_AUDIT));
-
- whatis_report_pointer(w->w_addr, addr, "");
+ int quiet = (mdb_whatis_flags(w) & WHATIS_QUIET);
+ int call_printer = (!quiet && (cp->cache_flags & KMF_AUDIT));
+
+ mdb_whatis_report_object(w, maddr, addr, "");
if (baddr != 0 && !call_printer)
mdb_printf("bufctl %p ", baddr);
- mdb_printf("%s from %s%s\n",
- (w->w_freemem == FALSE) ? "allocated" : "freed", cp->cache_name,
- (call_printer || (!w->w_quiet && count > 0)) ? ":" : "");
-
- if (call_printer)
+ mdb_printf("%s from %s",
+ (wi->wi_freemem == FALSE) ? "allocated" : "freed", cp->cache_name);
+
+ if (baddr != 0 && call_printer) {
whatis_call_printer(bufctl, baddr);
-
- if (!w->w_quiet && count > 0) {
- mdb_inc_indent(8);
- mdb_printf("recent caller%s: %a%s", (count != 1)? "s":"",
- callers[0], (count != 1)? ", ":"\n");
- for (i = 1; i < count; i++)
- mdb_printf("%a%s", callers[i],
- (i + 1 < count)? ", ":"\n");
- mdb_dec_indent(8);
+ return;
}
+
+ /* for KMF_LITE caches, try to print out the previous callers */
+ if (!quiet && (cp->cache_flags & KMF_LITE))
+ whatis_print_kmf_lite(btaddr, wi->wi_kmem_lite_count);
+
+ mdb_printf("\n");
+}
+
+/*ARGSUSED*/
+static int
+whatis_walk_kmem(uintptr_t addr, void *ignored, whatis_info_t *wi)
+{
+ mdb_whatis_t *w = wi->wi_w;
+
+ uintptr_t cur;
+ size_t size = wi->wi_cache->cache_bufsize;
+
+ while (mdb_whatis_match(w, addr, size, &cur))
+ whatis_print_kmem(wi, cur, addr, NULL);
+
+ return (WHATIS_WALKRET(w));
}
/*ARGSUSED*/
static int
-whatis_walk_kmem(uintptr_t addr, void *ignored, whatis_t *w)
+whatis_walk_bufctl(uintptr_t baddr, const kmem_bufctl_t *bcp, whatis_info_t *wi)
{
- if (w->w_addr < addr || w->w_addr >= addr + w->w_cache->cache_bufsize)
- return (WALK_NEXT);
-
- whatis_print_kmem(addr, 0, w);
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ mdb_whatis_t *w = wi->wi_w;
+
+ uintptr_t cur;
+ uintptr_t addr = (uintptr_t)bcp->bc_addr;
+ size_t size = wi->wi_cache->cache_bufsize;
+
+ while (mdb_whatis_match(w, addr, size, &cur))
+ whatis_print_kmem(wi, cur, addr, baddr);
+
+ return (WHATIS_WALKRET(w));
}
static int
-whatis_walk_seg(uintptr_t addr, const vmem_seg_t *vs, whatis_t *w)
+whatis_walk_seg(uintptr_t addr, const vmem_seg_t *vs, whatis_info_t *wi)
{
- if (w->w_addr < vs->vs_start || w->w_addr >= vs->vs_end)
+ mdb_whatis_t *w = wi->wi_w;
+
+ size_t size = vs->vs_end - vs->vs_start;
+ uintptr_t cur;
+
+ /* We're not interested in anything but alloc and free segments */
+ if (vs->vs_type != VMEM_ALLOC && vs->vs_type != VMEM_FREE)
return (WALK_NEXT);
- whatis_report_pointer(w->w_addr, vs->vs_start, "");
-
- /*
- * If we're not printing it seperately, provide the vmem_seg
- * pointer if it has a stack trace.
- */
- if (w->w_quiet && (w->w_bufctl == TRUE ||
- (vs->vs_type == VMEM_ALLOC && vs->vs_depth != 0))) {
- mdb_printf("vmem_seg %p ", addr);
+ while (mdb_whatis_match(w, vs->vs_start, size, &cur)) {
+ mdb_whatis_report_object(w, cur, vs->vs_start, "");
+
+ /*
+ * If we're not printing it seperately, provide the vmem_seg
+ * pointer if it has a stack trace.
+ */
+ if ((mdb_whatis_flags(w) & WHATIS_QUIET) &&
+ (!(mdb_whatis_flags(w) & WHATIS_BUFCTL) ||
+ (vs->vs_type == VMEM_ALLOC && vs->vs_depth != 0))) {
+ mdb_printf("vmem_seg %p ", addr);
+ }
+
+ mdb_printf("%s from the %s vmem arena",
+ (vs->vs_type == VMEM_ALLOC) ? "allocated" : "freed",
+ wi->wi_vmem->vm_name);
+
+ if (!(mdb_whatis_flags(w) & WHATIS_QUIET))
+ whatis_call_printer(vmem_seg, addr);
+ else
+ mdb_printf("\n");
}
- mdb_printf("%s from %s vmem arena%s\n",
- (w->w_freemem == FALSE) ? "allocated" : "freed", w->w_vmem->vm_name,
- !w->w_quiet ? ":" : "");
-
- if (!w->w_quiet)
- whatis_call_printer(vmem_seg, addr);
-
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ return (WHATIS_WALKRET(w));
}
static int
-whatis_walk_vmem(uintptr_t addr, const vmem_t *vmem, whatis_t *w)
+whatis_walk_vmem(uintptr_t addr, const vmem_t *vmem, whatis_info_t *wi)
{
+ mdb_whatis_t *w = wi->wi_w;
const char *nm = vmem->vm_name;
- w->w_vmem = vmem;
- w->w_freemem = FALSE;
-
- if (((vmem->vm_cflags & VMC_IDENTIFIER) != 0) ^ w->w_idspace)
+
+ int identifier = ((vmem->vm_cflags & VMC_IDENTIFIER) != 0);
+ int idspace = ((mdb_whatis_flags(w) & WHATIS_IDSPACE) != 0);
+
+ if (identifier != idspace)
return (WALK_NEXT);
- if (w->w_verbose)
+ wi->wi_vmem = vmem;
+
+ if (mdb_whatis_flags(w) & WHATIS_VERBOSE)
mdb_printf("Searching vmem arena %s...\n", nm);
- if (mdb_pwalk("vmem_alloc",
- (mdb_walk_cb_t)whatis_walk_seg, w, addr) == -1) {
- mdb_warn("can't walk vmem seg for %p", addr);
+ if (mdb_pwalk("vmem_seg",
+ (mdb_walk_cb_t)whatis_walk_seg, wi, addr) == -1) {
+ mdb_warn("can't walk vmem_seg for %p", addr);
return (WALK_NEXT);
}
- if (w->w_found && w->w_all == FALSE)
- return (WALK_DONE);
-
- if (w->w_verbose)
- mdb_printf("Searching vmem arena %s for free virtual...\n", nm);
-
- w->w_freemem = TRUE;
-
- if (mdb_pwalk("vmem_free",
- (mdb_walk_cb_t)whatis_walk_seg, w, addr) == -1) {
- mdb_warn("can't walk vmem seg for %p", addr);
- return (WALK_NEXT);
- }
-
- return (w->w_found && w->w_all == FALSE ? WALK_DONE : WALK_NEXT);
+ return (WHATIS_WALKRET(w));
}
/*ARGSUSED*/
static int
-whatis_walk_bufctl(uintptr_t baddr, const kmem_bufctl_t *bcp, whatis_t *w)
+whatis_walk_slab(uintptr_t saddr, const kmem_slab_t *sp, whatis_info_t *wi)
{
- uintptr_t addr;
-
- if (bcp == NULL)
- return (WALK_NEXT);
-
- addr = (uintptr_t)bcp->bc_addr;
-
- if (w->w_addr < addr || w->w_addr >= addr + w->w_cache->cache_bufsize)
- return (WALK_NEXT);
-
- whatis_print_kmem(addr, baddr, w);
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
-}
-
-/*ARGSUSED*/
-static int
-whatis_walk_slab(uintptr_t saddr, const kmem_slab_t *sp, whatis_t *w)
-{
- uintptr_t base = P2ALIGN((uintptr_t)sp->slab_base, w->w_slab_align);
-
- if ((w->w_addr - base) >= w->w_cache->cache_slabsize)
- return (WALK_NEXT);
-
- w->w_slab_found++;
- return (WALK_DONE);
+ mdb_whatis_t *w = wi->wi_w;
+
+ /* It must overlap with the slab data, or it's not interesting */
+ if (mdb_whatis_overlaps(w,
+ (uintptr_t)sp->slab_base, wi->wi_slab_size)) {
+ wi->wi_slab_found++;
+ return (WALK_DONE);
+ }
+ return (WALK_NEXT);
}
static int
-whatis_walk_cache(uintptr_t addr, const kmem_cache_t *c, whatis_t *w)
+whatis_walk_cache(uintptr_t addr, const kmem_cache_t *c, whatis_info_t *wi)
{
+ mdb_whatis_t *w = wi->wi_w;
+
char *walk, *freewalk;
mdb_walk_cb_t func;
- vmem_t *vmp = c->cache_arena;
-
- if (((c->cache_flags & KMC_IDENTIFIER) != 0) ^ w->w_idspace)
+ int do_bufctl;
+
+ int identifier = ((c->cache_flags & KMC_IDENTIFIER) != 0);
+ int idspace = ((mdb_whatis_flags(w) & WHATIS_IDSPACE) != 0);
+
+ if (identifier != idspace)
return (WALK_NEXT);
- /* For caches with auditing info, we always walk the bufctls */
- if (w->w_bufctl || (c->cache_flags & KMF_AUDIT)) {
+ /* Override the '-b' flag as necessary */
+ if (!(c->cache_flags & KMF_HASH))
+ do_bufctl = FALSE; /* no bufctls to walk */
+ else if (c->cache_flags & KMF_AUDIT)
+ do_bufctl = TRUE; /* we always want debugging info */
+ else
+ do_bufctl = ((mdb_whatis_flags(w) & WHATIS_BUFCTL) != 0);
+
+ if (do_bufctl) {
walk = "bufctl";
freewalk = "freectl";
func = (mdb_walk_cb_t)whatis_walk_bufctl;
@@ -2334,130 +2335,142 @@
func = (mdb_walk_cb_t)whatis_walk_kmem;
}
- w->w_cache = c;
-
- if (w->w_verbose)
- mdb_printf("Searching %s's slabs...\n", c->cache_name);
+ wi->wi_cache = c;
+
+ if (mdb_whatis_flags(w) & WHATIS_VERBOSE)
+ mdb_printf("Searching %s...\n", c->cache_name);
/*
- * Verify that the address is in one of the cache's slabs. If not,
- * we can skip the more expensive walkers. (this is purely a
- * heuristic -- as long as there are no false-negatives, we'll be fine)
- *
- * We try to get the cache's arena's quantum, since to accurately
- * get the base of a slab, you have to align it to the quantum. If
- * it doesn't look sensible, we fall back to not aligning.
+ * If more then two buffers live on each slab, figure out if we're
+ * interested in anything in any slab before doing the more expensive
+ * kmem/freemem (bufctl/freectl) walkers.
*/
- if (mdb_vread(&w->w_slab_align, sizeof (w->w_slab_align),
- (uintptr_t)&vmp->vm_quantum) == -1) {
- mdb_warn("unable to read %p->cache_arena->vm_quantum", c);
- w->w_slab_align = 1;
- }
-
- if ((c->cache_slabsize < w->w_slab_align) || w->w_slab_align == 0 ||
- (w->w_slab_align & (w->w_slab_align - 1))) {
- mdb_warn("%p's arena has invalid quantum (0x%p)\n", c,
- w->w_slab_align);
- w->w_slab_align = 1;
+ wi->wi_slab_size = c->cache_slabsize - c->cache_maxcolor;
+ if (!(c->cache_flags & KMF_HASH))
+ wi->wi_slab_size -= sizeof (kmem_slab_t);
+
+ if ((wi->wi_slab_size / c->cache_chunksize) > 2) {
+ wi->wi_slab_found = 0;
+ if (mdb_pwalk("kmem_slab", (mdb_walk_cb_t)whatis_walk_slab, wi,
+ addr) == -1) {
+ mdb_warn("can't find kmem_slab walker");
+ return (WALK_DONE);
+ }
+ if (wi->wi_slab_found == 0)
+ return (WALK_NEXT);
}
- w->w_slab_found = 0;
- if (mdb_pwalk("kmem_slab", (mdb_walk_cb_t)whatis_walk_slab, w,
- addr) == -1) {
- mdb_warn("can't find kmem_slab walker");
- return (WALK_DONE);
- }
- if (w->w_slab_found == 0)
- return (WALK_NEXT);
-
- if (c->cache_flags & KMF_LITE) {
- if (mdb_readvar(&w->w_kmem_lite_count,
- "kmem_lite_count") == -1 || w->w_kmem_lite_count > 16)
- w->w_kmem_lite_count = 0;
- }
-
- if (w->w_verbose)
- mdb_printf("Searching %s...\n", c->cache_name);
-
- w->w_freemem = FALSE;
-
- if (mdb_pwalk(walk, func, w, addr) == -1) {
+ wi->wi_freemem = FALSE;
+ if (mdb_pwalk(walk, func, wi, addr) == -1) {
mdb_warn("can't find %s walker", walk);
return (WALK_DONE);
}
- if (w->w_found && w->w_all == FALSE)
+ if (mdb_whatis_done(w))
return (WALK_DONE);
/*
* We have searched for allocated memory; now search for freed memory.
*/
- if (w->w_verbose)
+ if (mdb_whatis_flags(w) & WHATIS_VERBOSE)
mdb_printf("Searching %s for free memory...\n", c->cache_name);
- w->w_freemem = TRUE;
-
- if (mdb_pwalk(freewalk, func, w, addr) == -1) {
+ wi->wi_freemem = TRUE;
+ if (mdb_pwalk(freewalk, func, wi, addr) == -1) {
mdb_warn("can't find %s walker", freewalk);
return (WALK_DONE);
}
- return (w->w_found && w->w_all == FALSE ? WALK_DONE : WALK_NEXT);
+ return (WHATIS_WALKRET(w));
+}
+
+static int
+whatis_walk_touch(uintptr_t addr, const kmem_cache_t *c, whatis_info_t *wi)
+{
+ if (c->cache_arena == wi->wi_msb_arena ||
+ (c->cache_cflags & KMC_NOTOUCH))
+ return (WALK_NEXT);
+
+ return (whatis_walk_cache(addr, c, wi));
}
static int
-whatis_walk_touch(uintptr_t addr, const kmem_cache_t *c, whatis_t *w)
+whatis_walk_metadata(uintptr_t addr, const kmem_cache_t *c, whatis_info_t *wi)
{
- if (c->cache_cflags & KMC_NOTOUCH)
+ if (c->cache_arena != wi->wi_msb_arena)
return (WALK_NEXT);
- return (whatis_walk_cache(addr, c, w));
+ return (whatis_walk_cache(addr, c, wi));
}
static int
-whatis_walk_notouch(uintptr_t addr, const kmem_cache_t *c, whatis_t *w)
+whatis_walk_notouch(uintptr_t addr, const kmem_cache_t *c, whatis_info_t *wi)
{
- if (!(c->cache_cflags & KMC_NOTOUCH))
+ if (c->cache_arena == wi->wi_msb_arena ||
+ !(c->cache_cflags & KMC_NOTOUCH))
return (WALK_NEXT);
- return (whatis_walk_cache(addr, c, w));
+ return (whatis_walk_cache(addr, c, wi));
}
static int
-whatis_walk_thread(uintptr_t addr, const kthread_t *t, whatis_t *w)
+whatis_walk_thread(uintptr_t addr, const kthread_t *t, mdb_whatis_t *w)
{
+ uintptr_t cur;
+ uintptr_t saddr;
+ size_t size;
+
/*
* Often, one calls ::whatis on an address from a thread structure.
* We use this opportunity to short circuit this case...
*/
- if (w->w_addr >= addr && w->w_addr < addr + sizeof (kthread_t)) {
- whatis_report_pointer(w->w_addr, addr,
+ while (mdb_whatis_match(w, addr, sizeof (kthread_t), &cur))
+ mdb_whatis_report_object(w, cur, addr,
"allocated as a thread structure\n");
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
- }
-
- if (w->w_addr < (uintptr_t)t->t_stkbase ||
- w->w_addr > (uintptr_t)t->t_stk)
- return (WALK_NEXT);
-
+
+ /*
+ * Now check the stack
+ */
if (t->t_stkbase == NULL)
return (WALK_NEXT);
- mdb_printf("%p is in thread %p's stack%s\n", w->w_addr, addr,
- stack_active(t, w->w_addr));
-
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ /*
+ * This assumes that t_stk is the end of the stack, but it's really
+ * only the initial stack pointer for the thread. Arguments to the
+ * initial procedure, SA(MINFRAME), etc. are all after t_stk. So
+ * that 't->t_stk::whatis' reports "part of t's stack", we include
+ * t_stk in the range (the "+ 1", below), but the kernel should
+ * really include the full stack bounds where we can find it.
+ */
+ saddr = (uintptr_t)t->t_stkbase;
+ size = (uintptr_t)t->t_stk - saddr + 1;
+ while (mdb_whatis_match(w, saddr, size, &cur))
+ mdb_whatis_report_object(w, cur, cur,
+ "in thread %p's stack%s\n", addr, stack_active(t, cur));
+
+ return (WHATIS_WALKRET(w));
+}
+
+static void
+whatis_modctl_match(mdb_whatis_t *w, const char *name,
+ uintptr_t base, size_t size, const char *where)
+{
+ uintptr_t cur;
+
+ /*
+ * Since we're searching for addresses inside a module, we report
+ * them as symbols.
+ */
+ while (mdb_whatis_match(w, base, size, &cur))
+ mdb_whatis_report_address(w, cur, "in %s's %s\n", name, where);
}
static int
-whatis_walk_modctl(uintptr_t addr, const struct modctl *m, whatis_t *w)
+whatis_walk_modctl(uintptr_t addr, const struct modctl *m, mdb_whatis_t *w)
{
+ char name[MODMAXNAMELEN];
struct module mod;
- char name[MODMAXNAMELEN], *where;
Shdr shdr;
- GElf_Sym sym;
if (m->mod_mp == NULL)
return (WALK_NEXT);
@@ -2467,207 +2480,138 @@
return (WALK_NEXT);
}
- if (w->w_addr >= (uintptr_t)mod.text &&
- w->w_addr < (uintptr_t)mod.text + mod.text_size) {
- where = "text segment";
- goto found;
- }
-
- if (w->w_addr >= (uintptr_t)mod.data &&
- w->w_addr < (uintptr_t)mod.data + mod.data_size) {
- where = "data segment";
- goto found;
- }
-
- if (w->w_addr >= (uintptr_t)mod.bss &&
- w->w_addr < (uintptr_t)mod.bss + mod.bss_size) {
- where = "bss";
- goto found;
- }
+ if (mdb_readstr(name, sizeof (name), (uintptr_t)m->mod_modname) == -1)
+ (void) mdb_snprintf(name, sizeof (name), "0x%p", addr);
+
+ whatis_modctl_match(w, name,
+ (uintptr_t)mod.text, mod.text_size, "text segment");
+ whatis_modctl_match(w, name,
+ (uintptr_t)mod.data, mod.data_size, "data segment");
+ whatis_modctl_match(w, name,
+ (uintptr_t)mod.bss, mod.bss_size, "bss segment");
if (mdb_vread(&shdr, sizeof (shdr), (uintptr_t)mod.symhdr) == -1) {
mdb_warn("couldn't read symbol header for %p's module", addr);
return (WALK_NEXT);
}
- if (w->w_addr >= (uintptr_t)mod.symtbl && w->w_addr <
- (uintptr_t)mod.symtbl + (uintptr_t)mod.nsyms * shdr.sh_entsize) {
- where = "symtab";
- goto found;
- }
-
- if (w->w_addr >= (uintptr_t)mod.symspace &&
- w->w_addr < (uintptr_t)mod.symspace + (uintptr_t)mod.symsize) {
- where = "symspace";
- goto found;
+ whatis_modctl_match(w, name,
+ (uintptr_t)mod.symtbl, mod.nsyms * shdr.sh_entsize, "symtab");
+ whatis_modctl_match(w, name,
+ (uintptr_t)mod.symspace, mod.symsize, "symtab");
+
+ return (WHATIS_WALKRET(w));
+}
+
+/*ARGSUSED*/
+static int
+whatis_walk_memseg(uintptr_t addr, const struct memseg *seg, mdb_whatis_t *w)
+{
+ uintptr_t cur;
+
+ uintptr_t base = (uintptr_t)seg->pages;
+ size_t size = (uintptr_t)seg->epages - base;
+
+ while (mdb_whatis_match(w, base, size, &cur)) {
+ /* round our found pointer down to the page_t base. */
+ size_t offset = (cur - base) % sizeof (page_t);
+
+ mdb_whatis_report_object(w, cur, cur - offset,
+ "allocated as a page structure\n");
}
- return (WALK_NEXT);
-
-found:
- if (mdb_readstr(name, sizeof (name), (uintptr_t)m->mod_modname) == -1)
- (void) mdb_snprintf(name, sizeof (name), "0x%p", addr);
-
- mdb_printf("%p is ", w->w_addr);
-
+ return (WHATIS_WALKRET(w));
+}
+
+/*ARGSUSED*/
+static int
+whatis_run_modules(mdb_whatis_t *w, void *arg)
+{
+ if (mdb_walk("modctl", (mdb_walk_cb_t)whatis_walk_modctl, w) == -1) {
+ mdb_warn("couldn't find modctl walker");
+ return (1);
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+whatis_run_threads(mdb_whatis_t *w, void *ignored)
+{
/*
- * If we found this address in a module, then there's a chance that
- * it's actually a named symbol. Try the symbol lookup.
+ * Now search all thread stacks. Yes, this is a little weak; we
+ * can save a lot of work by first checking to see if the
+ * address is in segkp vs. segkmem. But hey, computers are
+ * fast.
*/
- if (mdb_lookup_by_addr(w->w_addr, MDB_SYM_FUZZY, NULL, 0, &sym) != -1 &&
- (w->w_addr - (uintptr_t)sym.st_value) < sym.st_size) {
- mdb_printf("%a, ", w->w_addr);
+ if (mdb_walk("thread", (mdb_walk_cb_t)whatis_walk_thread, w) == -1) {
+ mdb_warn("couldn't find thread walker");
+ return (1);
}
-
- mdb_printf("in %s's %s\n", name, where);
-
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ return (0);
}
/*ARGSUSED*/
static int
-whatis_walk_page(uintptr_t addr, const void *ignored, whatis_t *w)
+whatis_run_pages(mdb_whatis_t *w, void *ignored)
{
- static int machsize = 0;
- mdb_ctf_id_t id;
-
- if (machsize == 0) {
- if (mdb_ctf_lookup_by_name("unix`page_t", &id) == 0)
- machsize = mdb_ctf_type_size(id);
- else {
- mdb_warn("could not get size of page_t");
- machsize = sizeof (page_t);
- }
+ if (mdb_walk("memseg", (mdb_walk_cb_t)whatis_walk_memseg, w) == -1) {
+ mdb_warn("couldn't find memseg walker");
+ return (1);
}
-
- if (w->w_addr < addr || w->w_addr >= addr + machsize)
- return (WALK_NEXT);
-
- whatis_report_pointer(w->w_addr, addr,
- "allocated as a page structure\n");
-
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ return (0);
}
-int
-whatis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+/*ARGSUSED*/
+static int
+whatis_run_kmem(mdb_whatis_t *w, void *ignored)
{
- whatis_t w;
-
- if (!(flags & DCMD_ADDRSPEC))
- return (DCMD_USAGE);
-
- w.w_all = FALSE;
- w.w_bufctl = FALSE;
- w.w_idspace = FALSE;
- w.w_quiet = FALSE;
- w.w_verbose = FALSE;
-
- if (mdb_getopts(argc, argv,
- 'a', MDB_OPT_SETBITS, TRUE, &w.w_all,
- 'b', MDB_OPT_SETBITS, TRUE, &w.w_bufctl,
- 'i', MDB_OPT_SETBITS, TRUE, &w.w_idspace,
- 'q', MDB_OPT_SETBITS, TRUE, &w.w_quiet,
- 'v', MDB_OPT_SETBITS, TRUE, &w.w_verbose,
- NULL) != argc)
- return (DCMD_USAGE);
-
- w.w_addr = addr;
- w.w_found = 0;
-
- if (w.w_verbose)
- mdb_printf("Searching modules...\n");
-
- if (!w.w_idspace) {
- if (mdb_walk("modctl", (mdb_walk_cb_t)whatis_walk_modctl, &w)
- == -1) {
- mdb_warn("couldn't find modctl walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
-
- /*
- * Now search all thread stacks. Yes, this is a little weak; we
- * can save a lot of work by first checking to see if the
- * address is in segkp vs. segkmem. But hey, computers are
- * fast.
- */
- if (w.w_verbose)
- mdb_printf("Searching threads...\n");
-
- if (mdb_walk("thread", (mdb_walk_cb_t)whatis_walk_thread, &w)
- == -1) {
- mdb_warn("couldn't find thread walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
-
- if (w.w_verbose)
- mdb_printf("Searching page structures...\n");
-
- if (mdb_walk("page", (mdb_walk_cb_t)whatis_walk_page, &w)
- == -1) {
- mdb_warn("couldn't find page walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
+ whatis_info_t wi;
+
+ bzero(&wi, sizeof (wi));
+ wi.wi_w = w;
+
+ if (mdb_readvar(&wi.wi_msb_arena, "kmem_msb_arena") == -1)
+ mdb_warn("unable to readvar \"kmem_msb_arena\"");
+
+ if (mdb_readvar(&wi.wi_kmem_lite_count,
+ "kmem_lite_count") == -1 || wi.wi_kmem_lite_count > 16)
+ wi.wi_kmem_lite_count = 0;
+
+ /*
+ * We process kmem caches in the following order:
+ *
+ * non-KMC_NOTOUCH, non-metadata (typically the most interesting)
+ * metadata (can be huge with KMF_AUDIT)
+ * KMC_NOTOUCH, non-metadata (see kmem_walk_all())
+ */
+ if (mdb_walk("kmem_cache", (mdb_walk_cb_t)whatis_walk_touch,
+ &wi) == -1 ||
+ mdb_walk("kmem_cache", (mdb_walk_cb_t)whatis_walk_metadata,
+ &wi) == -1 ||
+ mdb_walk("kmem_cache", (mdb_walk_cb_t)whatis_walk_notouch,
+ &wi) == -1) {
+ mdb_warn("couldn't find kmem_cache walker");
+ return (1);
}
-
- if (mdb_walk("kmem_cache",
- (mdb_walk_cb_t)whatis_walk_touch, &w) == -1) {
- mdb_warn("couldn't find kmem_cache walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
-
- if (mdb_walk("kmem_cache",
- (mdb_walk_cb_t)whatis_walk_notouch, &w) == -1) {
- mdb_warn("couldn't find kmem_cache walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+whatis_run_vmem(mdb_whatis_t *w, void *ignored)
+{
+ whatis_info_t wi;
+
+ bzero(&wi, sizeof (wi));
+ wi.wi_w = w;
if (mdb_walk("vmem_postfix",
- (mdb_walk_cb_t)whatis_walk_vmem, &w) == -1) {
+ (mdb_walk_cb_t)whatis_walk_vmem, &wi) == -1) {
mdb_warn("couldn't find vmem_postfix walker");
- return (DCMD_ERR);
+ return (1);
}
-
- if (w.w_found == 0)
- mdb_printf("%p is unknown\n", addr);
-
- return (DCMD_OK);
-}
-
-void
-whatis_help(void)
-{
- mdb_printf(
- "Given a virtual address, attempt to determine where it came\n"
- "from.\n"
- "\n"
- "\t-a\tFind all possible sources. Default behavior is to stop at\n"
- "\t\tthe first (most specific) source.\n"
- "\t-b\tReport bufctls and vmem_segs for matches in kmem and vmem,\n"
- "\t\trespectively. Warning: if the buffer exists, but does not\n"
- "\t\thave a bufctl, it will not be reported.\n"
- "\t-i\tSearch only identifier arenas and caches. By default\n"
- "\t\tthese are ignored.\n"
- "\t-q\tDon't print multi-line reports (stack traces, etc.)\n"
- "\t-v\tVerbose output; display caches/arenas/etc as they are\n"
- "\t\tsearched\n");
+ return (0);
}
typedef struct kmem_log_cpu {
@@ -4322,6 +4266,18 @@
}
kmem_statechange();
+
+ /* register our ::whatis handlers */
+ mdb_whatis_register("modules", whatis_run_modules, NULL,
+ WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
+ mdb_whatis_register("threads", whatis_run_threads, NULL,
+ WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
+ mdb_whatis_register("pages", whatis_run_pages, NULL,
+ WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
+ mdb_whatis_register("kmem", whatis_run_kmem, NULL,
+ WHATIS_PRIO_ALLOCATOR, 0);
+ mdb_whatis_register("vmem", whatis_run_vmem, NULL,
+ WHATIS_PRIO_ALLOCATOR, 0);
}
typedef struct whatthread {
--- a/usr/src/cmd/mdb/common/modules/genunix/kmem.h Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/genunix/kmem.h Tue Sep 22 13:42:17 2009 -0700
@@ -88,7 +88,6 @@
extern int kmem_slabs(uintptr_t, uint_t, int, const mdb_arg_t *);
extern int allocdby(uintptr_t, uint_t, int, const mdb_arg_t *);
extern int freedby(uintptr_t, uint_t, int, const mdb_arg_t *);
-extern int whatis(uintptr_t, uint_t, int, const mdb_arg_t *);
extern int kmem_log(uintptr_t, uint_t, int, const mdb_arg_t *);
extern int kmem_debug(uintptr_t, uint_t, int, const mdb_arg_t *);
extern int bufctl(uintptr_t, uint_t, int, const mdb_arg_t *);
@@ -101,7 +100,6 @@
extern int kmausers(uintptr_t, uint_t, int, const mdb_arg_t *);
extern void kmem_cache_help(void);
extern void kmem_slabs_help(void);
-extern void whatis_help(void);
extern void bufctl_help(void);
extern void vmem_seg_help(void);
extern void kmausers_help(void);
--- a/usr/src/cmd/mdb/common/modules/libc/libc.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/libc/libc.c Tue Sep 22 13:42:17 2009 -0700
@@ -25,6 +25,7 @@
*/
#include <sys/mdb_modapi.h>
+#include <mdb/mdb_whatis.h>
#include <procfs.h>
#include <ucontext.h>
#include <siginfo.h>
@@ -914,6 +915,61 @@
return (wsp->walk_callback(addr, &ulwp, wsp->walk_cbdata));
}
+/* Avoid classifying NULL pointers as part of the main stack on x86 */
+#define MIN_STACK_ADDR (0x10000ul)
+
+static int
+whatis_walk_ulwp(uintptr_t addr, const ulwp_t *ulwp, mdb_whatis_t *w)
+{
+ uintptr_t cur;
+ lwpid_t id = ulwp->ul_lwpid;
+ uintptr_t top, base, size;
+
+ while (mdb_whatis_match(w, addr, sizeof (ulwp_t), &cur))
+ mdb_whatis_report_object(w, cur, addr,
+ "allocated as thread %#r's ulwp_t\n", id);
+
+ top = (uintptr_t)ulwp->ul_stktop;
+ size = ulwp->ul_stksiz;
+
+ /*
+ * The main stack ends up being a little weird, especially if
+ * the stack ulimit is unlimited. This tries to take that into
+ * account.
+ */
+ if (size > top)
+ size = top;
+ if (top > MIN_STACK_ADDR && top - size < MIN_STACK_ADDR)
+ size = top - MIN_STACK_ADDR;
+
+ base = top - size;
+
+ while (mdb_whatis_match(w, base, size, &cur))
+ mdb_whatis_report_address(w, cur, "in [ stack tid=%#r ]\n", id);
+
+ if (ulwp->ul_ustack.ss_flags & SS_ONSTACK) {
+ base = (uintptr_t)ulwp->ul_ustack.ss_sp;
+ size = ulwp->ul_ustack.ss_size;
+
+ while (mdb_whatis_match(w, base, size, &cur))
+ mdb_whatis_report_address(w, cur,
+ "in [ altstack tid=%#r ]\n", id);
+ }
+
+ return (WHATIS_WALKRET(w));
+}
+
+/*ARGSUSED*/
+static int
+whatis_run_ulwps(mdb_whatis_t *w, void *arg)
+{
+ if (mdb_walk("ulwps", (mdb_walk_cb_t)whatis_walk_ulwp, w) == -1) {
+ mdb_warn("couldn't find ulwps walker");
+ return (1);
+ }
+ return (0);
+}
+
/*
* =======================================================
* End of thread (previously libthread) interfaces.
@@ -945,5 +1001,8 @@
const mdb_modinfo_t *
_mdb_init(void)
{
+ mdb_whatis_register("threads", whatis_run_ulwps, NULL,
+ WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
+
return (&modinfo);
}
--- a/usr/src/cmd/mdb/common/modules/libumem/libumem.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/libumem/libumem.c Tue Sep 22 13:42:17 2009 -0700
@@ -352,8 +352,6 @@
{ "vmem_seg", ":[-sv] [-c caller] [-e earliest] [-l latest] "
"[-m minsize] [-M maxsize] [-t thread] [-T type]",
"print or filter a vmem_seg", vmem_seg, vmem_seg_help },
- { "whatis", ":[-abqv]", "given an address, return information",
- whatis },
#ifndef _KMDB
/* from ../genunix/kgrep.c + libumem.c */
--- a/usr/src/cmd/mdb/common/modules/libumem/umem.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/common/modules/libumem/umem.c Tue Sep 22 13:42:17 2009 -0700
@@ -30,6 +30,7 @@
#include <alloca.h>
#include <limits.h>
+#include <mdb/mdb_whatis.h>
#include "misc.h"
#include "leaky.h"
@@ -145,29 +146,6 @@
}
int
-umem_init(void)
-{
- mdb_walker_t w = {
- "umem_cache", "walk list of umem caches", umem_cache_walk_init,
- umem_cache_walk_step, umem_cache_walk_fini
- };
-
- if (mdb_add_walker(&w) == -1) {
- mdb_warn("failed to add umem_cache walker");
- return (-1);
- }
-
- if (umem_update_variables() == -1)
- return (-1);
-
- /* install a callback so that our variables are always up-to-date */
- (void) mdb_callback_add(MDB_CALLBACK_STCHG, umem_statechange_cb, NULL);
- umem_statechange_cb(NULL);
-
- return (0);
-}
-
-int
umem_abort_messages(void)
{
char *umem_error_buffer;
@@ -1845,29 +1823,15 @@
return (allocdby_common(addr, flags, "freedby"));
}
-typedef struct whatis {
- uintptr_t w_addr;
- const umem_cache_t *w_cache;
- const vmem_t *w_vmem;
- int w_found;
- uint_t w_all;
- uint_t w_bufctl;
- uint_t w_freemem;
- uint_t w_quiet;
- uint_t w_verbose;
-} whatis_t;
-
-/* nicely report pointers as offsets from a base */
-static void
-whatis_report_pointer(uintptr_t addr, uintptr_t base, const char *description)
-{
- if (addr == base)
- mdb_printf("%p is %s",
- addr, description);
- else
- mdb_printf("%p is %p+%p, %s",
- addr, base, addr - base, description);
-}
+typedef struct whatis_info {
+ mdb_whatis_t *wi_w;
+ const umem_cache_t *wi_cache;
+ const vmem_t *wi_vmem;
+ vmem_t *wi_msb_arena;
+ size_t wi_slab_size;
+ int wi_slab_found;
+ uint_t wi_freemem;
+} whatis_info_t;
/* call one of our dcmd functions with "-v" and the provided address */
static void
@@ -1877,153 +1841,156 @@
a.a_type = MDB_TYPE_STRING;
a.a_un.a_str = "-v";
+ mdb_printf(":\n");
(void) (*dcmd)(addr, DCMD_ADDRSPEC, 1, &a);
}
static void
-whatis_print_umem(uintptr_t addr, uintptr_t baddr, whatis_t *w)
+whatis_print_umem(whatis_info_t *wi, uintptr_t maddr, uintptr_t addr,
+ uintptr_t baddr)
{
- const umem_cache_t *cp = w->w_cache;
- /* LINTED pointer cast may result in improper alignment */
- uintptr_t btaddr = (uintptr_t)UMEM_BUFTAG(cp, addr);
- intptr_t stat;
- int call_printer;
-
- if (cp->cache_flags & UMF_REDZONE) {
- umem_buftag_t bt;
-
- if (mdb_vread(&bt, sizeof (bt), btaddr) == -1)
- goto done;
-
- stat = (intptr_t)bt.bt_bufctl ^ bt.bt_bxstat;
-
- if (stat != UMEM_BUFTAG_ALLOC && stat != UMEM_BUFTAG_FREE)
- goto done;
-
- /*
- * provide the bufctl ptr if it has useful information
- */
- if (baddr == 0 && (cp->cache_flags & UMF_AUDIT))
- baddr = (uintptr_t)bt.bt_bufctl;
- }
-
-done:
- call_printer =
- (!w->w_quiet && baddr != 0 && (cp->cache_flags & UMF_AUDIT));
-
- whatis_report_pointer(w->w_addr, addr, "");
+ mdb_whatis_t *w = wi->wi_w;
+ const umem_cache_t *cp = wi->wi_cache;
+ int quiet = (mdb_whatis_flags(w) & WHATIS_QUIET);
+
+ int call_printer = (!quiet && (cp->cache_flags & UMF_AUDIT));
+
+ mdb_whatis_report_object(w, maddr, addr, "");
if (baddr != 0 && !call_printer)
mdb_printf("bufctl %p ", baddr);
- mdb_printf("%s from %s%s\n",
- (w->w_freemem == FALSE) ? "allocated" : "freed", cp->cache_name,
- call_printer ? ":" : "");
-
- if (call_printer)
+ mdb_printf("%s from %s",
+ (wi->wi_freemem == FALSE) ? "allocated" : "freed", cp->cache_name);
+
+ if (call_printer && baddr != 0) {
whatis_call_printer(bufctl, baddr);
+ return;
+ }
+ mdb_printf("\n");
+}
+
+/*ARGSUSED*/
+static int
+whatis_walk_umem(uintptr_t addr, void *ignored, whatis_info_t *wi)
+{
+ mdb_whatis_t *w = wi->wi_w;
+
+ uintptr_t cur;
+ size_t size = wi->wi_cache->cache_bufsize;
+
+ while (mdb_whatis_match(w, addr, size, &cur))
+ whatis_print_umem(wi, cur, addr, NULL);
+
+ return (WHATIS_WALKRET(w));
}
/*ARGSUSED*/
static int
-whatis_walk_umem(uintptr_t addr, void *ignored, whatis_t *w)
+whatis_walk_bufctl(uintptr_t baddr, const umem_bufctl_t *bcp, whatis_info_t *wi)
{
- if (w->w_addr < addr || w->w_addr >= addr + w->w_cache->cache_bufsize)
+ mdb_whatis_t *w = wi->wi_w;
+
+ uintptr_t cur;
+ uintptr_t addr = (uintptr_t)bcp->bc_addr;
+ size_t size = wi->wi_cache->cache_bufsize;
+
+ while (mdb_whatis_match(w, addr, size, &cur))
+ whatis_print_umem(wi, cur, addr, baddr);
+
+ return (WHATIS_WALKRET(w));
+}
+
+
+static int
+whatis_walk_seg(uintptr_t addr, const vmem_seg_t *vs, whatis_info_t *wi)
+{
+ mdb_whatis_t *w = wi->wi_w;
+
+ size_t size = vs->vs_end - vs->vs_start;
+ uintptr_t cur;
+
+ /* We're not interested in anything but alloc and free segments */
+ if (vs->vs_type != VMEM_ALLOC && vs->vs_type != VMEM_FREE)
return (WALK_NEXT);
- whatis_print_umem(addr, 0, w);
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ while (mdb_whatis_match(w, vs->vs_start, size, &cur)) {
+ mdb_whatis_report_object(w, cur, vs->vs_start, "");
+
+ /*
+ * If we're not printing it seperately, provide the vmem_seg
+ * pointer if it has a stack trace.
+ */
+ if ((mdb_whatis_flags(w) & WHATIS_QUIET) &&
+ ((mdb_whatis_flags(w) & WHATIS_BUFCTL) != 0 ||
+ (vs->vs_type == VMEM_ALLOC && vs->vs_depth != 0))) {
+ mdb_printf("vmem_seg %p ", addr);
+ }
+
+ mdb_printf("%s from %s vmem arena",
+ (vs->vs_type == VMEM_ALLOC) ? "allocated" : "freed",
+ wi->wi_vmem->vm_name);
+
+ if (!mdb_whatis_flags(w) & WHATIS_QUIET)
+ whatis_call_printer(vmem_seg, addr);
+ else
+ mdb_printf("\n");
+ }
+
+ return (WHATIS_WALKRET(w));
}
static int
-whatis_walk_seg(uintptr_t addr, const vmem_seg_t *vs, whatis_t *w)
+whatis_walk_vmem(uintptr_t addr, const vmem_t *vmem, whatis_info_t *wi)
{
- if (w->w_addr < vs->vs_start || w->w_addr >= vs->vs_end)
- return (WALK_NEXT);
-
- whatis_report_pointer(w->w_addr, vs->vs_start, "");
-
- /*
- * If we're not going to print it anyway, provide the vmem_seg pointer
- * if it has a stack trace.
- */
- if (w->w_quiet && (w->w_bufctl ||
- (vs->vs_type == VMEM_ALLOC && vs->vs_depth != 0))) {
- mdb_printf("vmem_seg %p ", addr);
- }
-
- mdb_printf("%s from %s vmem arena%s\n",
- (w->w_freemem == FALSE) ? "allocated" : "freed",
- w->w_vmem->vm_name, !w->w_quiet ? ":" : "");
-
- if (!w->w_quiet)
- whatis_call_printer(vmem_seg, addr);
-
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
-}
-
-static int
-whatis_walk_vmem(uintptr_t addr, const vmem_t *vmem, whatis_t *w)
-{
+ mdb_whatis_t *w = wi->wi_w;
const char *nm = vmem->vm_name;
- w->w_vmem = vmem;
- w->w_freemem = FALSE;
-
- if (w->w_verbose)
+ wi->wi_vmem = vmem;
+
+ if (mdb_whatis_flags(w) & WHATIS_VERBOSE)
mdb_printf("Searching vmem arena %s...\n", nm);
- if (mdb_pwalk("vmem_alloc",
- (mdb_walk_cb_t)whatis_walk_seg, w, addr) == -1) {
+ if (mdb_pwalk("vmem_seg",
+ (mdb_walk_cb_t)whatis_walk_seg, wi, addr) == -1) {
mdb_warn("can't walk vmem seg for %p", addr);
return (WALK_NEXT);
}
- if (w->w_found && w->w_all == FALSE)
- return (WALK_DONE);
-
- if (w->w_verbose)
- mdb_printf("Searching vmem arena %s for free virtual...\n", nm);
-
- w->w_freemem = TRUE;
-
- if (mdb_pwalk("vmem_free",
- (mdb_walk_cb_t)whatis_walk_seg, w, addr) == -1) {
- mdb_warn("can't walk vmem seg for %p", addr);
- return (WALK_NEXT);
- }
-
- return (w->w_found && w->w_all == FALSE ? WALK_DONE : WALK_NEXT);
+ return (WHATIS_WALKRET(w));
}
/*ARGSUSED*/
static int
-whatis_walk_bufctl(uintptr_t baddr, const umem_bufctl_t *bcp, whatis_t *w)
+whatis_walk_slab(uintptr_t saddr, const umem_slab_t *sp, whatis_info_t *wi)
{
- uintptr_t addr;
-
- if (bcp == NULL)
- return (WALK_NEXT);
-
- addr = (uintptr_t)bcp->bc_addr;
-
- if (w->w_addr < addr || w->w_addr >= addr + w->w_cache->cache_bufsize)
- return (WALK_NEXT);
-
- whatis_print_umem(addr, baddr, w);
- w->w_found++;
- return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE);
+ mdb_whatis_t *w = wi->wi_w;
+
+ /* It must overlap with the slab data, or it's not interesting */
+ if (mdb_whatis_overlaps(w,
+ (uintptr_t)sp->slab_base, wi->wi_slab_size)) {
+ wi->wi_slab_found++;
+ return (WALK_DONE);
+ }
+ return (WALK_NEXT);
}
static int
-whatis_walk_cache(uintptr_t addr, const umem_cache_t *c, whatis_t *w)
+whatis_walk_cache(uintptr_t addr, const umem_cache_t *c, whatis_info_t *wi)
{
+ mdb_whatis_t *w = wi->wi_w;
char *walk, *freewalk;
mdb_walk_cb_t func;
-
- /* For caches with auditing info, we always walk the bufctls */
- if (w->w_bufctl || (c->cache_flags & UMF_AUDIT)) {
+ int do_bufctl;
+
+ /* Override the '-b' flag as necessary */
+ if (!(c->cache_flags & UMF_HASH))
+ do_bufctl = FALSE; /* no bufctls to walk */
+ else if (c->cache_flags & UMF_AUDIT)
+ do_bufctl = TRUE; /* we always want debugging info */
+ else
+ do_bufctl = ((mdb_whatis_flags(w) & WHATIS_BUFCTL) != 0);
+
+ if (do_bufctl) {
walk = "bufctl";
freewalk = "freectl";
func = (mdb_walk_cb_t)whatis_walk_bufctl;
@@ -2033,109 +2000,163 @@
func = (mdb_walk_cb_t)whatis_walk_umem;
}
- if (w->w_verbose)
+ wi->wi_cache = c;
+
+ if (mdb_whatis_flags(w) & WHATIS_VERBOSE)
mdb_printf("Searching %s...\n", c->cache_name);
- w->w_cache = c;
- w->w_freemem = FALSE;
-
- if (mdb_pwalk(walk, func, w, addr) == -1) {
+ /*
+ * If more then two buffers live on each slab, figure out if we're
+ * interested in anything in any slab before doing the more expensive
+ * umem/freemem (bufctl/freectl) walkers.
+ */
+ wi->wi_slab_size = c->cache_slabsize - c->cache_maxcolor;
+ if (!(c->cache_flags & UMF_HASH))
+ wi->wi_slab_size -= sizeof (umem_slab_t);
+
+ if ((wi->wi_slab_size / c->cache_chunksize) > 2) {
+ wi->wi_slab_found = 0;
+ if (mdb_pwalk("umem_slab", (mdb_walk_cb_t)whatis_walk_slab, wi,
+ addr) == -1) {
+ mdb_warn("can't find umem_slab walker");
+ return (WALK_DONE);
+ }
+ if (wi->wi_slab_found == 0)
+ return (WALK_NEXT);
+ }
+
+ wi->wi_freemem = FALSE;
+ if (mdb_pwalk(walk, func, wi, addr) == -1) {
mdb_warn("can't find %s walker", walk);
return (WALK_DONE);
}
- if (w->w_found && w->w_all == FALSE)
+ if (mdb_whatis_done(w))
return (WALK_DONE);
/*
* We have searched for allocated memory; now search for freed memory.
*/
- if (w->w_verbose)
+ if (mdb_whatis_flags(w) & WHATIS_VERBOSE)
mdb_printf("Searching %s for free memory...\n", c->cache_name);
- w->w_freemem = TRUE;
-
- if (mdb_pwalk(freewalk, func, w, addr) == -1) {
+ wi->wi_freemem = TRUE;
+
+ if (mdb_pwalk(freewalk, func, wi, addr) == -1) {
mdb_warn("can't find %s walker", freewalk);
return (WALK_DONE);
}
- return (w->w_found && w->w_all == FALSE ? WALK_DONE : WALK_NEXT);
+ return (WHATIS_WALKRET(w));
+}
+
+static int
+whatis_walk_touch(uintptr_t addr, const umem_cache_t *c, whatis_info_t *wi)
+{
+ if (c->cache_arena == wi->wi_msb_arena ||
+ (c->cache_cflags & UMC_NOTOUCH))
+ return (WALK_NEXT);
+
+ return (whatis_walk_cache(addr, c, wi));
+}
+
+static int
+whatis_walk_metadata(uintptr_t addr, const umem_cache_t *c, whatis_info_t *wi)
+{
+ if (c->cache_arena != wi->wi_msb_arena)
+ return (WALK_NEXT);
+
+ return (whatis_walk_cache(addr, c, wi));
}
static int
-whatis_walk_touch(uintptr_t addr, const umem_cache_t *c, whatis_t *w)
+whatis_walk_notouch(uintptr_t addr, const umem_cache_t *c, whatis_info_t *wi)
{
- if (c->cache_cflags & UMC_NOTOUCH)
+ if (c->cache_arena == wi->wi_msb_arena ||
+ !(c->cache_cflags & UMC_NOTOUCH))
return (WALK_NEXT);
- return (whatis_walk_cache(addr, c, w));
+ return (whatis_walk_cache(addr, c, wi));
}
+/*ARGSUSED*/
static int
-whatis_walk_notouch(uintptr_t addr, const umem_cache_t *c, whatis_t *w)
+whatis_run_umem(mdb_whatis_t *w, void *ignored)
{
- if (!(c->cache_cflags & UMC_NOTOUCH))
- return (WALK_NEXT);
-
- return (whatis_walk_cache(addr, c, w));
+ whatis_info_t wi;
+
+ bzero(&wi, sizeof (wi));
+ wi.wi_w = w;
+
+ /* umem's metadata is allocated from the umem_internal_arena */
+ if (mdb_readvar(&wi.wi_msb_arena, "umem_internal_arena") == -1)
+ mdb_warn("unable to readvar \"umem_internal_arena\"");
+
+ /*
+ * We process umem caches in the following order:
+ *
+ * non-UMC_NOTOUCH, non-metadata (typically the most interesting)
+ * metadata (can be huge with UMF_AUDIT)
+ * UMC_NOTOUCH, non-metadata (see umem_walk_all())
+ */
+ if (mdb_walk("umem_cache", (mdb_walk_cb_t)whatis_walk_touch,
+ &wi) == -1 ||
+ mdb_walk("umem_cache", (mdb_walk_cb_t)whatis_walk_metadata,
+ &wi) == -1 ||
+ mdb_walk("umem_cache", (mdb_walk_cb_t)whatis_walk_notouch,
+ &wi) == -1) {
+ mdb_warn("couldn't find umem_cache walker");
+ return (1);
+ }
+ return (0);
+}
+
+/*ARGSUSED*/
+static int
+whatis_run_vmem(mdb_whatis_t *w, void *ignored)
+{
+ whatis_info_t wi;
+
+ bzero(&wi, sizeof (wi));
+ wi.wi_w = w;
+
+ if (mdb_walk("vmem_postfix",
+ (mdb_walk_cb_t)whatis_walk_vmem, &wi) == -1) {
+ mdb_warn("couldn't find vmem_postfix walker");
+ return (1);
+ }
+ return (0);
}
int
-whatis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+umem_init(void)
{
- whatis_t w;
-
- if (!(flags & DCMD_ADDRSPEC))
- return (DCMD_USAGE);
-
- w.w_all = FALSE;
- w.w_bufctl = FALSE;
- w.w_quiet = FALSE;
- w.w_verbose = FALSE;
-
- if (mdb_getopts(argc, argv,
- 'a', MDB_OPT_SETBITS, TRUE, &w.w_all,
- 'b', MDB_OPT_SETBITS, TRUE, &w.w_bufctl,
- 'q', MDB_OPT_SETBITS, TRUE, &w.w_quiet,
- 'v', MDB_OPT_SETBITS, TRUE, &w.w_verbose,
- NULL) != argc)
- return (DCMD_USAGE);
-
- w.w_addr = addr;
- w.w_found = 0;
+ mdb_walker_t w = {
+ "umem_cache", "walk list of umem caches", umem_cache_walk_init,
+ umem_cache_walk_step, umem_cache_walk_fini
+ };
+
+ if (mdb_add_walker(&w) == -1) {
+ mdb_warn("failed to add umem_cache walker");
+ return (-1);
+ }
+
+ if (umem_update_variables() == -1)
+ return (-1);
+
+ /* install a callback so that our variables are always up-to-date */
+ (void) mdb_callback_add(MDB_CALLBACK_STCHG, umem_statechange_cb, NULL);
+ umem_statechange_cb(NULL);
/*
- * Mappings and threads should eventually be added here.
+ * Register our ::whatis callbacks.
*/
- if (mdb_walk("umem_cache",
- (mdb_walk_cb_t)whatis_walk_touch, &w) == -1) {
- mdb_warn("couldn't find umem_cache walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
-
- if (mdb_walk("umem_cache",
- (mdb_walk_cb_t)whatis_walk_notouch, &w) == -1) {
- mdb_warn("couldn't find umem_cache walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found && w.w_all == FALSE)
- return (DCMD_OK);
-
- if (mdb_walk("vmem_postfix",
- (mdb_walk_cb_t)whatis_walk_vmem, &w) == -1) {
- mdb_warn("couldn't find vmem_postfix walker");
- return (DCMD_ERR);
- }
-
- if (w.w_found == 0)
- mdb_printf("%p is unknown\n", addr);
-
- return (DCMD_OK);
+ mdb_whatis_register("umem", whatis_run_umem, NULL,
+ WHATIS_PRIO_ALLOCATOR, WHATIS_REG_NO_ID);
+ mdb_whatis_register("vmem", whatis_run_vmem, NULL,
+ WHATIS_PRIO_ALLOCATOR, WHATIS_REG_NO_ID);
+
+ return (0);
}
typedef struct umem_log_cpu {
--- a/usr/src/cmd/mdb/intel/Makefile.kmdb Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/intel/Makefile.kmdb Tue Sep 22 13:42:17 2009 -0700
@@ -19,11 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
PROMSRCS += \
prom_env.c \
@@ -66,14 +64,7 @@
KMDBLIBS = $(STANDLIBS) ../mdb_ks/kmod/mdb_ks
MAPFILE_SOURCES = \
- ../../../common/mdb/mdb_ctf.h \
- ../../../common/kmdb/kmdb_dpi.h \
- ../../../common/kmdb/kmdb_kctl.h \
- ../../../common/kmdb/kmdb_kdi.h \
- ../../../common/mdb/mdb_ks.h \
- ../../../common/mdb/mdb_modapi.h \
- ../../../common/mdb/mdb_param.h \
- ../../../common/kmdb/kmdb_wr.h \
+ $(MAPFILE_SOURCES_COMMON) \
../../kmdb/kmdb_dpi_isadep.h \
$(MAPFILE_SOURCES_$(MACH))
--- a/usr/src/cmd/mdb/sparc/Makefile.kmdb Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/sparc/Makefile.kmdb Tue Sep 22 13:42:17 2009 -0700
@@ -2,9 +2,8 @@
# 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.
+# 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
# or http://www.opensolaris.org/os/licensing.
@@ -20,21 +19,13 @@
# CDDL HEADER END
#
#
-# Copyright 2005 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
SACPPFLAGS = -D__sparc
MAPFILE_SOURCES = \
- ../../../common/mdb/mdb_ctf.h \
- ../../../common/kmdb/kmdb_dpi.h \
- ../../../common/kmdb/kmdb_kctl.h \
- ../../../common/kmdb/kmdb_kdi.h \
- ../../../common/mdb/mdb_ks.h \
- ../../../common/mdb/mdb_modapi.h \
- ../../../common/mdb/mdb_param.h \
- ../../../common/kmdb/kmdb_wr.h \
+ $(MAPFILE_SOURCES_COMMON) \
../../../sparc/kmdb/kmdb_dpi_isadep.h \
$(MAPFILE_SOURCES_$(MACH))
--- a/usr/src/cmd/mdb/sun4u/Makefile.kmdb Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/sun4u/Makefile.kmdb Tue Sep 22 13:42:17 2009 -0700
@@ -19,10 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
PROMSRCS += \
prom_2path.c \
@@ -80,14 +79,7 @@
KMDBLIBS = $(STANDLIBS) ../../../sparc/v9/mdb_ks/kmod/mdb_ks
MAPFILE_SOURCES = \
- ../../../common/mdb/mdb_ctf.h \
- ../../../common/kmdb/kmdb_dpi.h \
- ../../../common/kmdb/kmdb_kctl.h \
- ../../../common/kmdb/kmdb_kdi.h \
- ../../../common/mdb/mdb_ks.h \
- ../../../common/mdb/mdb_modapi.h \
- ../../../common/mdb/mdb_param.h \
- ../../../common/kmdb/kmdb_wr.h \
+ $(MAPFILE_SOURCES_COMMON) \
../../../sparc/kmdb/kmdb_dpi_isadep.h \
$(MAPFILE_SOURCES_$(MACH))
--- a/usr/src/cmd/mdb/sun4u/modules/unix/unix.c Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/sun4u/modules/unix/unix.c Tue Sep 22 13:42:17 2009 -0700
@@ -19,12 +19,10 @@
* CDDL HEADER END
*/
/*
- * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
-#pragma ident "%Z%%M% %I% %E% SMI"
-
#include <sys/types.h>
#ifndef DEBUG
@@ -45,6 +43,7 @@
#include <mdb/mdb_modapi.h>
#include <mdb/mdb_ctf.h>
+#include <mdb/mdb_whatis.h>
#include "sfmmu.h"
#ifndef SYSTRAP_TT
@@ -882,7 +881,7 @@
htraptrace_buf_inuse = 1;
mdb_vread(&hdr, sizeof (htrap_trace_hdr_t),
- (uintptr_t)ctl->d.hvaddr_base);
+ (uintptr_t)ctl->d.hvaddr_base);
mdb_printf("htrap_trace_ctl[%d] = {\n", i);
mdb_printf(" vaddr_base = 0x%lx\n", (long)ctl->d.hvaddr_base);
mdb_printf(" last_offset = 0x%lx\n", hdr.last_offset);
@@ -917,8 +916,8 @@
ttstr = ttp->tt_tt < ttndescr ? ttdescr[ttp->tt_tt] : "?";
mdb_printf("%016llx %02x %04hx %04hx %-16s %02x %02x %0?p %A\n",
- ttp->tt_tick, ttp->tt_ty, ttp->tt_tag, ttp->tt_tt, ttstr,
- ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc, ttp->tt_tpc);
+ ttp->tt_tick, ttp->tt_ty, ttp->tt_tag, ttp->tt_tt, ttstr,
+ ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc, ttp->tt_tpc);
return (WALK_NEXT);
}
@@ -935,10 +934,10 @@
return (WALK_NEXT);
mdb_printf("%016llx %016llx %02x %02x %04hx %04hx %02x %02x %0?p "
- "[%p,%p,%p,%p]\n",
- ttp->tt_tick, ttp->tt_tstate, ttp->tt_hpstate, ttp->tt_ty,
- ttp->tt_tag, ttp->tt_tt, ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc,
- ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4);
+ "[%p,%p,%p,%p]\n",
+ ttp->tt_tick, ttp->tt_tstate, ttp->tt_hpstate, ttp->tt_ty,
+ ttp->tt_tag, ttp->tt_tt, ttp->tt_tl, ttp->tt_gl, ttp->tt_tpc,
+ ttp->tt_f1, ttp->tt_f2, ttp->tt_f3, ttp->tt_f4);
return (WALK_NEXT);
}
@@ -1006,9 +1005,9 @@
} else {
hdr = (htrap_trace_hdr_t *)buf;
tc->tc_rec = (struct htrap_trace_record *)
- ((uintptr_t)buf + (uintptr_t)hdr->last_offset);
+ ((uintptr_t)buf + (uintptr_t)hdr->last_offset);
tc->tc_stop = (struct htrap_trace_record *)
- ((uintptr_t)buf + (uintptr_t)hdr->offset);
+ ((uintptr_t)buf + (uintptr_t)hdr->offset);
}
}
if (!htraptrace_buf_inuse) {
@@ -1114,13 +1113,13 @@
if (opt_x) {
mdb_printf("%-16s %-16s %-3s %-3s %-4s %-4s %-3s %-3s %-?s "
- "F1-4\n", "%tick", "%tstate", "%hp", "%ty", "%tag",
- "%tt", "%tl", "%gl", "%tpc");
+ "F1-4\n", "%tick", "%tstate", "%hp", "%ty", "%tag",
+ "%tt", "%tl", "%gl", "%tpc");
ttprint = (mdb_walk_cb_t)httprint_long;
} else {
mdb_printf("%-16s %-3s %-4s %-4s %-16s %-3s %-3s %s\n",
- "%tick", "%ty", "%tag", "%tt", "", "%tl", "%gl",
- "%tpc");
+ "%tick", "%ty", "%tag", "%tt", "", "%tl", "%gl",
+ "%tpc");
ttprint = (mdb_walk_cb_t)httprint_short;
}
@@ -1520,38 +1519,32 @@
}
static int
-whatis_walk_tt(uintptr_t taddr, const trap_trace_fullrec_t *ttf, uintptr_t *ap)
+whatis_walk_tt(uintptr_t taddr, const trap_trace_fullrec_t *ttf,
+ mdb_whatis_t *w)
{
- uintptr_t addr = *ap;
+ uintptr_t cur = 0;
- if (addr < taddr || addr > taddr + sizeof (struct trap_trace_record))
- return (WALK_NEXT);
+ while (mdb_whatis_match(w, taddr, sizeof (struct trap_trace_record),
+ &cur))
+ mdb_whatis_report_object(w, cur, taddr,
+ "trap trace record for cpu %d\n", ttf->ttf_cpu);
- mdb_printf("%p is %p+%p, trap trace record for cpu %d\n",
- addr, taddr, addr - taddr, ttf->ttf_cpu);
-
- mdb_set_dot(1);
- return (WALK_DONE);
+ return (WHATIS_WALKRET(w));
}
/*ARGSUSED*/
-int
-whatis(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
+static int
+whatis_run_traptrace(mdb_whatis_t *w, void *ignored)
{
GElf_Sym sym;
- if (!(flags & DCMD_ADDRSPEC))
- return (DCMD_USAGE);
+ if (mdb_lookup_by_name("trap_trace_ctl", &sym) == -1)
+ return (0);
- if (mdb_lookup_by_name("trap_trace_ctl", &sym) == -1)
- return (DCMD_NEXT);
-
- mdb_set_dot(0);
-
- if (mdb_walk("ttrace", (mdb_walk_cb_t)whatis_walk_tt, &addr) == -1)
+ if (mdb_walk("ttrace", (mdb_walk_cb_t)whatis_walk_tt, w) == -1)
mdb_warn("failed to walk 'ttrace'");
- return (DCMD_NEXT);
+ return (0);
}
/*ARGSUSED*/
@@ -1598,7 +1591,6 @@
vecint_dcmd },
{ "softint", NULL, "display a registered software interrupt",
softint_dcmd },
- { "whatis", ":[-abv]", "given an address, return information", whatis },
{ "sfmmu_vtop", ":[[-v] -a as]", "print virtual to physical mapping",
sfmmu_vtop },
{ "page_num2pp", ":", "page frame number to page structure",
@@ -1639,5 +1631,8 @@
return (NULL);
}
+ mdb_whatis_register("traptrace", whatis_run_traptrace, NULL,
+ WHATIS_PRIO_EARLY, WHATIS_REG_NO_ID);
+
return (&modinfo);
}
--- a/usr/src/cmd/mdb/sun4v/Makefile.kmdb Tue Sep 22 13:42:10 2009 -0700
+++ b/usr/src/cmd/mdb/sun4v/Makefile.kmdb Tue Sep 22 13:42:17 2009 -0700
@@ -19,10 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
PROMSRCS += \
prom_2path.c \
@@ -89,14 +88,7 @@
KMDBLIBS = $(STANDLIBS) ../../../sparc/v9/mdb_ks/kmod/mdb_ks
MAPFILE_SOURCES = \
- ../../../common/mdb/mdb_ctf.h \
- ../../../common/kmdb/kmdb_dpi.h \
- ../../../common/kmdb/kmdb_kctl.h \
- ../../../common/kmdb/kmdb_kdi.h \
- ../../../common/mdb/mdb_ks.h \
- ../../../common/mdb/mdb_modapi.h \
- ../../../common/mdb/mdb_param.h \
- ../../../common/kmdb/kmdb_wr.h \
+ $(MAPFILE_SOURCES_COMMON) \
../../../sparc/kmdb/kmdb_dpi_isadep.h \
$(MAPFILE_SOURCES_$(MACH))