tools/llvm: Do not build with symbols
[minix3.git] / minix / lib / libc / minix-malloc-debug.c
blob25c9fded41ff7b390a78463c169b07d4159f53b7
1 /* pointless without assertions */
2 #ifdef NDEBUG
3 #undef NDEBUG
4 #endif
6 #include <assert.h>
7 #include <machine/vm.h>
8 #include <machine/vmparam.h>
9 #include <minix/minlib.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/mman.h>
13 #include <unistd.h>
15 #include "malloc-debug.h"
17 #if 0
18 #include <stdio.h>
19 static int reenter;
20 #define LOG(args) if (!reenter) { reenter++; printf args; reenter--; }
21 #else
22 #define LOG(args)
23 #endif
25 struct block {
26 size_t size;
27 unsigned magic;
30 static u8_t *ptr_min, *ptr_max;
32 static unsigned long page_round_down(unsigned long x)
34 return x - x % PAGE_SIZE;
37 static unsigned long page_round_up(unsigned long x)
39 unsigned long rem;
41 rem = x % PAGE_SIZE;
42 if (rem)
43 x += PAGE_SIZE - rem;
45 return x;
48 #define page_round_down_ptr(x) ((u8_t *) page_round_down((unsigned long) (x)))
49 #define page_round_up_ptr(x) ((u8_t *) page_round_up((unsigned long) (x)))
51 static unsigned long block_compute_magic(struct block *block)
53 return (unsigned long) block + block->size + 0xDEADBEEFUL;
56 static size_t block_get_totalsize(size_t size)
58 return page_round_up(sizeof(struct block) + size);
61 static u8_t *block_get_endptr(struct block *block)
63 return (u8_t *) block + block_get_totalsize(block->size);
66 static u8_t *block_get_dataptr(struct block *block)
68 return block_get_endptr(block) - block->size;
71 static void block_check(struct block *block)
73 u8_t *dataptr, *p;
75 /* check location */
76 assert(block);
77 assert(!((unsigned long) block % PAGE_SIZE));
78 assert((u8_t *) block >= ptr_min);
79 assert((u8_t *) block <= ptr_max);
81 /* check size */
82 assert(block->size > 0);
84 /* check fillers */
85 assert(block->magic == block_compute_magic(block));
86 dataptr = block_get_dataptr(block);
87 for (p = (u8_t *) (block + 1); p < dataptr; p++)
88 assert(*p == ((unsigned long) p & 0xff));
91 static struct block *block_alloc(size_t size)
93 struct block *block;
94 u8_t *dataptr, *p, *ptr;
95 unsigned page_index, page_index_max;
96 size_t sizerem, totalsize;
97 u64_t tsc;
99 LOG(("block_alloc; size=0x%x\n", size));
100 assert(size > 0);
102 /* round size up to machine word size */
103 sizerem = size % sizeof(long);
104 if (sizerem)
105 size += sizeof(long) - sizerem;
107 /* initialize address range */
108 if (!ptr_min && !ptr_max) {
109 /* keep a safe distance from areas that are in use:
110 * - 4MB from the break (should not change if traditional
111 * malloc is not used so a small margin is sufficient
112 * - 256MB from the stack (big margin because memory beyond
113 * this may be allocated by mmap when the address space
114 * starts to fill up)
116 ptr_min = page_round_up_ptr((u8_t *) sbrk(0) + 0x400000);
117 ptr_max = page_round_down_ptr((u8_t *) &size - 0x10000000);
119 assert(ptr_min);
120 assert(ptr_max);
121 assert(ptr_min < ptr_max);
123 /* select address at random */
124 tsc = 0;
125 /* LSC FIXME Broken for now... */
126 /* read_tsc_64(&tsc); */
127 totalsize = block_get_totalsize(size);
128 page_index_max = (ptr_max - ptr_min - totalsize) / PAGE_SIZE;
129 page_index = (page_index_max > 0) ? (ex64lo(tsc) % page_index_max) : 0;
130 ptr = ptr_min + page_index * PAGE_SIZE;
132 /* allocate block */
133 block = (struct block *) mmap(
134 ptr, /* addr */
135 totalsize, /* len */
136 PROT_READ|PROT_WRITE, /* prot */
137 MAP_PREALLOC, /* flags */
138 -1, /* fd */
139 0); /* offset */
140 if (block == MAP_FAILED) {
141 /* mmap call failed */
142 abort();
145 /* block may not be at the requested location if that is in use */
146 if (ptr_min > (u8_t *) block)
147 ptr_min = (u8_t *) block;
149 if (ptr_max < (u8_t *) block)
150 ptr_max = (u8_t *) block;
152 /* initialize block, including fillers */
153 block->size = size;
154 block->magic = block_compute_magic(block);
155 dataptr = block_get_dataptr(block);
156 for (p = (u8_t *) (block + 1); p < dataptr; p++)
157 *p = ((unsigned long) p & 0xff);
159 LOG(("block_alloc; block=0x%x\n", block));
160 return block;
163 static struct block *block_find(const void *ptr)
165 struct block *block;
167 LOG(("block_find; ptr=0x%x\n", ptr));
168 assert(ptr);
170 /* locate block based on pointer, then check whether it is valid */
171 block = (struct block *) page_round_down(
172 (unsigned long) ((struct block *) __UNCONST(ptr) - 1));
173 block_check(block);
174 LOG(("block_find; block=0x%x\n", block));
175 return block;
178 static void block_free(struct block *block)
180 LOG(("block_free; block=0x%x\n", block));
181 assert(block);
183 /* simply unmap the block */
184 if (munmap(block, block_get_totalsize(block->size)) < 0) {
185 /* munmap call failed */
186 abort();
190 void *_dbg_malloc(size_t size)
192 struct block *newblock;
193 u8_t *ptr;
195 LOG(("_dbg_malloc; size=0x%x\n", size));
196 assert(size > 0); /* enforced by regular malloc */
198 newblock = block_alloc(size);
199 if (!newblock)
200 return NULL;
202 ptr = block_get_dataptr(newblock);
203 LOG(("_dbg_malloc; ptr=0x%x\n", ptr));
204 return ptr;
207 void *_dbg_realloc(void *oldp, size_t size)
209 u8_t *newp;
210 struct block *oldblock, *newblock;
212 LOG(("_dbg_realloc; oldp=0x%x; size=0x%x\n", oldp, size));
213 assert(oldp); /* enforced by regular realloc */
214 assert(size > 0); /* enforced by regular realloc */
216 /* always allocate new block */
217 newblock = block_alloc(size);
218 if (!newblock)
219 return NULL;
221 /* copy the data */
222 oldblock = block_find(oldp);
223 memcpy(block_get_dataptr(newblock),
224 block_get_dataptr(oldblock),
225 MIN(newblock->size, oldblock->size));
227 /* deallocate old block */
228 block_free(oldblock);
230 newp = block_get_dataptr(newblock);
231 LOG(("_dbg_realloc; newp=0x%x\n", newp));
232 return newp;
235 void _dbg_free(void *ptr)
237 LOG(("_dbg_free; ptr=0x%x\n", ptr));
238 assert(ptr); /* enforced by regular free */
240 /* find the block and free it */
241 block_free(block_find(ptr));
243 LOG(("_dbg_free done\n"));