phunix/lib/libc/minix/malloc-debug.c
Ben Gras 2fe8fb192f Full switch to clang/ELF. Drop ack. Simplify.
There is important information about booting non-ack images in
docs/UPDATING. ack/aout-format images can't be built any more, and
booting clang/ELF-format ones is a little different. Updating to the
new boot monitor is recommended.

Changes in this commit:

	. drop boot monitor -> allowing dropping ack support
	. facility to copy ELF boot files to /boot so that old boot monitor
	  can still boot fairly easily, see UPDATING
	. no more ack-format libraries -> single-case libraries
	. some cleanup of OBJECT_FMT, COMPILER_TYPE, etc cases
	. drop several ack toolchain commands, but not all support
	  commands (e.g. aal is gone but acksize is not yet).
	. a few libc files moved to netbsd libc dir
	. new /bin/date as minix date used code in libc/
	. test compile fix
	. harmonize includes
	. /usr/lib is no longer special: without ack, /usr/lib plays no
	  kind of special bootstrapping role any more and bootstrapping
	  is done exclusively through packages, so releases depend even
	  less on the state of the machine making them now.
	. rename nbsd_lib* to lib*
	. reduce mtree
2012-02-14 14:52:02 +01:00

254 lines
5.6 KiB
C

/* pointless without assertions */
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <assert.h>
#include <machine/vm.h>
#include <minix/minlib.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
#define mmap minix_mmap
#define munmap minix_munmap
#include "malloc-debug.h"
#if 0
#include <stdio.h>
static int reenter;
#define LOG(args) if (!reenter) { reenter++; printf args; reenter--; }
#else
#define LOG(args)
#endif
#define PAGE_SIZE I386_PAGE_SIZE
struct block {
size_t size;
unsigned magic;
};
static u8_t *ptr_min, *ptr_max;
#define MIN(x, y) ((x) < (y) ? (x) : (y))
static unsigned long page_round_down(unsigned long x)
{
return x - x % PAGE_SIZE;
}
static unsigned long page_round_up(unsigned long x)
{
unsigned long rem;
rem = x % PAGE_SIZE;
if (rem)
x += PAGE_SIZE - rem;
return x;
}
#define page_round_down_ptr(x) ((u8_t *) page_round_down((unsigned long) (x)))
#define page_round_up_ptr(x) ((u8_t *) page_round_up((unsigned long) (x)))
static unsigned long block_compute_magic(struct block *block)
{
return (unsigned long) block + block->size + 0xDEADBEEFUL;
}
static size_t block_get_totalsize(size_t size)
{
return page_round_up(sizeof(struct block) + size);
}
static u8_t *block_get_endptr(struct block *block)
{
return (u8_t *) block + block_get_totalsize(block->size);
}
static u8_t *block_get_dataptr(struct block *block)
{
return block_get_endptr(block) - block->size;
}
static void block_check(struct block *block)
{
u8_t *dataptr, *p;
/* check location */
assert(block);
assert(!((unsigned long) block % PAGE_SIZE));
assert((u8_t *) block >= ptr_min);
assert((u8_t *) block <= ptr_max);
/* check size */
assert(block->size > 0);
/* check fillers */
assert(block->magic == block_compute_magic(block));
dataptr = block_get_dataptr(block);
for (p = (u8_t *) (block + 1); p < dataptr; p++)
assert(*p == ((unsigned long) p & 0xff));
}
static struct block *block_alloc(size_t size)
{
struct block *block;
u8_t *dataptr, *p, *ptr;
unsigned page_index, page_index_max;
size_t sizerem, totalsize;
u64_t tsc;
LOG(("block_alloc; size=0x%x\n", size));
assert(size > 0);
/* round size up to machine word size */
sizerem = size % sizeof(long);
if (sizerem)
size += sizeof(long) - sizerem;
/* initialize address range */
if (!ptr_min && !ptr_max) {
/* keep a safe distance from areas that are in use:
* - 4MB from the break (should not change if traditional
* malloc is not used so a small margin is sufficient
* - 256MB from the stack (big margin because memory beyond
* this may be allocated by mmap when the address space
* starts to fill up)
*/
ptr_min = page_round_up_ptr((u8_t *) sbrk(0) + 0x400000);
ptr_max = page_round_down_ptr((u8_t *) &size - 0x10000000);
}
assert(ptr_min);
assert(ptr_max);
assert(ptr_min < ptr_max);
/* select address at random */
#ifdef __NBSD_LIBC
tsc = 0;
#else
read_tsc_64(&tsc);
#endif
totalsize = block_get_totalsize(size);
page_index_max = (ptr_max - ptr_min - totalsize) / PAGE_SIZE;
page_index = (page_index_max > 0) ? (ex64lo(tsc) % page_index_max) : 0;
ptr = ptr_min + page_index * PAGE_SIZE;
/* allocate block */
block = (struct block *) mmap(
ptr, /* addr */
totalsize, /* len */
PROT_READ|PROT_WRITE, /* prot */
MAP_PREALLOC, /* flags */
-1, /* fd */
0); /* offset */
if (block == MAP_FAILED) {
/* mmap call failed */
abort();
}
/* block may not be at the requested location if that is in use */
if (ptr_min > (u8_t *) block)
ptr_min = (u8_t *) block;
if (ptr_max < (u8_t *) block)
ptr_max = (u8_t *) block;
/* initialize block, including fillers */
block->size = size;
block->magic = block_compute_magic(block);
dataptr = block_get_dataptr(block);
for (p = (u8_t *) (block + 1); p < dataptr; p++)
*p = ((unsigned long) p & 0xff);
LOG(("block_alloc; block=0x%x\n", block));
return block;
}
static struct block *block_find(const void *ptr)
{
struct block *block;
LOG(("block_find; ptr=0x%x\n", ptr));
assert(ptr);
/* locate block based on pointer, then check whether it is valid */
block = (struct block *) page_round_down(
(unsigned long) ((struct block *) __UNCONST(ptr) - 1));
block_check(block);
LOG(("block_find; block=0x%x\n", block));
return block;
}
static void block_free(struct block *block)
{
LOG(("block_free; block=0x%x\n", block));
assert(block);
/* simply unmap the block */
if (munmap(block, block_get_totalsize(block->size)) < 0) {
/* munmap call failed */
abort();
}
}
void *_dbg_malloc(size_t size)
{
struct block *newblock;
u8_t *ptr;
LOG(("_dbg_malloc; size=0x%x\n", size));
assert(size > 0); /* enforced by regular malloc */
newblock = block_alloc(size);
if (!newblock)
return NULL;
ptr = block_get_dataptr(newblock);
LOG(("_dbg_malloc; ptr=0x%x\n", ptr));
return ptr;
}
void *_dbg_realloc(void *oldp, size_t size)
{
u8_t *newp;
struct block *oldblock, *newblock;
LOG(("_dbg_realloc; oldp=0x%x; size=0x%x\n", oldp, size));
assert(oldp); /* enforced by regular realloc */
assert(size > 0); /* enforced by regular realloc */
/* always allocate new block */
newblock = block_alloc(size);
if (!newblock)
return NULL;
/* copy the data */
oldblock = block_find(oldp);
memcpy(block_get_dataptr(newblock),
block_get_dataptr(oldblock),
MIN(newblock->size, oldblock->size));
/* deallocate old block */
block_free(oldblock);
newp = block_get_dataptr(newblock);
LOG(("_dbg_realloc; newp=0x%x\n", newp));
return newp;
}
void _dbg_free(void *ptr)
{
LOG(("_dbg_free; ptr=0x%x\n", ptr));
assert(ptr); /* enforced by regular free */
/* find the block and free it */
block_free(block_find(ptr));
LOG(("_dbg_free done\n"));
}