Print this page
9525 kmem_dump_size is a corrupting influence


   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2011 Joyent, Inc.  All rights reserved.
  28  * Copyright (c) 2012 by Delphix. All rights reserved.
  29  */
  30 
  31 #include <mdb/mdb_param.h>
  32 #include <mdb/mdb_modapi.h>
  33 #include <mdb/mdb_ctf.h>
  34 #include <mdb/mdb_whatis.h>
  35 #include <sys/cpuvar.h>
  36 #include <sys/kmem_impl.h>
  37 #include <sys/vmem_impl.h>
  38 #include <sys/machelf.h>
  39 #include <sys/modctl.h>
  40 #include <sys/kobj.h>
  41 #include <sys/panic.h>
  42 #include <sys/stack.h>
  43 #include <sys/sysmacros.h>
  44 #include <vm/page.h>
  45 
  46 #include "avl.h"
  47 #include "combined.h"


2995                         if (mdb_lookup_by_addr(bc.bc_stack[i],
2996                             MDB_SYM_FUZZY, c, sizeof (c), &sym) == -1)
2997                                 continue;
2998                         if (strncmp(c, "kmem_", 5) == 0)
2999                                 continue;
3000                         mdb_printf(" %a\n", bc.bc_stack[i]);
3001                         break;
3002                 }
3003 
3004                 if (i >= depth)
3005                         mdb_printf("\n");
3006         }
3007 
3008         return (DCMD_OK);
3009 }
3010 
3011 typedef struct kmem_verify {
3012         uint64_t *kmv_buf;              /* buffer to read cache contents into */
3013         size_t kmv_size;                /* number of bytes in kmv_buf */
3014         int kmv_corruption;             /* > 0 if corruption found. */
3015         int kmv_besilent;               /* report actual corruption sites */
3016         struct kmem_cache kmv_cache;    /* the cache we're operating on */
3017 } kmem_verify_t;
3018 
3019 /*
3020  * verify_pattern()
3021  *      verify that buf is filled with the pattern pat.
3022  */
3023 static int64_t
3024 verify_pattern(uint64_t *buf_arg, size_t size, uint64_t pat)
3025 {
3026         /*LINTED*/
3027         uint64_t *bufend = (uint64_t *)((char *)buf_arg + size);
3028         uint64_t *buf;
3029 
3030         for (buf = buf_arg; buf < bufend; buf++)
3031                 if (*buf != pat)
3032                         return ((uintptr_t)buf - (uintptr_t)buf_arg);
3033         return (-1);
3034 }
3035 


3040 static int
3041 verify_buftag(kmem_buftag_t *btp, uintptr_t pat)
3042 {
3043         return (btp->bt_bxstat == ((intptr_t)btp->bt_bufctl ^ pat) ? 0 : -1);
3044 }
3045 
3046 /*
3047  * verify_free()
3048  *      verify the integrity of a free block of memory by checking
3049  *      that it is filled with 0xdeadbeef and that its buftag is sane.
3050  */
3051 /*ARGSUSED1*/
3052 static int
3053 verify_free(uintptr_t addr, const void *data, void *private)
3054 {
3055         kmem_verify_t *kmv = (kmem_verify_t *)private;
3056         uint64_t *buf = kmv->kmv_buf;        /* buf to validate */
3057         int64_t corrupt;                /* corruption offset */
3058         kmem_buftag_t *buftagp;         /* ptr to buftag */
3059         kmem_cache_t *cp = &kmv->kmv_cache;
3060         int besilent = kmv->kmv_besilent;
3061 
3062         /*LINTED*/
3063         buftagp = KMEM_BUFTAG(cp, buf);
3064 
3065         /*
3066          * Read the buffer to check.
3067          */
3068         if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
3069                 if (!besilent)
3070                         mdb_warn("couldn't read %p", addr);
3071                 return (WALK_NEXT);
3072         }
3073 
3074         if ((corrupt = verify_pattern(buf, cp->cache_verify,
3075             KMEM_FREE_PATTERN)) >= 0) {
3076                 if (!besilent)
3077                         mdb_printf("buffer %p (free) seems corrupted, at %p\n",
3078                             addr, (uintptr_t)addr + corrupt);
3079                 goto corrupt;
3080         }


