uma_dbg.c revision 103531
195771Sjeff/* 295771Sjeff * Copyright (c) 2002, Jeffrey Roberson <jroberson@chesapeake.net> 395771Sjeff * All rights reserved. 495771Sjeff * 595771Sjeff * Redistribution and use in source and binary forms, with or without 695771Sjeff * modification, are permitted provided that the following conditions 795771Sjeff * are met: 895771Sjeff * 1. Redistributions of source code must retain the above copyright 995771Sjeff * notice unmodified, this list of conditions, and the following 1095771Sjeff * disclaimer. 1195771Sjeff * 2. Redistributions in binary form must reproduce the above copyright 1295771Sjeff * notice, this list of conditions and the following disclaimer in the 1395771Sjeff * documentation and/or other materials provided with the distribution. 1495771Sjeff * 1595771Sjeff * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1695771Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1795771Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1895771Sjeff * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1995771Sjeff * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2095771Sjeff * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2195771Sjeff * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2295771Sjeff * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2395771Sjeff * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2495771Sjeff * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2595771Sjeff * 2695771Sjeff * $FreeBSD: head/sys/vm/uma_dbg.c 103531 2002-09-18 08:26:30Z jeff $ 2795771Sjeff * 2895771Sjeff */ 2995771Sjeff 3095771Sjeff/* 3195771Sjeff * uma_dbg.c Debugging features for UMA users 3295771Sjeff * 3395771Sjeff */ 3495771Sjeff 3595771Sjeff 3695771Sjeff#include <sys/param.h> 3795771Sjeff#include <sys/systm.h> 3895771Sjeff#include <sys/kernel.h> 3995771Sjeff#include <sys/types.h> 4095771Sjeff#include <sys/queue.h> 4195771Sjeff#include <sys/lock.h> 4295771Sjeff#include <sys/mutex.h> 4395931Sjeff#include <sys/malloc.h> 4495771Sjeff 45103531Sjeff#include <vm/vm.h> 46103531Sjeff#include <vm/vm_object.h> 47103531Sjeff#include <vm/vm_page.h> 4895771Sjeff#include <vm/uma.h> 4995771Sjeff#include <vm/uma_int.h> 5095771Sjeff#include <vm/uma_dbg.h> 5195771Sjeff 5295771Sjeffstatic const u_int32_t uma_junk = 0xdeadc0de; 5395771Sjeff 5495771Sjeff/* 5595771Sjeff * Checks an item to make sure it hasn't been overwritten since freed. 5695771Sjeff * 5795771Sjeff * Complies with standard ctor arg/return 5895771Sjeff * 5995771Sjeff */ 6095771Sjeffvoid 6195771Sjefftrash_ctor(void *mem, int size, void *arg) 6295771Sjeff{ 6395771Sjeff int cnt; 6495771Sjeff u_int32_t *p; 6595771Sjeff 6695771Sjeff cnt = size / sizeof(uma_junk); 6795771Sjeff 6895771Sjeff for (p = mem; cnt > 0; cnt--, p++) 6995771Sjeff if (*p != uma_junk) 7095771Sjeff panic("Memory modified after free %p(%d)\n", 7195771Sjeff mem, size); 7295771Sjeff} 7395771Sjeff 7495771Sjeff/* 7595771Sjeff * Fills an item with predictable garbage 7695771Sjeff * 7795771Sjeff * Complies with standard dtor arg/return 7895771Sjeff * 7995771Sjeff */ 8095771Sjeffvoid 8195771Sjefftrash_dtor(void *mem, int size, void *arg) 8295771Sjeff{ 8395771Sjeff int cnt; 8495771Sjeff u_int32_t *p; 8595771Sjeff 8695771Sjeff cnt = size / sizeof(uma_junk); 8795771Sjeff 8895771Sjeff for (p = mem; cnt > 0; cnt--, p++) 8995771Sjeff *p = uma_junk; 9095771Sjeff} 9195771Sjeff 9295771Sjeff/* 9395771Sjeff * Fills an item with predictable garbage 9495771Sjeff * 9595771Sjeff * Complies with standard init arg/return 9695771Sjeff * 9795771Sjeff */ 9895771Sjeffvoid 9995771Sjefftrash_init(void *mem, int size) 10095771Sjeff{ 10195771Sjeff trash_dtor(mem, size, NULL); 10295771Sjeff} 10395771Sjeff 10495771Sjeff/* 10595771Sjeff * Checks an item to make sure it hasn't been overwritten since it was freed. 10695771Sjeff * 10795771Sjeff * Complies with standard fini arg/return 10895771Sjeff * 10995771Sjeff */ 11095771Sjeffvoid 11195771Sjefftrash_fini(void *mem, int size) 11295771Sjeff{ 11395771Sjeff trash_ctor(mem, size, NULL); 11495771Sjeff} 11595899Sjeff 11695931Sjeff/* 11795931Sjeff * Checks an item to make sure it hasn't been overwritten since freed. 11895931Sjeff * 11995931Sjeff * Complies with standard ctor arg/return 12095931Sjeff * 12195931Sjeff */ 12295931Sjeffvoid 12395931Sjeffmtrash_ctor(void *mem, int size, void *arg) 12495931Sjeff{ 12595931Sjeff struct malloc_type **ksp; 12695931Sjeff u_int32_t *p = mem; 12795931Sjeff int cnt; 12895931Sjeff 12995931Sjeff size -= sizeof(struct malloc_type *); 13095931Sjeff ksp = (struct malloc_type **)mem; 13195931Sjeff ksp += size / sizeof(struct malloc_type *); 13295931Sjeff cnt = size / sizeof(uma_junk); 13395931Sjeff 13495931Sjeff for (p = mem; cnt > 0; cnt--, p++) 13595931Sjeff if (*p != uma_junk) { 13695931Sjeff printf("Memory modified after free %p(%d)\n", 13795931Sjeff mem, size); 13895931Sjeff panic("Most recently used by %s\n", (*ksp == NULL)? 13995931Sjeff "none" : (*ksp)->ks_shortdesc); 14095931Sjeff } 14195931Sjeff} 14295931Sjeff 14395931Sjeff/* 14495931Sjeff * Fills an item with predictable garbage 14595931Sjeff * 14695931Sjeff * Complies with standard dtor arg/return 14795931Sjeff * 14895931Sjeff */ 14995931Sjeffvoid 15095931Sjeffmtrash_dtor(void *mem, int size, void *arg) 15195931Sjeff{ 15295931Sjeff int cnt; 15395931Sjeff u_int32_t *p; 15495931Sjeff 15595931Sjeff size -= sizeof(struct malloc_type *); 15695931Sjeff cnt = size / sizeof(uma_junk); 15795931Sjeff 15895931Sjeff for (p = mem; cnt > 0; cnt--, p++) 15995931Sjeff *p = uma_junk; 16095931Sjeff} 16195931Sjeff 16295931Sjeff/* 16395931Sjeff * Fills an item with predictable garbage 16495931Sjeff * 16595931Sjeff * Complies with standard init arg/return 16695931Sjeff * 16795931Sjeff */ 16895931Sjeffvoid 16995931Sjeffmtrash_init(void *mem, int size) 17095931Sjeff{ 17195931Sjeff struct malloc_type **ksp; 17295931Sjeff 17395931Sjeff mtrash_dtor(mem, size, NULL); 17495931Sjeff 17595931Sjeff ksp = (struct malloc_type **)mem; 17695931Sjeff ksp += (size / sizeof(struct malloc_type *)) - 1; 17795931Sjeff *ksp = NULL; 17895931Sjeff} 17995931Sjeff 18095931Sjeff/* 18195931Sjeff * Checks an item to make sure it hasn't been overwritten since it was freed. 18295931Sjeff * 18395931Sjeff * Complies with standard fini arg/return 18495931Sjeff * 18595931Sjeff */ 18695931Sjeffvoid 18795931Sjeffmtrash_fini(void *mem, int size) 18895931Sjeff{ 18995931Sjeff mtrash_ctor(mem, size, NULL); 19095931Sjeff} 19195931Sjeff 19295899Sjeffstatic uma_slab_t 19395899Sjeffuma_dbg_getslab(uma_zone_t zone, void *item) 19495899Sjeff{ 19595899Sjeff uma_slab_t slab; 19695899Sjeff u_int8_t *mem; 19795899Sjeff 19895899Sjeff mem = (u_int8_t *)((unsigned long)item & (~UMA_SLAB_MASK)); 19995899Sjeff if (zone->uz_flags & UMA_ZFLAG_MALLOC) { 200103531Sjeff slab = vtoslab((vm_offset_t)mem); 201103531Sjeff } else if (zone->uz_flags & UMA_ZFLAG_HASH) { 20295899Sjeff ZONE_LOCK(zone); 20395899Sjeff slab = hash_sfind(&zone->uz_hash, mem); 20495899Sjeff ZONE_UNLOCK(zone); 20595899Sjeff } else { 20695899Sjeff mem += zone->uz_pgoff; 20795899Sjeff slab = (uma_slab_t)mem; 20895899Sjeff } 20995899Sjeff 21095899Sjeff return (slab); 21195899Sjeff} 21295899Sjeff 21395899Sjeff/* 21495899Sjeff * Set up the slab's freei data such that uma_dbg_free can function. 21595899Sjeff * 21695899Sjeff */ 21795899Sjeff 21895899Sjeffvoid 21995899Sjeffuma_dbg_alloc(uma_zone_t zone, uma_slab_t slab, void *item) 22095899Sjeff{ 22195899Sjeff int freei; 22295899Sjeff 22395899Sjeff if (slab == NULL) { 22495899Sjeff slab = uma_dbg_getslab(zone, item); 22595899Sjeff if (slab == NULL) 22695899Sjeff panic("uma: item %p did not belong to zone %s\n", 22795899Sjeff item, zone->uz_name); 22895899Sjeff } 22995899Sjeff 23095899Sjeff freei = ((unsigned long)item - (unsigned long)slab->us_data) 23195899Sjeff / zone->uz_rsize; 23295899Sjeff 23395899Sjeff slab->us_freelist[freei] = 255; 23495899Sjeff 23595899Sjeff return; 23695899Sjeff} 23795899Sjeff 23895899Sjeff/* 23995899Sjeff * Verifies freed addresses. Checks for alignment, valid slab membership 24095899Sjeff * and duplicate frees. 24195899Sjeff * 24295899Sjeff */ 24395899Sjeff 24495899Sjeffvoid 24595899Sjeffuma_dbg_free(uma_zone_t zone, uma_slab_t slab, void *item) 24695899Sjeff{ 24795899Sjeff int freei; 24895899Sjeff 24995899Sjeff if (slab == NULL) { 25095899Sjeff slab = uma_dbg_getslab(zone, item); 25195899Sjeff if (slab == NULL) 25295899Sjeff panic("uma: Freed item %p did not belong to zone %s\n", 25395899Sjeff item, zone->uz_name); 25495899Sjeff } 25595899Sjeff 25695899Sjeff freei = ((unsigned long)item - (unsigned long)slab->us_data) 25795899Sjeff / zone->uz_rsize; 25895899Sjeff 25995899Sjeff if (freei >= zone->uz_ipers) 26097453Speter panic("zone: %s(%p) slab %p freelist %d out of range 0-%d\n", 26195899Sjeff zone->uz_name, zone, slab, freei, zone->uz_ipers-1); 26295899Sjeff 26395899Sjeff if (((freei * zone->uz_rsize) + slab->us_data) != item) { 26495899Sjeff printf("zone: %s(%p) slab %p freed address %p unaligned.\n", 26595899Sjeff zone->uz_name, zone, slab, item); 26695899Sjeff panic("should be %p\n", 26795899Sjeff (freei * zone->uz_rsize) + slab->us_data); 26895899Sjeff } 26995899Sjeff 27095899Sjeff if (slab->us_freelist[freei] != 255) { 27195899Sjeff printf("Slab at %p, freei %d = %d.\n", 27295899Sjeff slab, freei, slab->us_freelist[freei]); 27395899Sjeff panic("Duplicate free of item %p from zone %p(%s)\n", 27495899Sjeff item, zone, zone->uz_name); 27595899Sjeff } 27695899Sjeff 27795899Sjeff /* 27895899Sjeff * When this is actually linked into the slab this will change. 27995899Sjeff * Until then the count of valid slabs will make sure we don't 28095899Sjeff * accidentally follow this and assume it's a valid index. 28195899Sjeff */ 28295899Sjeff slab->us_freelist[freei] = 0; 28395899Sjeff} 284