diff options
author | Jonathan Adams <Jonathan.Adams@Sun.COM> | 2009-09-22 13:42:17 -0700 |
---|---|---|
committer | Jonathan Adams <Jonathan.Adams@Sun.COM> | 2009-09-22 13:42:17 -0700 |
commit | 4a1c24318fe7c9bdae38ce58a2e4624597d297e2 (patch) | |
tree | 7600cfc8c09b4048e1b5ba35af08deaa6674cd67 /usr/src/cmd/mdb/common/modules/genunix | |
parent | 57f8140f6a54fd2ffd46f34a9d2c36071a5ac58e (diff) | |
download | illumos-gate-4a1c24318fe7c9bdae38ce58a2e4624597d297e2.tar.gz |
6881824 ::whatis needs to be faster, smarter, and modular
Diffstat (limited to 'usr/src/cmd/mdb/common/modules/genunix')
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/genunix.c | 2 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/kmem.c | 728 | ||||
-rw-r--r-- | usr/src/cmd/mdb/common/modules/genunix/kmem.h | 2 |
3 files changed, 342 insertions, 390 deletions
diff --git a/usr/src/cmd/mdb/common/modules/genunix/genunix.c b/usr/src/cmd/mdb/common/modules/genunix/genunix.c index 28b2794519..c2f2653466 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/genunix.c +++ b/usr/src/cmd/mdb/common/modules/genunix/genunix.c @@ -4437,8 +4437,6 @@ static const mdb_dcmd_t dcmds[] = { { "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 }, diff --git a/usr/src/cmd/mdb/common/modules/genunix/kmem.c b/usr/src/cmd/mdb/common/modules/genunix/kmem.c index 7f019ebbb7..6aad6c64c2 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/kmem.c +++ b/usr/src/cmd/mdb/common/modules/genunix/kmem.c @@ -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 @@ stack_active(const kthread_t *t, uintptr_t addr) 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 @@ whatis_call_printer(mdb_dcmd_f *dcmd, uintptr_t addr) 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; - /* LINTED pointer cast may result in improper alignment */ - uintptr_t btaddr = (uintptr_t)KMEM_BUFTAG(cp, addr); +#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; - int call_printer; - int count = 0; + const char *plural = ""; 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; + /* validate our arguments and read in the buftag */ + if (count == 0 || count > KMEM_LITE_MAX || + mdb_vread(&bt, sizeof (bt), btaddr) == -1) + return; - if (stat != KMEM_BUFTAG_ALLOC && stat != KMEM_BUFTAG_FREE) - goto done; + /* validate the buffer state and read in the callers */ + stat = (intptr_t)bt.bt_bufctl ^ bt.bt_bxstat; - /* - * provide the bufctl ptr if it has useful information - */ - if (baddr == 0 && (cp->cache_flags & KMF_AUDIT)) - baddr = (uintptr_t)bt.bt_bufctl; + 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 (cp->cache_flags & KMF_LITE) { - count = w->w_kmem_lite_count; + /* If there aren't any filled in callers, bail */ + if (callers[0] == uninit) + return; - if (count * sizeof (pc_t) > sizeof (callers)) - count = 0; + plural = (callers[1] == uninit) ? "" : "s"; - if (count > 0 && - mdb_vread(callers, count * sizeof (pc_t), - btaddr + - offsetof(kmem_buftag_lite_t, bt_history)) == -1) - count = 0; + /* Everything's done and checked; print them out */ + mdb_printf(":\n"); - /* - * skip unused callers - */ - while (count > 0 && callers[count - 1] == - (pc_t)KMEM_UNINITIALIZED_PATTERN) - count--; - } + 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); +} -done: - call_printer = - (!w->w_quiet && baddr != 0 && (cp->cache_flags & KMF_AUDIT)); +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); + int quiet = (mdb_whatis_flags(w) & WHATIS_QUIET); + int call_printer = (!quiet && (cp->cache_flags & KMF_AUDIT)); - whatis_report_pointer(w->w_addr, addr, ""); + 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)) ? ":" : ""); + mdb_printf("%s from %s", + (wi->wi_freemem == FALSE) ? "allocated" : "freed", cp->cache_name); - if (call_printer) + 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_t *w) +whatis_walk_kmem(uintptr_t addr, void *ignored, whatis_info_t *wi) { - if (w->w_addr < addr || w->w_addr >= addr + w->w_cache->cache_bufsize) - return (WALK_NEXT); + 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); - whatis_print_kmem(addr, 0, w); - w->w_found++; - return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE); + return (WHATIS_WALKRET(w)); } +/*ARGSUSED*/ static int -whatis_walk_seg(uintptr_t addr, const vmem_seg_t *vs, whatis_t *w) +whatis_walk_bufctl(uintptr_t baddr, const kmem_bufctl_t *bcp, 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 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); - } + mdb_whatis_t *w = wi->wi_w; - mdb_printf("%s from %s vmem arena%s\n", - (w->w_freemem == FALSE) ? "allocated" : "freed", w->w_vmem->vm_name, - !w->w_quiet ? ":" : ""); + uintptr_t cur; + uintptr_t addr = (uintptr_t)bcp->bc_addr; + size_t size = wi->wi_cache->cache_bufsize; - if (!w->w_quiet) - whatis_call_printer(vmem_seg, addr); + while (mdb_whatis_match(w, addr, size, &cur)) + whatis_print_kmem(wi, cur, addr, baddr); - 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_seg(uintptr_t addr, const vmem_seg_t *vs, whatis_info_t *wi) { - const char *nm = vmem->vm_name; - w->w_vmem = vmem; - w->w_freemem = FALSE; + mdb_whatis_t *w = wi->wi_w; - if (((vmem->vm_cflags & VMC_IDENTIFIER) != 0) ^ w->w_idspace) - return (WALK_NEXT); + size_t size = vs->vs_end - vs->vs_start; + uintptr_t cur; - if (w->w_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); + /* 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); - } - if (w->w_found && w->w_all == FALSE) - return (WALK_DONE); + while (mdb_whatis_match(w, vs->vs_start, size, &cur)) { + mdb_whatis_report_object(w, cur, vs->vs_start, ""); - if (w->w_verbose) - mdb_printf("Searching vmem arena %s for free virtual...\n", nm); + /* + * 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); + } - w->w_freemem = TRUE; + mdb_printf("%s from the %s vmem arena", + (vs->vs_type == VMEM_ALLOC) ? "allocated" : "freed", + wi->wi_vmem->vm_name); - 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); + if (!(mdb_whatis_flags(w) & WHATIS_QUIET)) + whatis_call_printer(vmem_seg, addr); + else + mdb_printf("\n"); } - 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_vmem(uintptr_t addr, const vmem_t *vmem, whatis_info_t *wi) { - uintptr_t addr; + mdb_whatis_t *w = wi->wi_w; + const char *nm = vmem->vm_name; + + int identifier = ((vmem->vm_cflags & VMC_IDENTIFIER) != 0); + int idspace = ((mdb_whatis_flags(w) & WHATIS_IDSPACE) != 0); - if (bcp == NULL) + if (identifier != idspace) return (WALK_NEXT); - addr = (uintptr_t)bcp->bc_addr; + wi->wi_vmem = vmem; - if (w->w_addr < addr || w->w_addr >= addr + w->w_cache->cache_bufsize) + if (mdb_whatis_flags(w) & WHATIS_VERBOSE) + mdb_printf("Searching vmem arena %s...\n", nm); + + 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); + } - whatis_print_kmem(addr, baddr, w); - w->w_found++; - return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE); + return (WHATIS_WALKRET(w)); } /*ARGSUSED*/ static int -whatis_walk_slab(uintptr_t saddr, const kmem_slab_t *sp, whatis_t *w) +whatis_walk_slab(uintptr_t saddr, const kmem_slab_t *sp, whatis_info_t *wi) { - uintptr_t base = P2ALIGN((uintptr_t)sp->slab_base, w->w_slab_align); + mdb_whatis_t *w = wi->wi_w; - if ((w->w_addr - base) >= w->w_cache->cache_slabsize) - return (WALK_NEXT); - - w->w_slab_found++; - return (WALK_DONE); + /* 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; + int do_bufctl; - if (((c->cache_flags & KMC_IDENTIFIER) != 0) ^ w->w_idspace) + 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 @@ whatis_walk_cache(uintptr_t addr, const kmem_cache_t *c, whatis_t *w) func = (mdb_walk_cb_t)whatis_walk_kmem; } - w->w_cache = c; + wi->wi_cache = c; - if (w->w_verbose) - mdb_printf("Searching %s's slabs...\n", c->cache_name); + 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; - } + 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 ((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; - } - - 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 ((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); } - 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_t *w) +whatis_walk_touch(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, wi)); +} + +static int +whatis_walk_metadata(uintptr_t addr, const kmem_cache_t *c, whatis_info_t *wi) +{ + 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)); + /* + * 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; - w->w_found++; - return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE); + /* + * 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 @@ whatis_walk_modctl(uintptr_t addr, const struct modctl *m, whatis_t *w) 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 (mdb_readstr(name, sizeof (name), (uintptr_t)m->mod_modname) == -1) + (void) mdb_snprintf(name, sizeof (name), "0x%p", addr); - if (w->w_addr >= (uintptr_t)mod.bss && - w->w_addr < (uintptr_t)mod.bss + mod.bss_size) { - where = "bss"; - goto found; - } + 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; - } + 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"); - if (w->w_addr >= (uintptr_t)mod.symspace && - w->w_addr < (uintptr_t)mod.symspace + (uintptr_t)mod.symsize) { - where = "symspace"; - goto found; - } + return (WHATIS_WALKRET(w)); +} - return (WALK_NEXT); +/*ARGSUSED*/ +static int +whatis_walk_memseg(uintptr_t addr, const struct memseg *seg, mdb_whatis_t *w) +{ + uintptr_t cur; -found: - if (mdb_readstr(name, sizeof (name), (uintptr_t)m->mod_modname) == -1) - (void) mdb_snprintf(name, sizeof (name), "0x%p", addr); + uintptr_t base = (uintptr_t)seg->pages; + size_t size = (uintptr_t)seg->epages - base; - mdb_printf("%p is ", w->w_addr); + 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); - /* - * If we found this address in a module, then there's a chance that - * it's actually a named symbol. Try the symbol lookup. - */ - 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); + mdb_whatis_report_object(w, cur, cur - offset, + "allocated as a page structure\n"); } - mdb_printf("in %s's %s\n", name, where); - - w->w_found++; - return (w->w_all == TRUE ? WALK_NEXT : WALK_DONE); + return (WHATIS_WALKRET(w)); } /*ARGSUSED*/ static int -whatis_walk_page(uintptr_t addr, const void *ignored, whatis_t *w) +whatis_run_modules(mdb_whatis_t *w, void *arg) { - 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("modctl", (mdb_walk_cb_t)whatis_walk_modctl, w) == -1) { + mdb_warn("couldn't find modctl 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_threads(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"); + /* + * 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_walk("thread", (mdb_walk_cb_t)whatis_walk_thread, w) == -1) { + mdb_warn("couldn't find thread walker"); + return (1); + } + return (0); +} - if (mdb_walk("thread", (mdb_walk_cb_t)whatis_walk_thread, &w) - == -1) { - mdb_warn("couldn't find thread walker"); - return (DCMD_ERR); - } +/*ARGSUSED*/ +static int +whatis_run_pages(mdb_whatis_t *w, void *ignored) +{ + if (mdb_walk("memseg", (mdb_walk_cb_t)whatis_walk_memseg, w) == -1) { + mdb_warn("couldn't find memseg walker"); + return (1); + } + return (0); +} - if (w.w_found && w.w_all == FALSE) - return (DCMD_OK); +/*ARGSUSED*/ +static int +whatis_run_kmem(mdb_whatis_t *w, void *ignored) +{ + whatis_info_t wi; - if (w.w_verbose) - mdb_printf("Searching page structures...\n"); + bzero(&wi, sizeof (wi)); + wi.wi_w = w; - if (mdb_walk("page", (mdb_walk_cb_t)whatis_walk_page, &w) - == -1) { - mdb_warn("couldn't find page walker"); - return (DCMD_ERR); - } + if (mdb_readvar(&wi.wi_msb_arena, "kmem_msb_arena") == -1) + mdb_warn("unable to readvar \"kmem_msb_arena\""); - if (w.w_found && w.w_all == FALSE) - return (DCMD_OK); - } + if (mdb_readvar(&wi.wi_kmem_lite_count, + "kmem_lite_count") == -1 || wi.wi_kmem_lite_count > 16) + wi.wi_kmem_lite_count = 0; - if (mdb_walk("kmem_cache", - (mdb_walk_cb_t)whatis_walk_touch, &w) == -1) { + /* + * 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 (DCMD_ERR); + return (1); } + return (0); +} - 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); - } +/*ARGSUSED*/ +static int +whatis_run_vmem(mdb_whatis_t *w, void *ignored) +{ + whatis_info_t wi; - if (w.w_found && w.w_all == FALSE) - return (DCMD_OK); + 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_init(void) } 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 { diff --git a/usr/src/cmd/mdb/common/modules/genunix/kmem.h b/usr/src/cmd/mdb/common/modules/genunix/kmem.h index bdff5e2daf..dc5fd2eb11 100644 --- a/usr/src/cmd/mdb/common/modules/genunix/kmem.h +++ b/usr/src/cmd/mdb/common/modules/genunix/kmem.h @@ -88,7 +88,6 @@ extern int kmem_cache(uintptr_t, uint_t, int, const mdb_arg_t *); 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 kmalog(uintptr_t, uint_t, int, const mdb_arg_t *); 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); |