3086         if ((cp->cache_flags & (KMF_HASH | KMF_LITE)) == KMF_HASH &&
3087             buftagp->bt_redzone != KMEM_REDZONE_PATTERN) {
3088                 if (!besilent)
3089                         mdb_printf("buffer %p (free) seems to "
3090                             "have a corrupt redzone pattern\n", addr);
3091                 goto corrupt;
3092         }
3093 
3094         /*
3095          * confirm bufctl pointer integrity.
3096          */
3097         if (verify_buftag(buftagp, KMEM_BUFTAG_FREE) == -1) {
3098                 if (!besilent)
3099                         mdb_printf("buffer %p (free) has a corrupt "
3100                             "buftag\n", addr);
3101                 goto corrupt;
3102         }
3103 
3104         return (WALK_NEXT);
3105 corrupt:


3106         kmv->kmv_corruption++;
3107         return (WALK_NEXT);
3108 }
3109 
3110 /*
3111  * verify_alloc()
3112  *      Verify that the buftag of an allocated buffer makes sense with respect
3113  *      to the buffer.
3114  */
3115 /*ARGSUSED1*/
3116 static int
3117 verify_alloc(uintptr_t addr, const void *data, void *private)
3118 {
3119         kmem_verify_t *kmv = (kmem_verify_t *)private;
3120         kmem_cache_t *cp = &kmv->kmv_cache;
3121         uint64_t *buf = kmv->kmv_buf;        /* buf to validate */
3122         /*LINTED*/
3123         kmem_buftag_t *buftagp = KMEM_BUFTAG(cp, buf);
3124         uint32_t *ip = (uint32_t *)buftagp;
3125         uint8_t *bp = (uint8_t *)buf;
3126         int looks_ok = 0, size_ok = 1;  /* flags for finding corruption */
3127         int besilent = kmv->kmv_besilent;
3128 
3129         /*
3130          * Read the buffer to check.
3131          */
3132         if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
3133                 if (!besilent)
3134                         mdb_warn("couldn't read %p", addr);
3135                 return (WALK_NEXT);
3136         }
3137 
3138         /*
3139          * There are two cases to handle:
3140          * 1. If the buf was alloc'd using kmem_cache_alloc, it will have
3141          *    0xfeedfacefeedface at the end of it
3142          * 2. If the buf was alloc'd using kmem_alloc, it will have
3143          *    0xbb just past the end of the region in use.  At the buftag,
3144          *    it will have 0xfeedface (or, if the whole buffer is in use,
3145          *    0xfeedface & bb000000 or 0xfeedfacf & 000000bb depending on
3146          *    endianness), followed by 32 bits containing the offset of the
3147          *    0xbb byte in the buffer.


3165                             "redzone size encoding\n", addr);
3166                 goto corrupt;
3167         }
3168 
3169         if (!looks_ok) {
3170                 if (!besilent)
3171                         mdb_printf("buffer %p (allocated) has a corrupt "
3172                             "redzone signature\n", addr);
3173                 goto corrupt;
3174         }
3175 
3176         if (verify_buftag(buftagp, KMEM_BUFTAG_ALLOC) == -1) {
3177                 if (!besilent)
3178                         mdb_printf("buffer %p (allocated) has a "
3179                             "corrupt buftag\n", addr);
3180                 goto corrupt;
3181         }
3182 
3183         return (WALK_NEXT);
3184 corrupt:



3185         kmv->kmv_corruption++;
3186         return (WALK_NEXT);
3187 }
3188 
3189 /*ARGSUSED2*/
3190 int
3191 kmem_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3192 {
3193         if (flags & DCMD_ADDRSPEC) {
3194                 int check_alloc = 0, check_free = 0;
3195                 kmem_verify_t kmv;
3196 
3197                 if (mdb_vread(&kmv.kmv_cache, sizeof (kmv.kmv_cache),
3198                     addr) == -1) {
3199                         mdb_warn("couldn't read kmem_cache %p", addr);
3200                         return (DCMD_ERR);
3201                 }
3202 







3203                 kmv.kmv_size = kmv.kmv_cache.cache_buftag +
3204                     sizeof (kmem_buftag_t);
3205                 kmv.kmv_buf = mdb_alloc(kmv.kmv_size, UM_SLEEP | UM_GC);
3206                 kmv.kmv_corruption = 0;

3207 
3208                 if ((kmv.kmv_cache.cache_flags & KMF_REDZONE)) {
3209                         check_alloc = 1;
3210                         if (kmv.kmv_cache.cache_flags & KMF_DEADBEEF)
3211                                 check_free = 1;
3212                 } else {
3213                         if (!(flags & DCMD_LOOP)) {
3214                                 mdb_warn("cache %p (%s) does not have "
3215                                     "redzone checking enabled\n", addr,
3216                                     kmv.kmv_cache.cache_name);
3217                         }
3218                         return (DCMD_ERR);
3219                 }
3220 
3221                 if (flags & DCMD_LOOP) {
3222                         /*
3223                          * table mode, don't print out every corrupt buffer
3224                          */
3225                         kmv.kmv_besilent = 1;
3226                 } else {
3227                         mdb_printf("Summary for cache '%s'\n",
3228                             kmv.kmv_cache.cache_name);
3229                         mdb_inc_indent(2);
3230                         kmv.kmv_besilent = 0;
3231                 }
3232 
3233                 if (check_alloc)
3234                         (void) mdb_pwalk("kmem", verify_alloc, &kmv, addr);
3235                 if (check_free)
3236                         (void) mdb_pwalk("freemem", verify_free, &kmv, addr);
3237 

3238                 if (flags & DCMD_LOOP) {
3239                         if (kmv.kmv_corruption == 0) {
3240                                 mdb_printf("%-*s %?p clean\n",
3241                                     KMEM_CACHE_NAMELEN,
3242                                     kmv.kmv_cache.cache_name, addr);
3243                         } else {
3244                                 char *s = "";   /* optional s in "buffer[s]" */
3245                                 if (kmv.kmv_corruption > 1)
3246                                         s = "s";
3247 
3248                                 mdb_printf("%-*s %?p %d corrupt buffer%s\n",
3249                                     KMEM_CACHE_NAMELEN,
3250                                     kmv.kmv_cache.cache_name, addr,
3251                                     kmv.kmv_corruption, s);

3252                         }
3253                 } else {
3254                         /*
3255                          * This is the more verbose mode, when the user has
3256                          * type addr::kmem_verify.  If the cache was clean,
3257                          * nothing will have yet been printed. So say something.

3258                          */
3259                         if (kmv.kmv_corruption == 0)
3260                                 mdb_printf("clean\n");
3261 
3262                         mdb_dec_indent(2);
3263                 }

3264         } else {
3265                 /*
3266                  * If the user didn't specify a cache to verify, we'll walk all
3267                  * kmem_cache's, specifying ourself as a callback for each...
3268                  * this is the equivalent of '::walk kmem_cache .::kmem_verify'
3269                  */
3270                 mdb_printf("%<u>%-*s %-?s %-20s%</b>\n", KMEM_CACHE_NAMELEN,
3271                     "Cache Name", "Addr", "Cache Integrity");















3272                 (void) (mdb_walk_dcmd("kmem_cache", "kmem_verify", 0, NULL));
3273         }
3274 
3275         return (DCMD_OK);
3276 }
3277 
3278 typedef struct vmem_node {
3279         struct vmem_node *vn_next;
3280         struct vmem_node *vn_parent;
3281         struct vmem_node *vn_sibling;
3282         struct vmem_node *vn_children;
3283         uintptr_t vn_addr;
3284         int vn_marked;
3285         vmem_t vn_vmem;
3286 } vmem_node_t;
3287 
3288 typedef struct vmem_walk {
3289         vmem_node_t *vw_root;
3290         vmem_node_t *vw_current;
3291 } vmem_walk_t;




   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 
  26 /*
  27  * Copyright 2018 Joyent, Inc.  All rights reserved.
  28  * Copyright (c) 2012 by Delphix. All rights reserved.
  29  */
  30 
  31 #include <mdb/mdb_param.h>
  32 #include <mdb/mdb_modapi.h>
  33 #include <mdb/mdb_ctf.h>
  34 #include <mdb/mdb_whatis.h>
  35 #include <sys/cpuvar.h>
  36 #include <sys/kmem_impl.h>
  37 #include <sys/vmem_impl.h>
  38 #include <sys/machelf.h>
  39 #include <sys/modctl.h>
  40 #include <sys/kobj.h>
  41 #include <sys/panic.h>
  42 #include <sys/stack.h>
  43 #include <sys/sysmacros.h>
  44 #include <vm/page.h>
  45 
  46 #include "avl.h"
  47 #include "combined.h"


