Mercurial > illumos > illumos-gate
changeset 10610:218c21980cfd
6881824 ::whatis needs to be faster, smarter, and modular
line wrap: on
line diff
--- 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))