1 /* pointless without assertions */
7 #include <machine/vm.h>
8 #include <machine/vmparam.h>
9 #include <minix/minlib.h>
15 #include "malloc-debug.h"
20 #define LOG(args) if (!reenter) { reenter++; printf args; reenter--; }
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
)
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
)
77 assert(!((unsigned long) block
% PAGE_SIZE
));
78 assert((u8_t
*) block
>= ptr_min
);
79 assert((u8_t
*) block
<= ptr_max
);
82 assert(block
->size
> 0);
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
)
94 u8_t
*dataptr
, *p
, *ptr
;
95 unsigned page_index
, page_index_max
;
96 size_t sizerem
, totalsize
;
99 LOG(("block_alloc; size=0x%x\n", size
));
102 /* round size up to machine word size */
103 sizerem
= size
% sizeof(long);
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
116 ptr_min
= page_round_up_ptr((u8_t
*) sbrk(0) + 0x400000);
117 ptr_max
= page_round_down_ptr((u8_t
*) &size
- 0x10000000);
121 assert(ptr_min
< ptr_max
);
123 /* select address at random */
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
;
133 block
= (struct block
*) mmap(
136 PROT_READ
|PROT_WRITE
, /* prot */
137 MAP_PREALLOC
, /* flags */
140 if (block
== MAP_FAILED
) {
141 /* mmap call failed */
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 */
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
));
163 static struct block
*block_find(const void *ptr
)
167 LOG(("block_find; ptr=0x%x\n", 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));
174 LOG(("block_find; block=0x%x\n", block
));
178 static void block_free(struct block
*block
)
180 LOG(("block_free; block=0x%x\n", block
));
183 /* simply unmap the block */
184 if (munmap(block
, block_get_totalsize(block
->size
)) < 0) {
185 /* munmap call failed */
190 void *_dbg_malloc(size_t size
)
192 struct block
*newblock
;
195 LOG(("_dbg_malloc; size=0x%x\n", size
));
196 assert(size
> 0); /* enforced by regular malloc */
198 newblock
= block_alloc(size
);
202 ptr
= block_get_dataptr(newblock
);
203 LOG(("_dbg_malloc; ptr=0x%x\n", ptr
));
207 void *_dbg_realloc(void *oldp
, size_t size
)
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
);
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
));
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"));