2995                         if (mdb_lookup_by_addr(bc.bc_stack[i],
2996                             MDB_SYM_FUZZY, c, sizeof (c), &sym) == -1)
2997                                 continue;
2998                         if (strncmp(c, "kmem_", 5) == 0)
2999                                 continue;
3000                         mdb_printf(" %a\n", bc.bc_stack[i]);
3001                         break;
3002                 }
3003 
3004                 if (i >= depth)
3005                         mdb_printf("\n");
3006         }
3007 
3008         return (DCMD_OK);
3009 }
3010 
3011 typedef struct kmem_verify {
3012         uint64_t *kmv_buf;              /* buffer to read cache contents into */
3013         size_t kmv_size;                /* number of bytes in kmv_buf */
3014         int kmv_corruption;             /* > 0 if corruption found. */
3015         uint_t kmv_flags;               /* dcmd flags */
3016         struct kmem_cache kmv_cache;    /* the cache we're operating on */
3017 } kmem_verify_t;
3018 
3019 /*
3020  * verify_pattern()
3021  *      verify that buf is filled with the pattern pat.
3022  */
3023 static int64_t
3024 verify_pattern(uint64_t *buf_arg, size_t size, uint64_t pat)
3025 {
3026         /*LINTED*/
3027         uint64_t *bufend = (uint64_t *)((char *)buf_arg + size);
3028         uint64_t *buf;
3029 
3030         for (buf = buf_arg; buf < bufend; buf++)
3031                 if (*buf != pat)
3032                         return ((uintptr_t)buf - (uintptr_t)buf_arg);
3033         return (-1);
3034 }
3035 


3040 static int
3041 verify_buftag(kmem_buftag_t *btp, uintptr_t pat)
3042 {
3043         return (btp->bt_bxstat == ((intptr_t)btp->bt_bufctl ^ pat) ? 0 : -1);
3044 }
3045 
3046 /*
3047  * verify_free()
3048  *      verify the integrity of a free block of memory by checking
3049  *      that it is filled with 0xdeadbeef and that its buftag is sane.
3050  */
3051 /*ARGSUSED1*/
3052 static int
3053 verify_free(uintptr_t addr, const void *data, void *private)
3054 {
3055         kmem_verify_t *kmv = (kmem_verify_t *)private;
3056         uint64_t *buf = kmv->kmv_buf;        /* buf to validate */
3057         int64_t corrupt;                /* corruption offset */
3058         kmem_buftag_t *buftagp;         /* ptr to buftag */
3059         kmem_cache_t *cp = &kmv->kmv_cache;
3060         boolean_t besilent = !!(kmv->kmv_flags & (DCMD_LOOP | DCMD_PIPE_OUT));
3061 
3062         /*LINTED*/
3063         buftagp = KMEM_BUFTAG(cp, buf);
3064 
3065         /*
3066          * Read the buffer to check.
3067          */
3068         if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
3069                 if (!besilent)
3070                         mdb_warn("couldn't read %p", addr);
3071                 return (WALK_NEXT);
3072         }
3073 
3074         if ((corrupt = verify_pattern(buf, cp->cache_verify,
3075             KMEM_FREE_PATTERN)) >= 0) {
3076                 if (!besilent)
3077                         mdb_printf("buffer %p (free) seems corrupted, at %p\n",
3078                             addr, (uintptr_t)addr + corrupt);
3079                 goto corrupt;
3080         }


3086         if ((cp->cache_flags & (KMF_HASH | KMF_LITE)) == KMF_HASH &&
3087             buftagp->bt_redzone != KMEM_REDZONE_PATTERN) {
3088                 if (!besilent)
3089                         mdb_printf("buffer %p (free) seems to "
3090                             "have a corrupt redzone pattern\n", addr);
3091                 goto corrupt;
3092         }
3093 
3094         /*
3095          * confirm bufctl pointer integrity.
3096          */
3097         if (verify_buftag(buftagp, KMEM_BUFTAG_FREE) == -1) {
3098                 if (!besilent)
3099                         mdb_printf("buffer %p (free) has a corrupt "
3100                             "buftag\n", addr);
3101                 goto corrupt;
3102         }
3103 
3104         return (WALK_NEXT);
3105 corrupt:
3106         if (kmv->kmv_flags & DCMD_PIPE_OUT)
3107                 mdb_printf("%p\n", addr);
3108         kmv->kmv_corruption++;
3109         return (WALK_NEXT);
3110 }
3111 
3112 /*
3113  * verify_alloc()
3114  *      Verify that the buftag of an allocated buffer makes sense with respect
3115  *      to the buffer.
3116  */
3117 /*ARGSUSED1*/
3118 static int
3119 verify_alloc(uintptr_t addr, const void *data, void *private)
3120 {
3121         kmem_verify_t *kmv = (kmem_verify_t *)private;
3122         kmem_cache_t *cp = &kmv->kmv_cache;
3123         uint64_t *buf = kmv->kmv_buf;        /* buf to validate */
3124         /*LINTED*/
3125         kmem_buftag_t *buftagp = KMEM_BUFTAG(cp, buf);
3126         uint32_t *ip = (uint32_t *)buftagp;
3127         uint8_t *bp = (uint8_t *)buf;
3128         int looks_ok = 0, size_ok = 1;  /* flags for finding corruption */
3129         boolean_t besilent = !!(kmv->kmv_flags & (DCMD_LOOP | DCMD_PIPE_OUT));
3130 
3131         /*
3132          * Read the buffer to check.
3133          */
3134         if (mdb_vread(buf, kmv->kmv_size, addr) == -1) {
3135                 if (!besilent)
3136                         mdb_warn("couldn't read %p", addr);
3137                 return (WALK_NEXT);
3138         }
3139 
3140         /*
3141          * There are two cases to handle:
3142          * 1. If the buf was alloc'd using kmem_cache_alloc, it will have
3143          *    0xfeedfacefeedface at the end of it
3144          * 2. If the buf was alloc'd using kmem_alloc, it will have
3145          *    0xbb just past the end of the region in use.  At the buftag,
3146          *    it will have 0xfeedface (or, if the whole buffer is in use,
3147          *    0xfeedface & bb000000 or 0xfeedfacf & 000000bb depending on
3148          *    endianness), followed by 32 bits containing the offset of the
3149          *    0xbb byte in the buffer.


3167                             "redzone size encoding\n", addr);
3168                 goto corrupt;
3169         }
3170 
3171         if (!looks_ok) {
3172                 if (!besilent)
3173                         mdb_printf("buffer %p (allocated) has a corrupt "
3174                             "redzone signature\n", addr);
3175                 goto corrupt;
3176         }
3177 
3178         if (verify_buftag(buftagp, KMEM_BUFTAG_ALLOC) == -1) {
3179                 if (!besilent)
3180                         mdb_printf("buffer %p (allocated) has a "
3181                             "corrupt buftag\n", addr);
3182                 goto corrupt;
3183         }
3184 
3185         return (WALK_NEXT);
3186 corrupt:
3187         if (kmv->kmv_flags & DCMD_PIPE_OUT)
3188                 mdb_printf("%p\n", addr);
3189 
3190         kmv->kmv_corruption++;
3191         return (WALK_NEXT);
3192 }
3193 
3194 /*ARGSUSED2*/
3195 int
3196 kmem_verify(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
3197 {
3198         if (flags & DCMD_ADDRSPEC) {
3199                 int check_alloc = 0, check_free = 0;
3200                 kmem_verify_t kmv;
3201 
3202                 if (mdb_vread(&kmv.kmv_cache, sizeof (kmv.kmv_cache),
3203                     addr) == -1) {
3204                         mdb_warn("couldn't read kmem_cache %p", addr);
3205                         return (DCMD_ERR);
3206                 }
3207 
3208                 if ((kmv.kmv_cache.cache_dump.kd_unsafe ||
3209                     kmv.kmv_cache.cache_dump.kd_alloc_fails) &&
3210                     !(flags & (DCMD_LOOP | DCMD_PIPE_OUT))) {
3211                         mdb_warn("WARNING: cache was used during dump: "
3212                             "corruption may be incorrectly reported\n");
3213                 }
3214 
3215                 kmv.kmv_size = kmv.kmv_cache.cache_buftag +
3216                     sizeof (kmem_buftag_t);
3217                 kmv.kmv_buf = mdb_alloc(kmv.kmv_size, UM_SLEEP | UM_GC);
3218                 kmv.kmv_corruption = 0;
3219                 kmv.kmv_flags = flags;
3220 
3221                 if ((kmv.kmv_cache.cache_flags & KMF_REDZONE)) {
3222                         check_alloc = 1;
3223                         if (kmv.kmv_cache.cache_flags & KMF_DEADBEEF)
3224                                 check_free = 1;
3225                 } else {
3226                         if (!(flags & DCMD_LOOP)) {
3227                                 mdb_warn("cache %p (%s) does not have "
3228                                     "redzone checking enabled\n", addr,
3229                                     kmv.kmv_cache.cache_name);
3230                         }
3231                         return (DCMD_ERR);
3232                 }
3233 
3234                 if (!(flags & (DCMD_LOOP | DCMD_PIPE_OUT))) {





3235                         mdb_printf("Summary for cache '%s'\n",
3236                             kmv.kmv_cache.cache_name);
3237                         mdb_inc_indent(2);

3238                 }
3239 
3240                 if (check_alloc)
3241                         (void) mdb_pwalk("kmem", verify_alloc, &kmv, addr);
3242                 if (check_free)
3243                         (void) mdb_pwalk("freemem", verify_free, &kmv, addr);
3244 
3245                 if (!(flags & DCMD_PIPE_OUT)) {
3246                         if (flags & DCMD_LOOP) {
3247                                 if (kmv.kmv_corruption == 0) {
3248                                         mdb_printf("%-*s %?p clean\n",
3249                                             KMEM_CACHE_NAMELEN,
3250                                             kmv.kmv_cache.cache_name, addr);
3251                                 } else {
3252                                         mdb_printf("%-*s %?p %d corrupt "
3253                                             "buffer%s\n", KMEM_CACHE_NAMELEN,




3254                                             kmv.kmv_cache.cache_name, addr,
3255                                             kmv.kmv_corruption,
3256                                             kmv.kmv_corruption > 1 ? "s" : "");
3257                                 }
3258                         } else {
3259                                 /*
3260                                  * This is the more verbose mode, when the user
3261                                  * typed addr::kmem_verify.  If the cache was
3262                                  * clean, nothing will have yet been printed. So
3263                                  * say something.
3264                                  */
3265                                 if (kmv.kmv_corruption == 0)
3266                                         mdb_printf("clean\n");
3267 
3268                                 mdb_dec_indent(2);
3269                         }
3270                 }
3271         } else {
3272                 /*
3273                  * If the user didn't specify a cache to verify, we'll walk all
3274                  * kmem_cache's, specifying ourself as a callback for each...
3275                  * this is the equivalent of '::walk kmem_cache .::kmem_verify'
3276                  */
3277 
3278                 if (!(flags & DCMD_PIPE_OUT)) {
3279                         uintptr_t dump_curr;
3280                         uintptr_t dump_end;
3281 
3282                         if (mdb_readvar(&dump_curr, "kmem_dump_curr") != -1 &&
3283                             mdb_readvar(&dump_end, "kmem_dump_end") != -1 &&
3284                             dump_curr == dump_end) {
3285                                 mdb_warn("WARNING: exceeded kmem_dump_size; "
3286                                     "corruption may be incorrectly reported\n");
3287                         }
3288 
3289                         mdb_printf("%<u>%-*s %-?s %-20s%</b>\n",
3290                             KMEM_CACHE_NAMELEN, "Cache Name", "Addr",
3291                             "Cache Integrity");
3292                 }
3293 
3294                 (void) (mdb_walk_dcmd("kmem_cache", "kmem_verify", 0, NULL));
3295         }
3296 
3297         return (DCMD_OK);
3298 }
3299 
3300 typedef struct vmem_node {
3301         struct vmem_node *vn_next;
3302         struct vmem_node *vn_parent;
3303         struct vmem_node *vn_sibling;
3304         struct vmem_node *vn_children;
3305         uintptr_t vn_addr;
3306         int vn_marked;
3307         vmem_t vn_vmem;
3308 } vmem_node_t;
3309 
3310 typedef struct vmem_walk {
3311         vmem_node_t *vw_root;
3312         vmem_node_t *vw_current;
3313 } vmem_walk_t;