Remove building with NOCRYPTO option
[minix.git] / minix / lib / libmagicrt / magic_mem.c
blob795c8af1df80dcd65213fc8546153e6e30b91882
2 #ifdef _FILE_OFFSET_BITS
3 #undef _FILE_OFFSET_BITS
4 #endif
5 #define _FILE_OFFSET_BITS 64
7 #include <magic_mem.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <stdarg.h>
11 #include <magic_asr.h>
13 #ifdef __MINIX
14 #define util_time_tsc_read_ns(x) 0
15 #define util_strhash(x, y) 0
16 #define util_stacktrace_hash() 0
17 #define util_stacktrace_print_custom(x)
18 #define util_stacktrace_hash_skip(x) 0
19 #else
20 #include <common/util/stacktrace.h>
21 #include <common/util/time.h>
22 #include <common/util/string.h>
23 #endif
25 #define DEBUG MAGIC_DEBUG_SET(0)
26 #define DEBUG_TYPE_SIZE_MISMATCH MAGIC_DEBUG_SET(0)
28 #if DEBUG
29 #define MAGIC_MEM_PRINTF _magic_printf
30 #else
31 #define MAGIC_MEM_PRINTF magic_null_printf
32 #endif
34 /* CPU frequency (used for timestamp logging) */
35 PUBLIC double magic_cycles_per_ns = 0;
38 * External callbacks.
40 PUBLIC magic_mem_heap_alloc_cb_t magic_mem_heap_alloc_cb = NULL;
41 PUBLIC magic_mem_create_dsentry_cb_t magic_mem_create_dsentry_cb = NULL;
42 PUBLIC magic_mem_heap_free_cb_t magic_mem_heap_free_cb = NULL;
44 PUBLIC short magic_mem_create_dsentry_site_id = 0;
45 PUBLIC THREAD_LOCAL short magic_mem_wrapper_active = 0;
46 PUBLIC THREAD_LOCAL short magic_mempool_mgmt_active_level = 0;
47 PUBLIC THREAD_LOCAL short magic_mempool_ids[MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS];
49 const char* const MAGIC_MEMPOOL_NAME_UNKNOWN = "_magic_mempool_unknown#";
50 const char* const MAGIC_MEMPOOL_NAME_DETACHED = "_magic_mempool_detached#";
52 __attribute__((weak)) int magic_mempool_allow_reset = 1;
53 __attribute__((weak)) int magic_mempool_allow_reuse = 1;
54 __attribute__((weak)) int magic_mempool_allow_external_alloc = 0;
56 #define MAGIC_MEM_FAILED ((void*) -1)
58 #ifndef SHM_REMAP
59 #define SHM_REMAP 0
60 #endif
62 EXTERN char **environ;
64 PRIVATE magic_dsentry_cb_t magic_destroy_dsentry_ext_cb = NULL;
66 /* Magic real mem function definitions. */
67 PUBLIC void *(*magic_real_malloc)(size_t size) = &malloc;
68 PUBLIC void *(*magic_real_calloc)(size_t nmemb, size_t size) = &calloc;
69 PUBLIC void (*magic_real_free)(void *ptr) = &free;
70 PUBLIC void *(*magic_real_realloc)(void *ptr, size_t size) = &realloc;
72 PUBLIC int (*magic_real_posix_memalign)(void **memptr, size_t alignment, size_t size) = &posix_memalign;
74 #ifndef __MINIX
75 PUBLIC void *(*magic_real_valloc)(size_t size) = &valloc;
76 PUBLIC void *(*magic_real_memalign)(size_t boundary, size_t size) = &memalign;
77 #endif
79 PUBLIC void *(*magic_real_mmap)(void *start, size_t length, int prot, int flags,
80 int fd, off_t offset) = &mmap;
81 PUBLIC int (*magic_real_munmap)(void *start, size_t length) = &munmap;
83 PUBLIC int (*magic_real_brk)(void *addr) = &brk;
84 PUBLIC void *(*magic_real_sbrk)(intptr_t increment) = &sbrk;
86 #ifndef __MINIX
87 PUBLIC void *(*magic_real_shmat)(int shmid, const void *shmaddr, int shmflg) = &shmat;
88 PUBLIC int (*magic_real_shmdt)(const void *shmaddr) = &shmdt;
90 PUBLIC void *(*magic_real_mmap64)(void *start, size_t length, int prot, int flags,
91 int fd, off_t pgoffset) = &mmap64;
92 #else
93 PUBLIC void *(*magic_real_vm_map_cacheblock)(dev_t dev, off_t dev_offset,
94 ino_t ino, off_t ino_offset, u32_t *flags, int blocksize) = &vm_map_cacheblock;
95 #endif
97 /* Use magic_real* functions in the rest of the file. */
98 #include <magic_real_mem.h>
100 /* Macros for memory usage logging. */
101 #if MAGIC_MEM_USAGE_OUTPUT_CTL
102 #define MAGIC_MEM_DEBUG_PREFIX "MEM_USAGE: "
103 #define TIMESTAMP_STR "%llu"
104 #define TIMESTAMP_ARG (util_time_tsc_read_ns(magic_cycles_per_ns))
105 #define MAGIC_MEM_DEBUG_EVENT(EVENT, FORMAT, ...) \
106 _magic_printf(MAGIC_MEM_DEBUG_PREFIX TIMESTAMP_STR " " #EVENT " " FORMAT "\n", TIMESTAMP_ARG, __VA_ARGS__)
107 #define MAGIC_MEM_DEBUG_EVENT_1(event, ptr) MAGIC_MEM_DEBUG_EVENT(event, "%u", (unsigned) ptr)
108 #define MAGIC_MEM_DEBUG_EVENT_2(event, ptr, type) MAGIC_MEM_DEBUG_EVENT(event, "%u %lu", (unsigned) ptr, type)
109 #define MAGIC_MEM_DEBUG_EVENT_3(event, ptr, type, size) MAGIC_MEM_DEBUG_EVENT(event, "%u %lu %d", (unsigned) ptr, type, size)
111 #if (MAGIC_MEM_USAGE_OUTPUT_CTL == 1)
112 /* use the hash of the name (extended with line number & file name) as dynamic type */
113 #define MAGIC_MEM_GET_DTYPE() util_strhash(0, name)
114 #elif (MAGIC_MEM_USAGE_OUTPUT_CTL == 2)
115 /* use the hash of the stacktrace as a dynamic type */
116 #define MAGIC_MEM_GET_DTYPE() util_stacktrace_hash()
117 #endif
118 #define MAGIC_MEM_DEBUG_ALLOC(ptr, size) MAGIC_MEM_DEBUG_EVENT_3(alloc, ptr, (MAGIC_MEMPOOL_MGMT_IS_ACTIVE() ? MAGIC_MEMPOOL_GET_DTYPE() : MAGIC_MEM_GET_DTYPE()), size)
119 #define MAGIC_MEM_DEBUG_FREE(ptr) MAGIC_MEM_DEBUG_EVENT_1(dealloc, ptr)
120 #define MAGIC_MEM_DEBUG_RESET(ptr) MAGIC_MEM_DEBUG_EVENT_1(reset, ptr)
121 #define MAGIC_MEM_DEBUG_REUSE(ptr, type) MAGIC_MEM_DEBUG_EVENT_2(reuse, ptr, type)
122 #else
123 #define MAGIC_MEM_GET_DTYPE() 0
124 #define MAGIC_MEM_DEBUG_ALLOC(ptr, size)
125 #define MAGIC_MEM_DEBUG_FREE(ptr)
126 #define MAGIC_MEM_DEBUG_RESET(ptr)
127 #define MAGIC_MEM_DEBUG_REUSE(ptr, type)
128 #endif
130 /*===========================================================================*
131 * magic_mempool_alloc_id *
132 *===========================================================================*/
133 MAGIC_MACRO_FUNC short magic_mempool_alloc_id(void)
135 short i, id = -1;
137 MAGIC_MPDESC_LOCK();
139 /* Find a free slot. */
140 for(i = 0; i < MAGIC_MAX_MEMPOOLS; i++) {
141 if(MAGIC_MPDESC_IS_FREE(&_magic_mpdescs[i])) {
142 MAGIC_MPDESC_ALLOC(&_magic_mpdescs[i]);
143 id = i + 1;
144 break;
148 MAGIC_MPDESC_UNLOCK();
150 assert((id > 0) && (id <= MAGIC_MAX_MEMPOOLS) && "Ran out of memory pool descriptors!");
152 return id;
155 /*===========================================================================*
156 * magic_mempool_create_begin *
157 *===========================================================================*/
158 MAGIC_HOOK void magic_mempool_create_begin(__MDEBUG_ARGS__)
160 MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
161 assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
162 MAGIC_MEMPOOL_SET_ID(magic_mempool_alloc_id());
163 MAGIC_MEMPOOL_SET_DTYPE(MAGIC_MEM_GET_DTYPE());
166 /*===========================================================================*
167 * magic_mempool_create_end *
168 *===========================================================================*/
169 MAGIC_HOOK void magic_mempool_create_end(void* addr, int indirection)
171 void* pool;
172 pool = (indirection && addr) ? *((void**)addr) : addr;
173 assert(pool && "Cannot have a NULL pool pointer.");
174 _magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1].addr = pool;
175 magic_mempool_mgmt_end();
178 /*===========================================================================*
179 * magic_mempool_lookup_by_addr *
180 *===========================================================================*/
181 MAGIC_MACRO_FUNC short magic_mempool_lookup_by_addr(void* addr)
183 short i, id = MAGIC_MEMPOOL_ID_UNKNOWN;
185 if (addr) {
186 for(i = 0; i < MAGIC_MAX_MEMPOOLS; i++) {
187 if(_magic_mpdescs[i].addr == addr) {
188 id = i + 1;
189 break;
194 return id;
197 /*===========================================================================*
198 * magic_mempool_reset *
199 *===========================================================================*/
200 MAGIC_MACRO_FUNC void magic_mempool_reset(const char* mempool_name, int reset_name)
202 struct _magic_dsentry *prev_dsentry, *dsentry, *block_dsentry;
203 struct _magic_sentry* sentry;
205 MAGIC_DSENTRY_LOCK();
206 MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(_magic_first_mempool_dsentry, prev_dsentry, dsentry, sentry,
207 if (sentry->name == mempool_name) {
208 block_dsentry = MAGIC_DSENTRY_NEXT_MEMBLOCK(dsentry);
209 if (block_dsentry != NULL) {
210 struct _magic_dsentry *tmp_block_dsentry =
211 MAGIC_PCAS(&MAGIC_DSENTRY_NEXT_MEMBLOCK(dsentry), block_dsentry, NULL);
212 assert(tmp_block_dsentry == block_dsentry && "New blocks have been allocated from a reseted mempool!");
214 if (reset_name) {
215 const char *tmp_name =
216 MAGIC_PCAS(&sentry->name, mempool_name, MAGIC_MEMPOOL_NAME_UNKNOWN);
217 assert(tmp_name == mempool_name && "The name of the mempool has changed while being reseted!");
219 MAGIC_MEM_DEBUG_RESET((char*)dsentry);
223 MAGIC_DSENTRY_UNLOCK();
226 /*===========================================================================*
227 * magic_mempool_destroy_begin *
228 *===========================================================================*/
229 MAGIC_HOOK void magic_mempool_destroy_begin(void* addr, int memory_reuse)
231 magic_mempool_mgmt_begin(addr);
232 if (addr && memory_reuse) {
233 assert(MAGIC_MEMPOOL_ID_IS_SET() && "Cannot destroy a pool with an unknown id.");
234 magic_mempool_reset(MAGIC_MEMPOOL_GET_NAME(), TRUE);
238 /*===========================================================================*
239 * magic_mempool_destroy_end *
240 *===========================================================================*/
241 MAGIC_HOOK void magic_mempool_destroy_end()
243 MAGIC_MPDESC_LOCK();
245 MAGIC_MPDESC_FREE(&_magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1]);
247 MAGIC_MPDESC_UNLOCK();
249 magic_mempool_mgmt_end();
252 /*===========================================================================*
253 * magic_mempool_mgmt_begin *
254 *===========================================================================*/
255 MAGIC_HOOK void magic_mempool_mgmt_begin(void* addr)
257 short id;
259 MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
260 assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
262 id = magic_mempool_lookup_by_addr(addr);
263 /* For some reason, this mempool has not been registered yet, reserve a new slot in the mempool array. */
264 if (addr && (id == MAGIC_MEMPOOL_ID_UNKNOWN)) {
265 id = magic_mempool_alloc_id();
266 _magic_mpdescs[id - 1].addr = addr;
268 MAGIC_MEMPOOL_SET_ID(id);
271 /*===========================================================================*
272 * magic_mempool_mgmt_end *
273 *===========================================================================*/
274 MAGIC_HOOK void magic_mempool_mgmt_end()
276 MAGIC_MEMPOOL_SET_ID(MAGIC_MEMPOOL_ID_UNKNOWN);
277 assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
278 MAGIC_MEMPOOL_MGMT_UNSET_ACTIVE();
281 /*===========================================================================*
282 * magic_mempool_reset_begin *
283 *===========================================================================*/
284 MAGIC_HOOK void magic_mempool_reset_begin(void* addr)
286 magic_mempool_mgmt_begin(addr);
287 /* skip reset when it has been disabled by the application. */
288 if (magic_mempool_allow_reset) {
289 if (addr != NULL) {
290 assert(MAGIC_MEMPOOL_ID_IS_SET() && "Cannot reset a pool with an unknown id.");
291 magic_mempool_reset(MAGIC_MEMPOOL_GET_NAME(), TRUE);
296 /*===========================================================================*
297 * magic_mempool_dsentry_set_name *
298 *===========================================================================*/
299 MAGIC_MACRO_FUNC void magic_mempool_dsentry_set_name(struct _magic_dsentry* dsentry,
300 const char* name)
302 const char *old_name, *ret;
304 if ((name == MAGIC_MEMPOOL_NAME_UNKNOWN) || (name == MAGIC_MEMPOOL_NAME_DETACHED)) {
305 do {
306 old_name = MAGIC_DSENTRY_TO_SENTRY(dsentry)->name;
307 } while (MAGIC_CAS(&MAGIC_DSENTRY_TO_SENTRY(dsentry)->name, old_name, name) != old_name && old_name != name);
308 } else {
309 old_name = MAGIC_DSENTRY_TO_SENTRY(dsentry)->name;
310 if (old_name != name) {
311 if (!strncmp(old_name, MAGIC_MEMPOOL_NAME_PREFIX, strlen(MAGIC_MEMPOOL_NAME_PREFIX))) {
312 assert(((old_name == MAGIC_MEMPOOL_NAME_UNKNOWN) || (old_name == MAGIC_MEMPOOL_NAME_DETACHED))
313 && "Cannot overwrite an already existing valid memory pool name!");
315 ret = MAGIC_CAS(&MAGIC_DSENTRY_TO_SENTRY(dsentry)->name, old_name, name);
316 assert((ret == old_name || ret == name) && "Cannot overwrite an already existing valid memory pool name!");
321 /*===========================================================================*
322 * magic_mempool_dsentry_update *
323 *===========================================================================*/
324 MAGIC_MACRO_FUNC void magic_mempool_dsentry_update(struct _magic_dsentry* dsentry,
325 const char* name)
327 struct _magic_sentry* sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
328 struct _magic_dsentry* next_mempool_dsentry;
329 int flags;
330 /* set the magic state mempool flag atomically */
331 do {
332 flags = sentry->flags;
333 } while (MAGIC_CAS(&sentry->flags, flags, flags | MAGIC_STATE_MEMPOOL) != flags && !(flags & MAGIC_STATE_MEMPOOL));
334 magic_mempool_dsentry_set_name(dsentry, name);
335 /* the thread that updates the id adds the dsentry to the mempool dsentry list */
336 if (!(flags & MAGIC_STATE_MEMPOOL)) {
337 /* Add the new dsentry before the first dsentry atomically. */
338 do {
339 next_mempool_dsentry = _magic_first_mempool_dsentry;
340 MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = next_mempool_dsentry;
341 } while(MAGIC_CAS(&_magic_first_mempool_dsentry, next_mempool_dsentry, dsentry) != next_mempool_dsentry);
345 /*===========================================================================*
346 * mempool_block_alloc_template *
347 *===========================================================================*/
348 MAGIC_FUNC void *mempool_block_alloc_template(void* addr, size_t size)
350 return NULL;
353 /*===========================================================================*
354 * magic_mempool_block_alloc_template *
355 *===========================================================================*/
356 PUBLIC void *magic_mempool_block_alloc_template(__MA_ARGS__ void* addr, size_t size)
358 void *ptr, *data_ptr;
359 struct _magic_sentry* mempool_sentry;
360 struct _magic_dsentry* mempool_dsentry, *next_block_dsentry;
362 magic_mempool_mgmt_begin(addr);
363 /* don't set the memory wrapper flag, this function is supposed to allocate memory from a pool
364 and not using the standard allocators. it might also call other memory pool management functions */
365 if(size > 0) {
366 /* this call should be replaced with a call to a "real" block allocation function, when generating custom wrappers */
367 ptr = mempool_block_alloc_template(addr, MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP));
368 MAGIC_MEM_PRINTF("%s: ptr = malloc(size) <-> 0x%08x = malloc(%d)\n", __FUNCTION__,(unsigned) ptr, MAGIC_SIZE_TO_REAL(size));
369 data_ptr = magic_alloc(__MA_VALUES__ ptr, size, MAGIC_STATE_HEAP | MAGIC_STATE_MEMBLOCK);
370 if(data_ptr == MAGIC_MEM_FAILED) {
371 /* cannot free individual blocks inside the pool */
372 data_ptr = NULL;
373 errno = ENOMEM;
374 } else if (ptr) {
375 /* lookup the pool buffer dsentry from which this block was allocated */
376 mempool_sentry = magic_mempool_sentry_lookup_by_range(ptr, NULL);
377 if (!mempool_sentry && magic_mempool_allow_external_alloc) {
378 mempool_sentry = magic_sentry_lookup_by_range(ptr, NULL);
379 if (mempool_sentry) {
380 magic_mempool_dsentry_update(MAGIC_DSENTRY_FROM_SENTRY(mempool_sentry), MAGIC_MEMPOOL_GET_NAME());
384 assert(mempool_sentry && "XXX Mempool dsentry not found for this memblock dsentry: memory not allocated from a memory pool management function?");
385 mempool_dsentry = MAGIC_DSENTRY_FROM_SENTRY(mempool_sentry);
387 /* Reuse of buffers across pools - propagate the new pool name */
388 if (MAGIC_MEMPOOL_ID_IS_SET() && (mempool_sentry->name != MAGIC_MEMPOOL_GET_NAME())) {
389 assert(magic_mempool_allow_reuse && "Pool memory reuse is disabled!");
390 magic_mempool_dsentry_set_name(mempool_dsentry, MAGIC_MEMPOOL_GET_NAME());
392 MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr)))->name = mempool_sentry->name;
394 /* Add the new dsentry before the first block dsentry chained to the memory pool dsentry, atomically.
395 The list should be circular - the last block dsentry (first one added) points to the memory pool dsentry. */
396 do {
397 next_block_dsentry = MAGIC_DSENTRY_NEXT_MEMBLOCK(mempool_dsentry);
398 MAGIC_DSENTRY_NEXT_MEMBLOCK(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))) = next_block_dsentry ? next_block_dsentry : mempool_dsentry;
399 }while(MAGIC_CAS(&(MAGIC_DSENTRY_NEXT_MEMBLOCK(mempool_dsentry)), next_block_dsentry, MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))) != next_block_dsentry);
401 /* First write to this pool buffer, potential reuse */
402 if (next_block_dsentry == NULL) {
403 MAGIC_MEM_DEBUG_REUSE((char*)mempool_dsentry, MAGIC_MEMPOOL_GET_DTYPE());
407 else {
408 /* Some applications return a valid pointer even if size is 0... */
409 data_ptr = mempool_block_alloc_template(addr, size);
411 magic_mempool_mgmt_end();
413 return data_ptr;
416 /*===========================================================================*
417 * magic_create_dsentry *
418 *===========================================================================*/
419 PUBLIC int magic_create_dsentry(struct _magic_dsentry *dsentry,
420 void *data_ptr, struct _magic_type *type, size_t size, int flags,
421 const char *name, const char *parent_name)
423 /* This function does not require any dsentry locking. */
424 struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
425 struct _magic_dsentry *next_dsentry, *next_mempool_dsentry;
426 size_t type_size;
427 int is_varsized = 0;
428 int num_vsa_elements = 0;
430 struct _magic_dsentry *saved_next = dsentry->next;
431 int save_linkage = ((flags & MAGIC_STATE_HEAP) && _magic_vars->fake_malloc);
433 MAGIC_MEM_PRINTF("Dsentry created from stacktrace:\n");
434 if (MAGIC_MEM_PRINTF != magic_null_printf) {
435 MAGIC_MEM_WRAPPER_BEGIN();
436 util_stacktrace_print_custom(MAGIC_MEM_PRINTF);
437 MAGIC_MEM_WRAPPER_END();
440 if (!type) {
441 type = MAGIC_VOID_TYPE;
443 type_size = type->size;
444 assert(size > 0);
446 memcpy(dsentry, &magic_default_dsentry, sizeof(struct _magic_dsentry));
448 /* Catch variable-sized struct allocation. */
449 if (magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) {
450 is_varsized = 1;
453 if (size % type_size != 0 && !is_varsized) {
454 /* This should only happen for uncaught variable-sized struct allocations. */
455 #if DEBUG_TYPE_SIZE_MISMATCH
456 _magic_printf("magic_create_dsentry: type <-> size mismatch, reverting to void type: size=%d, type=", size);
457 MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
458 _magic_printf("\n");
459 #endif
460 type = MAGIC_VOID_TYPE;
461 type_size = type->size;
462 flags |= MAGIC_STATE_TYPE_SIZE_MISMATCH;
465 if (size == type_size && !is_varsized) {
466 sentry->type = type;
468 else {
469 struct _magic_type *array_type = &(dsentry->type);
470 MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(array_type, type,
471 MAGIC_DSENTRY_TO_TYPE_ARR(dsentry), size, num_vsa_elements);
472 array_type->id = MAGIC_FAA(&_magic_types_next_id, 1);
473 assert(_magic_types_next_id < MAGIC_ID_MAX);
474 sentry->type = array_type;
477 sentry->flags |= flags;
478 sentry->address = data_ptr;
480 if (name) {
481 sentry->name = name;
483 if (parent_name) {
484 dsentry->parent_name = parent_name;
486 sentry->id = MAGIC_FAA(&_magic_sentries_next_id, 1);
487 assert(_magic_sentries_next_id < MAGIC_ID_MAX);
490 * TODO: Also add per-callsite index to handle the following:
491 * for (;;) { p = malloc(); }
493 if (magic_mem_create_dsentry_site_id) {
494 MAGIC_MEM_WRAPPER_BEGIN();
496 * XXX: This is so damn ugly, but we don't want to include
497 * any magic_* functions in the stacktrace hash.
498 * This should probably be done in a much more elegant manner.
500 dsentry->site_id = util_stacktrace_hash_skip((char *)"("MAGIC_PREFIX_STR);
501 MAGIC_MEM_WRAPPER_END();
504 if (save_linkage) {
505 dsentry->next = saved_next;
506 return 0;
509 /* Add the new dsentry before the first dsentry atomically.
510 * Skip memblock dsentries to make pool reset/destruction faster.
512 if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_MEMBLOCK)) {
513 do {
514 next_dsentry = _magic_first_dsentry;
515 MAGIC_DSENTRY_NEXT(dsentry) = next_dsentry;
516 } while(MAGIC_CAS(&_magic_first_dsentry, next_dsentry, dsentry) != next_dsentry);
519 #if MAGIC_DSENTRY_ALLOW_PREV
520 next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
521 if (next_dsentry) {
522 MAGIC_DSENTRY_PREV(next_dsentry) = dsentry;
524 MAGIC_DSENTRY_PREV(dsentry) = NULL;
525 #endif
527 if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_MEMPOOL)) {
528 /* Add the new dsentry before the first mempool dsentry atomically. */
529 do {
530 next_mempool_dsentry = _magic_first_mempool_dsentry;
531 MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = next_mempool_dsentry;
532 } while(MAGIC_CAS(&_magic_first_mempool_dsentry, next_mempool_dsentry, dsentry) != next_mempool_dsentry);
534 magic_update_dsentry_ranges = 1;
536 if (magic_mem_create_dsentry_cb)
537 magic_mem_create_dsentry_cb(dsentry);
539 return 0;
542 /*===========================================================================*
543 * magic_create_obdsentry *
544 *===========================================================================*/
545 PUBLIC struct _magic_obdsentry* magic_create_obdsentry(void *data_ptr,
546 struct _magic_type *type, size_t size, int flags,
547 const char *name, const char *parent_name)
549 struct _magic_obdsentry *obdsentry = NULL;
550 int i, ret;
552 /* Check name. */
553 if(!name || !strcmp(name, "")) {
554 return NULL;
556 else if(strlen(name) >= MAGIC_MAX_OBDSENTRY_NAME_LEN) {
557 return NULL;
560 /* Check parent name. */
561 if(!parent_name || !strcmp(parent_name, "")) {
562 parent_name = MAGIC_OBDSENTRY_DEFAULT_PARENT_NAME;
564 if(strlen(parent_name) >= MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN) {
565 return NULL;
568 MAGIC_MEM_WRAPPER_LBEGIN();
570 /* Find a free slot. */
571 for(i=0;i<MAGIC_MAX_OBDSENTRIES;i++) {
572 if(MAGIC_OBDSENTRY_IS_FREE(&_magic_obdsentries[i])) {
573 obdsentry = &_magic_obdsentries[i];
574 break;
577 if(!obdsentry) {
578 MAGIC_MEM_WRAPPER_LEND();
579 return NULL;
582 /* Create the dsentry. */
583 strcpy(obdsentry->name, name);
584 strcpy(obdsentry->parent_name, parent_name);
585 flags |= MAGIC_STATE_OUT_OF_BAND;
586 ret = magic_create_dsentry(MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry), data_ptr, type,
587 size, flags, obdsentry->name, obdsentry->parent_name);
589 MAGIC_MEM_WRAPPER_LEND();
591 if(ret < 0) {
592 return NULL;
594 assert(!MAGIC_OBDSENTRY_IS_FREE(obdsentry));
596 return obdsentry;
599 /*===========================================================================*
600 * magic_update_dsentry_state *
601 *===========================================================================*/
602 PUBLIC int magic_update_dsentry_state(struct _magic_dsentry *dsentry,
603 unsigned long state)
605 int ret = 0;
606 unsigned long old_state;
607 unsigned long num_dead_dsentries;
608 unsigned long size, size_dead_dsentries;
609 size = MAGIC_DSENTRY_TO_SENTRY(dsentry)->type->size;
611 switch(state) {
612 case MAGIC_DSENTRY_MSTATE_FREED:
613 old_state = MAGIC_CAS(&dsentry->magic_state, MAGIC_DSENTRY_MSTATE_DEAD,
614 MAGIC_DSENTRY_MSTATE_FREED);
615 if(old_state != MAGIC_DSENTRY_MSTATE_DEAD) {
616 ret = MAGIC_EBADMSTATE;
617 break;
619 if (!MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMBLOCK)) {
620 num_dead_dsentries = MAGIC_FAS(&magic_num_dead_dsentries, 1) - 1;
621 size_dead_dsentries = MAGIC_FAS(&magic_size_dead_dsentries, size) - size;
622 MAGIC_MEM_PRINTF("magic_update_dsentry_state: --magic_num_dead_dsentries (num=%d, size=%d)\n", num_dead_dsentries, size_dead_dsentries);
624 break;
625 case MAGIC_DSENTRY_MSTATE_DEAD:
626 old_state = MAGIC_CAS(&dsentry->magic_state, MAGIC_DSENTRY_MSTATE_ALIVE,
627 MAGIC_DSENTRY_MSTATE_DEAD);
628 if(old_state != MAGIC_DSENTRY_MSTATE_ALIVE) {
629 ret = (old_state == MAGIC_DSENTRY_MSTATE_DEAD
630 || old_state == MAGIC_DSENTRY_MSTATE_FREED)
631 ? MAGIC_EBADMSTATE : MAGIC_EBADENT;
632 break;
634 MAGIC_DSENTRY_TO_SENTRY(dsentry)->id = MAGIC_FAA(&_magic_sentries_next_id, 1);
635 assert(_magic_sentries_next_id < MAGIC_ID_MAX);
636 if (!MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMBLOCK)) {
637 num_dead_dsentries = MAGIC_FAA(&magic_num_dead_dsentries, 1) + 1;
638 size_dead_dsentries = MAGIC_FAA(&magic_size_dead_dsentries, size) + size;
639 MAGIC_MEM_PRINTF("magic_update_dsentry_state: ++magic_num_dead_dsentries (num=%d, size=%d)\n", num_dead_dsentries, size_dead_dsentries);
640 if(!magic_ignore_dead_dsentries
641 && MAGIC_DEAD_DSENTRIES_NEED_FREEING()) {
642 magic_free_dead_dsentries();
645 break;
646 default:
647 ret = MAGIC_EINVAL;
648 break;
651 return ret;
654 /*===========================================================================*
655 * magic_free_dsentry *
656 *===========================================================================*/
657 PRIVATE int magic_free_dsentry(struct _magic_dsentry *dsentry)
659 int ret = 0;
660 struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
661 int region = MAGIC_STATE_REGION(sentry);
662 void *ptr = MAGIC_PTR_FROM_DSENTRY(dsentry);
663 size_t page_size, size;
664 void *data_ptr, *aligned_ptr;
665 int from_wrapper = MAGIC_MEM_WRAPPER_IS_ACTIVE();
666 assert(dsentry->magic_number == MAGIC_DSENTRY_MNUM_NULL);
668 if (!from_wrapper) {
669 MAGIC_MEM_WRAPPER_BEGIN();
672 if (magic_mem_heap_free_cb) {
673 ret = magic_mem_heap_free_cb(dsentry);
674 if (ret != MAGIC_ENOENT)
675 return ret;
678 * If the callback returned MAGIC_ENOENT, fallback to
679 * the default behavior.
681 ret = 0;
684 /* A MAP_SHARED region will have both MAGIC_STATE_MAP and MAGIC_STATE_SHM. */
685 if (region == (MAGIC_STATE_MAP | MAGIC_STATE_SHM))
686 region = MAGIC_STATE_MAP;
687 switch (region) {
688 case MAGIC_STATE_HEAP:
689 MAGIC_MEM_DEBUG_FREE(ptr);
690 free(ptr);
691 break;
692 case MAGIC_STATE_MAP:
693 case MAGIC_STATE_SHM:
694 page_size = MAGIC_PAGE_SIZE;
695 size = MAGIC_DSENTRY_TO_SENTRY(dsentry)->type->size;
696 data_ptr = MAGIC_PTR_TO_DATA(ptr);
697 aligned_ptr = ((char *)data_ptr) - page_size;
699 if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DETACHED)) {
700 size_t padding_size = (size_t) dsentry->ext;
701 MAGIC_MEM_DEBUG_FREE(ptr);
702 ret = munmap((char *)aligned_ptr, page_size + size + padding_size);
704 else {
705 #ifndef __MINIX
706 if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_SHM))
707 ret = shmdt(data_ptr);
708 else
709 #endif
710 ret = munmap(data_ptr, size);
711 MAGIC_MEM_DEBUG_FREE(ptr);
712 munmap(aligned_ptr, page_size);
714 if (ret != 0) {
715 ret = MAGIC_EBADENT;
717 break;
718 default:
719 ret = MAGIC_EBADENT;
720 break;
722 if (!from_wrapper) {
723 MAGIC_MEM_WRAPPER_END();
726 return ret;
729 /*===========================================================================*
730 * magic_free_dead_dsentries *
731 *===========================================================================*/
732 PUBLIC void magic_free_dead_dsentries()
734 struct _magic_dsentry *prev_dsentry, *dsentry, *next_first_dsentry, *skipped_dsentry;
735 struct _magic_sentry *sentry;
736 unsigned long num_dead_dsentries;
737 int dead_dsentries_left;
738 int ret;
740 MAGIC_DSENTRY_LOCK();
742 skipped_dsentry = NULL;
743 num_dead_dsentries = magic_num_dead_dsentries;
744 next_first_dsentry = _magic_first_dsentry;
745 if (next_first_dsentry) {
746 /* if the first dsentry is dead, skip it to eliminate contention on the list head */
747 if (next_first_dsentry->magic_state == MAGIC_DSENTRY_MSTATE_DEAD){
748 num_dead_dsentries--;
752 if(!next_first_dsentry || num_dead_dsentries == 0) {
753 MAGIC_DSENTRY_UNLOCK();
754 return;
757 MAGIC_MEM_PRINTF("magic_free_dead_dsentries: Freeing %d dead dsentries...\n", num_dead_dsentries);
759 /* Eliminate the dead dsentries but always skip the first one to eliminate contention on the head. */
760 do {
761 dead_dsentries_left = 0;
762 MAGIC_DSENTRY_ITER(next_first_dsentry->next, prev_dsentry, dsentry, sentry,
763 /* normal dsentry to be freed */
764 if ((dsentry->magic_state != MAGIC_DSENTRY_MSTATE_DEAD) ||
765 (magic_update_dsentry_state(dsentry, MAGIC_DSENTRY_MSTATE_FREED) < 0)) {
766 next_first_dsentry = dsentry;
767 } else {
768 magic_destroy_dsentry(dsentry, prev_dsentry);
769 ret = magic_free_dsentry(dsentry);
770 if(ret != 0) {
771 _magic_printf("Warning: magic_free_dsentry failed with return code %d for: ", ret);
772 MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
773 MAGIC_MEM_PRINTF("\n");
775 num_dead_dsentries--;
776 dead_dsentries_left = 1;
777 break;
780 } while(dead_dsentries_left && num_dead_dsentries > 0);
781 assert(num_dead_dsentries == 0);
783 MAGIC_DSENTRY_UNLOCK();
786 /*===========================================================================*
787 * magic_destroy_dsentry *
788 *===========================================================================*/
789 PUBLIC void magic_destroy_dsentry(struct _magic_dsentry *dsentry,
790 struct _magic_dsentry *prev_dsentry)
792 struct _magic_dsentry *next_dsentry, *next_mempool_dsentry, *prev_mempool_dsentry = NULL;
793 int dsentry_destroyed, mempool_dsentry_destroyed;
795 if(magic_destroy_dsentry_ext_cb && MAGIC_DSENTRY_HAS_EXT(dsentry)) {
796 magic_destroy_dsentry_ext_cb(dsentry);
798 if (MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry), MAGIC_STATE_MEMPOOL)) {
799 do {
800 if(!prev_mempool_dsentry) {
801 if(MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) != MAGIC_DSENTRY_NEXT_MEMPOOL(_magic_first_mempool_dsentry)) {
802 prev_mempool_dsentry = magic_mempool_dsentry_prev_lookup(dsentry);
803 assert(prev_mempool_dsentry != (struct _magic_dsentry *) MAGIC_ENOPTR && "Dsentry not found!");
806 if(prev_mempool_dsentry) {
807 MAGIC_DSENTRY_NEXT_MEMPOOL(prev_mempool_dsentry) = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry);
808 mempool_dsentry_destroyed = 1;
810 else {
811 /* Remove the first dsentry atomically. */
812 next_mempool_dsentry = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry);
813 mempool_dsentry_destroyed = (MAGIC_CAS(&_magic_first_mempool_dsentry,
814 dsentry, next_mempool_dsentry) == dsentry);
816 } while(!mempool_dsentry_destroyed);
817 MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = NULL;
819 do {
820 #if MAGIC_DSENTRY_ALLOW_PREV
821 prev_dsentry = MAGIC_DSENTRY_PREV(dsentry);
822 #else
823 if(!prev_dsentry) {
824 if(MAGIC_DSENTRY_NEXT(dsentry) != MAGIC_DSENTRY_NEXT(_magic_first_dsentry)) {
825 prev_dsentry = magic_dsentry_prev_lookup(dsentry);
826 assert(prev_dsentry != (struct _magic_dsentry *) MAGIC_ENOPTR && "Dsentry not found!");
829 #endif
831 if(prev_dsentry) {
832 MAGIC_DSENTRY_NEXT(prev_dsentry) = MAGIC_DSENTRY_NEXT(dsentry);
833 dsentry_destroyed = 1;
835 else {
836 /* Remove the first dsentry atomically. */
837 next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
838 dsentry_destroyed = (MAGIC_CAS(&_magic_first_dsentry,
839 dsentry, next_dsentry) == dsentry);
841 } while(!dsentry_destroyed);
843 #if MAGIC_DSENTRY_ALLOW_PREV
844 next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
845 if(next_dsentry) {
846 MAGIC_DSENTRY_PREV(next_dsentry) = MAGIC_DSENTRY_PREV(dsentry);
848 MAGIC_DSENTRY_PREV(dsentry) = NULL;
849 #endif
851 dsentry->magic_number = MAGIC_DSENTRY_MNUM_NULL;
852 MAGIC_DSENTRY_NEXT(dsentry) = NULL;
855 /*===========================================================================*
856 * magic_destroy_obdsentry_by_addr *
857 *===========================================================================*/
858 PUBLIC int magic_destroy_obdsentry_by_addr(void *data_ptr)
860 struct _magic_sentry *sentry;
861 struct _magic_dsentry *dsentry;
862 struct _magic_obdsentry *obdsentry;
863 int obflags = (MAGIC_STATE_DYNAMIC|MAGIC_STATE_OUT_OF_BAND);
865 MAGIC_MEM_WRAPPER_LBEGIN();
867 /* Lookup the obdsentry. */
868 sentry = magic_sentry_lookup_by_addr(data_ptr, NULL);
869 if(!sentry || ((sentry->flags & obflags) != obflags)) {
870 MAGIC_MEM_WRAPPER_LEND();
871 return MAGIC_EINVAL;
873 dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
874 obdsentry = MAGIC_OBDSENTRY_FROM_DSENTRY(dsentry);
876 /* Destroy it and free obdsentry slot. */
877 magic_destroy_dsentry(dsentry, NULL);
878 MAGIC_OBDSENTRY_FREE(obdsentry);
880 MAGIC_MEM_WRAPPER_LEND();
882 return 0;
885 /*===========================================================================*
886 * magic_destroy_dsentry_set_ext_cb *
887 *===========================================================================*/
888 PUBLIC void magic_destroy_dsentry_set_ext_cb(const magic_dsentry_cb_t cb)
890 magic_destroy_dsentry_ext_cb = cb;
893 /*===========================================================================*
894 * magic_update_dsentry *
895 *===========================================================================*/
896 PUBLIC int magic_update_dsentry(void* addr, struct _magic_type *type)
898 struct _magic_dsentry *prev_dsentry, *dsentry;
899 struct _magic_sentry* sentry;
900 size_t size, type_size;
901 int is_varsized = 0;
902 int num_vsa_elements = 0;
904 MAGIC_DSENTRY_LOCK();
905 MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
906 if(sentry->address == addr) {
907 size = sentry->type->size;
908 type_size = type->size;
910 /* Catch variable-sized struct allocation. */
911 if(magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) {
912 is_varsized = 1;
915 if(size % type_size != 0 && !is_varsized) {
916 return MAGIC_EBADENT;
918 if(size == type_size && !is_varsized) {
919 sentry->type = type;
921 else {
922 struct _magic_type *array_type = &(dsentry->type);
923 MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(array_type, type,
924 MAGIC_DSENTRY_TO_TYPE_ARR(dsentry), size, num_vsa_elements);
925 array_type->id = MAGIC_FAA(&_magic_types_next_id, 1);
926 assert(_magic_types_next_id < MAGIC_ID_MAX);
927 sentry->type = array_type;
929 return 0;
932 MAGIC_DSENTRY_UNLOCK();
934 return MAGIC_ENOENT;
937 /*===========================================================================*
938 * magic_stack_init *
939 *===========================================================================*/
940 PUBLIC void magic_stack_init()
942 struct _magic_obdsentry *obdsentry;
943 char **ptr;
944 size_t size;
945 void *initial_stack_bottom, *initial_stack_top;
946 unsigned long* word_ptr;
947 int argc;
948 char **argv;
950 assert(!_magic_first_stack_dsentry && !_magic_last_stack_dsentry);
952 /* Find initial stack bottom and top, this should be portable enough */
953 for (ptr = environ ; *ptr ; ptr++);
954 if (ptr == environ){
955 /* the environment is empty, and ptr still points to environ.
956 * decrement ptr twice: once to point at the argv terminator,
957 * and once to point to point at the last argument, which will be the stack bottom
959 ptr -= 2;
960 } else {
961 /* environment is not empty. decrement the pointer,
962 * because the for loop walked past the last env variable pointer.
964 ptr--;
967 if (*ptr) {
968 initial_stack_bottom = *ptr+strlen(*ptr)+1;
969 word_ptr = (unsigned long*) environ;
970 word_ptr--;
971 assert(*word_ptr == 0); /* argv terminator */
972 word_ptr--;
973 argc = 0;
974 while(*word_ptr != (unsigned long) argc) {
975 argc++;
976 word_ptr--;
978 argv = (char**) (word_ptr+1);
979 initial_stack_top = argv;
980 } else {
981 /* Environ and argv empty?. Resort to defaults. */
982 initial_stack_top = ptr;
983 initial_stack_bottom = environ;
985 size = (size_t)initial_stack_bottom - (size_t)initial_stack_top + 1;
987 /* Create the first stack dsentry. */
988 obdsentry = magic_create_obdsentry(initial_stack_top, MAGIC_VOID_TYPE,
989 size, MAGIC_STATE_STACK, MAGIC_ALLOC_INITIAL_STACK_NAME, NULL);
990 assert(obdsentry);
991 _magic_first_stack_dsentry = _magic_last_stack_dsentry = MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry);
994 /*===========================================================================*
995 * magic_stack_dsentries_create *
996 *===========================================================================*/
997 PUBLIC void magic_stack_dsentries_create(
998 struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries,
999 /* struct _magic_dsentry *dsentry, struct _magic_type *type, void* data_ptr, const char* function_name, const char* name, */ ...)
1001 int i;
1002 struct _magic_dsentry *dsentry;
1003 struct _magic_type *type;
1004 void* data_ptr;
1005 const char* function_name;
1006 const char* name;
1007 char *min_data_ptr = NULL, *max_data_ptr = NULL;
1008 va_list va;
1010 assert(num_dsentries > 0);
1012 MAGIC_DSENTRY_LOCK();
1013 assert(_magic_first_stack_dsentry && "First stack dsentry not found!");
1014 va_start(va, num_dsentries);
1015 *prev_last_stack_dsentry = _magic_last_stack_dsentry;
1016 for (i = 0 ; i < num_dsentries ; i++) {
1017 dsentry = va_arg(va, struct _magic_dsentry *);
1018 type = va_arg(va, struct _magic_type *);
1019 data_ptr = va_arg(va, void *);
1020 function_name = va_arg(va, const char *);
1021 name = va_arg(va, const char *);
1022 if (i == num_dsentries - 1) {
1023 /* Return address. */
1024 int *value_set = (void*) type;
1025 data_ptr = MAGIC_FRAMEADDR_TO_RETADDR_PTR(data_ptr);
1026 type = &(dsentry->type);
1027 magic_create_dsentry(dsentry, data_ptr, MAGIC_VOID_TYPE, MAGIC_VOID_TYPE->size,
1028 MAGIC_STATE_STACK | MAGIC_STATE_CONSTANT | MAGIC_STATE_ADDR_NOT_TAKEN,
1029 name, function_name);
1030 memcpy(type, &magic_default_ret_addr_type, sizeof(struct _magic_type));
1031 type->contained_types = MAGIC_DSENTRY_TO_TYPE_ARR(dsentry);
1032 type->contained_types[0] = MAGIC_VOID_TYPE;
1033 type->value_set = value_set;
1034 value_set[0] = 1;
1035 value_set[1] = *((int *)data_ptr);
1037 /* Safe to override the type non-atomically.
1038 * The new type is only more restrictive, and nobody could
1039 * have touched this stack dsentry in the meantime.
1041 MAGIC_DSENTRY_TO_SENTRY(dsentry)->type = type;
1042 } else {
1043 /* Local variable. */
1044 magic_create_dsentry(dsentry, data_ptr, type, type->size,
1045 MAGIC_STATE_STACK, name, function_name);
1046 if (!min_data_ptr || min_data_ptr > (char *) data_ptr) {
1047 min_data_ptr = (char *) data_ptr;
1049 if (!max_data_ptr || max_data_ptr < (char *) data_ptr) {
1050 max_data_ptr = (char *) data_ptr;
1055 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1056 if (min_data_ptr && max_data_ptr) {
1057 memset(min_data_ptr, 0, max_data_ptr - min_data_ptr + 1);
1059 #endif
1061 _magic_last_stack_dsentry = dsentry;
1062 MAGIC_DSENTRY_UNLOCK();
1064 va_end(va);
1067 /*===========================================================================*
1068 * magic_stack_dsentries_destroy *
1069 *===========================================================================*/
1070 PUBLIC void magic_stack_dsentries_destroy(
1071 struct _magic_dsentry **prev_last_stack_dsentry, int num_dsentries,
1072 /* struct _magic_dsentry *dsentry, */ ...)
1074 int i;
1075 struct _magic_dsentry *dsentry;
1076 va_list va;
1078 assert(num_dsentries > 0);
1080 MAGIC_MEM_WRAPPER_LBEGIN();
1082 va_start(va, num_dsentries);
1083 _magic_last_stack_dsentry = *prev_last_stack_dsentry;
1084 for (i = 0 ; i < num_dsentries ; i++) {
1085 dsentry = va_arg(va, struct _magic_dsentry *);
1086 magic_destroy_dsentry(dsentry, NULL);
1088 va_end(va);
1090 MAGIC_MEM_WRAPPER_LEND();
1093 /*===========================================================================*
1094 * magic_create_dfunction *
1095 *===========================================================================*/
1096 PUBLIC int magic_create_dfunction(struct _magic_dfunction *dfunction,
1097 void *data_ptr, struct _magic_type *type, int flags,
1098 const char *name, const char *parent_name)
1100 struct _magic_function *function = MAGIC_DFUNCTION_TO_FUNCTION(dfunction);
1102 if(!type) {
1103 type = MAGIC_VOID_TYPE;
1106 memcpy(dfunction, &magic_default_dfunction, sizeof(struct _magic_dfunction));
1108 assert(!(type->flags & MAGIC_TYPE_DYNAMIC) && "bad type!");
1110 function->type = type;
1111 function->flags |= flags;
1112 function->address = data_ptr;
1113 if(name) {
1114 function->name = name;
1116 if(parent_name) {
1117 dfunction->parent_name = parent_name;
1119 function->id = MAGIC_FAA(&_magic_functions_next_id, 1);
1120 assert(_magic_functions_next_id < MAGIC_ID_MAX);
1122 if(_magic_first_dfunction) {
1123 assert(_magic_last_dfunction);
1124 MAGIC_DFUNCTION_NEXT(_magic_last_dfunction) = dfunction;
1126 else {
1127 assert(!_magic_last_dfunction);
1128 assert(_magic_dfunctions_num == 0);
1129 _magic_first_dfunction = dfunction;
1131 MAGIC_DFUNCTION_PREV(dfunction) = _magic_last_dfunction;
1132 MAGIC_DFUNCTION_NEXT(dfunction) = NULL;
1133 _magic_last_dfunction = dfunction;
1134 _magic_dfunctions_num++;
1136 assert(magic_check_dfunction(dfunction, 0) && "Bad magic dfunction created!");
1137 magic_update_dfunction_ranges = 1;
1139 return 0;
1142 /*===========================================================================*
1143 * magic_destroy_dfunction *
1144 *===========================================================================*/
1145 PUBLIC void magic_destroy_dfunction(struct _magic_dfunction *dfunction)
1147 dfunction->magic_number = MAGIC_DFUNCTION_MNUM_NULL;
1148 if(MAGIC_DFUNCTION_HAS_NEXT(dfunction)) {
1149 MAGIC_DFUNCTION_PREV(MAGIC_DFUNCTION_NEXT(dfunction)) = MAGIC_DFUNCTION_PREV(dfunction);
1151 else {
1152 _magic_last_dfunction = MAGIC_DFUNCTION_PREV(dfunction);
1154 if(MAGIC_DFUNCTION_HAS_PREV(dfunction)) {
1155 MAGIC_DFUNCTION_NEXT(MAGIC_DFUNCTION_PREV(dfunction)) = MAGIC_DFUNCTION_NEXT(dfunction);
1157 else {
1158 _magic_first_dfunction = MAGIC_DFUNCTION_NEXT(dfunction);
1160 MAGIC_DFUNCTION_NEXT(dfunction) = NULL;
1161 MAGIC_DFUNCTION_PREV(dfunction) = NULL;
1162 _magic_dfunctions_num--;
1163 if(_magic_dfunctions_num == 0) {
1164 assert(!_magic_first_dfunction && !_magic_last_dfunction);
1166 else {
1167 assert(_magic_first_dfunction && _magic_last_dfunction);
1171 /*===========================================================================*
1172 * magic_create_sodesc *
1173 *===========================================================================*/
1174 PUBLIC int magic_create_sodesc(struct _magic_sodesc *sodesc)
1176 if(_magic_first_sodesc) {
1177 assert(_magic_last_sodesc);
1178 MAGIC_SODESC_NEXT(_magic_last_sodesc) = sodesc;
1180 else {
1181 assert(!_magic_last_sodesc);
1182 assert(_magic_sodescs_num == 0);
1183 _magic_first_sodesc = sodesc;
1185 MAGIC_SODESC_PREV(sodesc) = _magic_last_sodesc;
1186 MAGIC_SODESC_NEXT(sodesc) = NULL;
1187 _magic_last_sodesc = sodesc;
1188 _magic_sodescs_num++;
1190 return 0;
1193 /*===========================================================================*
1194 * magic_destroy_sodesc *
1195 *===========================================================================*/
1196 PUBLIC int magic_destroy_sodesc(struct _magic_sodesc *sodesc)
1199 * NB!: This function requires the calling thread to already
1200 * hold the DSENTRY and DFUNCTION locks.
1202 int ret;
1203 const char *name;
1204 struct _magic_dsentry *prev_dsentry, *dsentry, *last_dsentry;
1205 struct _magic_sentry *sentry;
1206 struct _magic_dfunction *dfunction, *last_dfunction;
1209 * Time to destroy all the dsentries and dfunctions
1210 * linked to the descriptor.
1212 name = sodesc->lib.name;
1213 last_dsentry = NULL;
1214 MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
1215 dsentry, sentry,
1216 if (last_dsentry)
1217 magic_destroy_dsentry(last_dsentry, NULL);
1218 last_dsentry = dsentry->parent_name == name ? dsentry : NULL;
1220 if (last_dsentry)
1221 magic_destroy_dsentry(last_dsentry, NULL);
1222 last_dfunction = NULL;
1223 MAGIC_DFUNCTION_ITER(_magic_first_dfunction, dfunction,
1224 if (last_dfunction)
1225 magic_destroy_dfunction(last_dfunction);
1226 last_dfunction = dfunction->parent_name == name ? dfunction : NULL;
1228 if(last_dfunction) magic_destroy_dfunction(last_dfunction);
1230 /* Now get rid of the descriptor. */
1231 if (MAGIC_SODESC_HAS_NEXT(sodesc)) {
1232 MAGIC_SODESC_PREV(MAGIC_SODESC_NEXT(sodesc)) =
1233 MAGIC_SODESC_PREV(sodesc);
1235 else {
1236 _magic_last_sodesc = MAGIC_SODESC_PREV(sodesc);
1238 if (MAGIC_SODESC_HAS_PREV(sodesc)) {
1239 MAGIC_SODESC_NEXT(MAGIC_SODESC_PREV(sodesc)) =
1240 MAGIC_SODESC_NEXT(sodesc);
1242 else {
1243 _magic_first_sodesc = MAGIC_SODESC_NEXT(sodesc);
1245 MAGIC_SODESC_NEXT(sodesc) = NULL;
1246 MAGIC_SODESC_PREV(sodesc) = NULL;
1247 _magic_sodescs_num--;
1248 if (_magic_sodescs_num == 0) {
1249 assert(!_magic_first_sodesc && !_magic_last_sodesc);
1251 else {
1252 assert(_magic_first_sodesc && _magic_last_sodesc);
1256 * Unmap the memory area that contained the dsentries and dfunctions
1257 * of this descriptor.
1259 ret = munmap(sodesc->lib.alloc_address, sodesc->lib.alloc_size);
1260 assert(ret == 0 && "Unable to unmap SODESC memory segment!");
1262 return 0;
1265 /*===========================================================================*
1266 * magic_create_dsodesc *
1267 *===========================================================================*/
1268 PUBLIC int magic_create_dsodesc(struct _magic_dsodesc *dsodesc)
1271 * NB!: This function requires the calling thread to already
1272 * hold the DSODESC lock.
1274 if (_magic_first_dsodesc) {
1275 assert(_magic_last_dsodesc);
1276 MAGIC_DSODESC_NEXT(_magic_last_dsodesc) = dsodesc;
1278 else {
1279 assert(!_magic_last_dsodesc);
1280 assert(_magic_dsodescs_num == 0);
1281 _magic_first_dsodesc = dsodesc;
1283 MAGIC_DSODESC_PREV(dsodesc) = _magic_last_dsodesc;
1284 MAGIC_DSODESC_NEXT(dsodesc) = NULL;
1285 _magic_last_dsodesc = dsodesc;
1286 _magic_dsodescs_num++;
1288 return 0;
1291 /*===========================================================================*
1292 * magic_destroy_dsodesc *
1293 *===========================================================================*/
1294 PUBLIC int magic_destroy_dsodesc(struct _magic_dsodesc *dsodesc)
1297 * NB!: This function requires the calling thread to already
1298 * hold the DSENTRY, DFUNCTION and DSODESC locks.
1300 int ret;
1301 const char *name;
1302 struct _magic_dsentry *prev_dsentry, *dsentry, *last_dsentry;
1303 struct _magic_sentry *sentry;
1304 struct _magic_dfunction *dfunction, *last_dfunction;
1306 dsodesc->ref_count--;
1307 /* Don't destroy the DSO descriptor quite yet, we still have references. */
1308 if (dsodesc->ref_count > 0) {
1309 return dsodesc->ref_count;
1313 * Time to destroy all the dsentries and dfunctions
1314 * linked to the descriptor.
1316 name = dsodesc->lib.name;
1317 last_dsentry = NULL;
1318 MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
1319 dsentry, sentry,
1320 if (last_dsentry)
1321 magic_destroy_dsentry(last_dsentry, NULL);
1322 last_dsentry = dsentry->parent_name == name ? dsentry : NULL;
1324 if (last_dsentry)
1325 magic_destroy_dsentry(last_dsentry, NULL);
1326 last_dfunction = NULL;
1327 MAGIC_DFUNCTION_ITER(_magic_first_dfunction, dfunction,
1328 if (last_dfunction)
1329 magic_destroy_dfunction(last_dfunction);
1330 last_dfunction = dfunction->parent_name == name ? dfunction : NULL;
1332 if (last_dfunction)
1333 magic_destroy_dfunction(last_dfunction);
1335 /* Now get rid of the descriptor. */
1336 if (MAGIC_DSODESC_HAS_NEXT(dsodesc)) {
1337 MAGIC_DSODESC_PREV(MAGIC_DSODESC_NEXT(dsodesc)) =
1338 MAGIC_DSODESC_PREV(dsodesc);
1340 else {
1341 _magic_last_dsodesc = MAGIC_DSODESC_PREV(dsodesc);
1343 if (MAGIC_DSODESC_HAS_PREV(dsodesc)) {
1344 MAGIC_DSODESC_NEXT(MAGIC_DSODESC_PREV(dsodesc)) =
1345 MAGIC_DSODESC_NEXT(dsodesc);
1347 else {
1348 _magic_first_dsodesc = MAGIC_DSODESC_NEXT(dsodesc);
1350 MAGIC_DSODESC_NEXT(dsodesc) = NULL;
1351 MAGIC_DSODESC_PREV(dsodesc) = NULL;
1352 _magic_dsodescs_num--;
1353 if (_magic_dsodescs_num == 0) {
1354 assert(!_magic_first_dsodesc && !_magic_last_dsodesc);
1356 else {
1357 assert(_magic_first_dsodesc && _magic_last_dsodesc);
1361 * Unmap the memory area that contained the dsentries and dfunctions
1362 * of this descriptor.
1364 ret = munmap(dsodesc->lib.alloc_address, dsodesc->lib.alloc_size);
1365 assert(ret == 0 && "Unable to unmap DSODESC memory segment!");
1367 return 0; /* no more references, descriptor is gone. */
1370 /*===========================================================================*
1371 * magic_alloc *
1372 *===========================================================================*/
1373 PUBLIC void *magic_alloc(__MA_ARGS__ void *ptr, size_t size, int flags)
1375 int ret;
1376 void *data_ptr;
1377 struct _magic_dsentry *dsentry;
1379 if(ptr == NULL) {
1380 return NULL;
1382 data_ptr = MAGIC_PTR_TO_DATA(ptr);
1383 dsentry = MAGIC_PTR_TO_DSENTRY(ptr);
1384 /* Catch pool allocations and update the name & flags */
1385 if (MAGIC_MEMPOOL_MGMT_IS_ACTIVE() && !(flags & MAGIC_STATE_MEMBLOCK)) {
1386 flags |= MAGIC_STATE_MEMPOOL;
1387 name = MAGIC_MEMPOOL_GET_NAME();
1389 ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, name, parent_name);
1390 MAGIC_MEM_PRINTF("magic_alloc: ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, NULL, NULL) <-> %d = magic_create_dsentry(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, NULL, NULL)\n", ret, (unsigned) dsentry, (unsigned) data_ptr, type, size, flags);
1391 if(ret < 0) {
1392 return MAGIC_MEM_FAILED;
1395 /* this way we skip the memory pool blocks -they are not real allocations and should not be logged */
1396 if (!(flags & MAGIC_STATE_MEMBLOCK)) {
1397 MAGIC_MEM_DEBUG_ALLOC(ptr, (MAGIC_SIZE_TO_REAL(size)));
1400 #if DEBUG
1401 MAGIC_MEM_PRINTF("magic_alloc: magic_create_dsentry created sentry: ");
1402 MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
1403 MAGIC_MEM_PRINTF("\n");
1404 #endif
1406 MAGIC_MEM_PRINTF("magic_alloc: return 0x%08x\n", (unsigned) data_ptr);
1408 return data_ptr;
1411 /*===========================================================================*
1412 * magic_malloc_positioned *
1413 *===========================================================================*/
1414 PUBLIC void *magic_malloc_positioned(__MA_ARGS__ size_t size, void *ptr)
1416 void *data_ptr;
1417 int dsentry_flags = MAGIC_STATE_HEAP;
1419 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1420 assert(!_magic_vars->fake_malloc);
1421 do {
1422 return magic_calloc(__MA_VALUES__ size, 1);
1423 } while(0);
1424 #endif
1426 MAGIC_MEM_WRAPPER_BEGIN();
1428 if(size > 0) {
1429 if (!ptr || !_magic_vars->fake_malloc) {
1431 * Check the external callback first.
1433 if (magic_mem_heap_alloc_cb)
1434 ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP), name, parent_name);
1436 if (!ptr)
1437 ptr = malloc(MAGIC_SIZE_TO_REAL(size) + magic_asr_get_padding_size(MAGIC_STATE_HEAP));
1438 MAGIC_MEM_PRINTF("magic_malloc: ptr = malloc(size) <-> 0x%08x = malloc(%d)\n", (unsigned) ptr, MAGIC_SIZE_TO_REAL(size));
1440 data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags);
1441 if (data_ptr == MAGIC_MEM_FAILED) {
1443 * XXX: This doesn't seem likely to happen. However, if it does,
1444 * we need to distinguish between regular malloc() memory
1445 * and super-objects. See llvm/shared/libst/include/heap.h for
1446 * more information.
1448 free(ptr);
1449 data_ptr = NULL;
1450 errno = ENOMEM;
1452 magic_heap_end = ((char *)sbrk(0)) - 1;
1454 else {
1455 data_ptr = NULL;
1458 MAGIC_MEM_WRAPPER_END();
1460 return data_ptr;
1463 /*===========================================================================*
1464 * magic_malloc *
1465 *===========================================================================*/
1466 PUBLIC void *magic_malloc(__MA_ARGS__ size_t size)
1468 return magic_malloc_positioned(__MA_VALUES__ size, NULL);
1471 /*===========================================================================*
1472 * magic_calloc *
1473 *===========================================================================*/
1474 PUBLIC void *magic_calloc(__MA_ARGS__ size_t nmemb, size_t size)
1476 void *ptr = NULL, *data_ptr;
1477 size_t real_size;
1478 int dsentry_flags = MAGIC_STATE_HEAP;
1480 MAGIC_MEM_WRAPPER_BEGIN();
1482 if(size > 0) {
1483 real_size = MAGIC_SIZE_TO_REAL(size*nmemb);
1485 * Check the external callback first.
1487 if (magic_mem_heap_alloc_cb)
1488 ptr = magic_mem_heap_alloc_cb(real_size + magic_asr_get_padding_size(MAGIC_STATE_HEAP), name, parent_name);
1490 if (!ptr)
1491 ptr = calloc(real_size + magic_asr_get_padding_size(MAGIC_STATE_HEAP), 1);
1492 MAGIC_MEM_PRINTF("magic_calloc: ptr = calloc(nmemb, size) <-> 0x%08x = calloc(%d, %d)\n", (unsigned) ptr, nmemb, real_size);
1493 data_ptr = magic_alloc(__MA_VALUES__ ptr, size*nmemb, dsentry_flags);
1494 if(data_ptr == MAGIC_MEM_FAILED) {
1496 * XXX: This doesn't seem likely to happen. However, if it does,
1497 * we need to distinguish between regular malloc() memory
1498 * and super-objects. See llvm/shared/libst/include/heap.h for
1499 * more information.
1501 free(ptr);
1502 data_ptr = NULL;
1503 errno = ENOMEM;
1505 magic_heap_end = ((char*)sbrk(0))-1;
1507 else {
1508 data_ptr = NULL;
1511 MAGIC_MEM_WRAPPER_END();
1513 return data_ptr;
1516 /*===========================================================================*
1517 * magic_free *
1518 *===========================================================================*/
1519 PUBLIC void magic_free(__MD_ARGS__ void *data_ptr)
1521 void *ptr;
1522 int ret;
1524 MAGIC_MEM_WRAPPER_BEGIN();
1526 if(data_ptr) {
1527 ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1529 /* Check for legitimate non-indexed chunks of memory and skip. */
1530 if((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS)
1531 && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) {
1532 MAGIC_MEM_WRAPPER_END();
1533 free(data_ptr);
1534 return;
1537 MAGIC_MEM_PRINTF("magic_free: magic_free(0x%08x) / free(0x%08x)\n", (unsigned) data_ptr, (unsigned) ptr);
1538 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_HEAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1540 if(magic_allow_dead_dsentries) {
1541 ret = magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_DSENTRY_MSTATE_DEAD);
1542 assert(ret == 0 && "Bad free!");
1544 else {
1545 MAGIC_DSENTRY_LOCK();
1546 magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL);
1547 ret = magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr));
1548 assert(ret == 0 && "Bad free!");
1549 MAGIC_DSENTRY_UNLOCK();
1553 MAGIC_MEM_WRAPPER_END();
1556 /*===========================================================================*
1557 * magic_realloc *
1558 *===========================================================================*/
1559 PUBLIC void *magic_realloc(__MA_ARGS__ void *data_ptr, size_t size)
1561 void *ptr, *new_ptr, *new_data_ptr;
1562 size_t old_size;
1564 if(!data_ptr) {
1565 return magic_malloc(__MA_VALUES__ size);
1567 if(size == 0) {
1568 magic_free(__MD_VALUES_DEFAULT__ data_ptr);
1569 return NULL;
1572 ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1573 new_data_ptr = magic_malloc(__MA_VALUES__ size);
1574 if(!new_data_ptr) {
1575 return NULL;
1577 new_ptr = MAGIC_PTR_FROM_DATA(new_data_ptr);
1578 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_HEAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1579 MAGIC_MEM_PRINTF("magic_realloc: ptr = realloc(ptr, size) <-> 0x%08x = realloc(0x%08x, %d)\n", (unsigned) new_ptr, (unsigned) ptr, MAGIC_SIZE_TO_REAL(size));
1581 old_size = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr))->type->size;
1582 memcpy(new_data_ptr, data_ptr, old_size < size ? old_size : size);
1583 magic_free(__MD_VALUES_DEFAULT__ data_ptr);
1585 return new_data_ptr;
1588 /*===========================================================================*
1589 * magic_posix_memalign *
1590 *===========================================================================*/
1591 PUBLIC int magic_posix_memalign(__MA_ARGS__ void **memptr, size_t alignment, size_t size)
1593 int ret = 0;
1594 void *ptr = NULL, *data_ptr;
1595 int dsentry_flags = MAGIC_STATE_HEAP;
1597 MAGIC_MEM_WRAPPER_BEGIN();
1599 if(size > 0) {
1601 * Check the external callback first.
1603 if (magic_mem_heap_alloc_cb)
1604 ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size), name, parent_name);
1606 if (!ptr)
1607 ret = posix_memalign(&ptr, alignment, MAGIC_SIZE_TO_REAL(size));
1608 MAGIC_MEM_PRINTF("magic_posix_memalign: ret = posix_memalign(ptr, alignment, size) <-> %d = posix_memalign(%p, %d, %d)\n", ret, ptr, alignment, MAGIC_SIZE_TO_REAL(size));
1609 if(ret == 0) {
1610 data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags);
1611 if(data_ptr == MAGIC_MEM_FAILED) {
1613 * XXX: This doesn't seem likely to happen. However, if it does,
1614 * we need to distinguish between regular malloc() memory
1615 * and super-objects. See llvm/shared/libst/include/heap.h for
1616 * more information.
1618 free(ptr);
1619 ret = ENOMEM;
1621 else {
1622 *memptr = data_ptr;
1623 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1624 memset(data_ptr, 0, size);
1625 #endif
1627 magic_heap_end = ((char*)sbrk(0))-1;
1630 else {
1631 ret = EINVAL;
1634 MAGIC_MEM_WRAPPER_END();
1636 return ret;
1639 #ifndef __MINIX
1640 /*===========================================================================*
1641 * magic_valloc *
1642 *===========================================================================*/
1643 PUBLIC void *magic_valloc(__MA_ARGS__ size_t size)
1645 return magic_memalign(__MA_VALUES__ MAGIC_PAGE_SIZE, size);
1648 /*===========================================================================*
1649 * magic_memalign *
1650 *===========================================================================*/
1651 PUBLIC void *magic_memalign(__MA_ARGS__ size_t boundary, size_t size)
1653 void *ptr;
1654 int ret = magic_posix_memalign(__MA_VALUES__ &ptr, boundary, size);
1655 if(ret != 0) {
1656 return NULL;
1658 return ptr;
1661 #endif
1663 /*===========================================================================*
1664 * magic_mmap_positioned *
1665 *===========================================================================*/
1666 PUBLIC void *magic_mmap_positioned(__MA_ARGS__ void *start, size_t length, int prot, int flags,
1667 int fd, off_t offset, struct _magic_dsentry *cached_dsentry)
1669 void *ptr, *data_ptr, *aligned_start, *aligned_ptr;
1670 void *new_ptr, *new_start;
1671 int dsentry_flags = MAGIC_STATE_MAP;
1672 size_t alloc_length;
1673 size_t page_size = MAGIC_PAGE_SIZE;
1674 int padding_type, padding_size;
1675 static THREAD_LOCAL int magic_is_first_mmap = 1;
1677 MAGIC_MEM_WRAPPER_BEGIN();
1679 if (flags & MAP_FIXED) {
1680 /* Allow safe overmapping. */
1681 struct _magic_sentry *sentry = magic_sentry_lookup_by_range(start, NULL);
1682 if (sentry && sentry == magic_sentry_lookup_by_range((char*)start+length-1, NULL))
1683 return mmap(start, length, prot, flags, fd, offset);
1685 assert(!(flags & MAP_FIXED) && "MAP_FIXED may override existing mapping, currently not implemented!");
1686 if (length > 0) {
1687 if (magic_is_first_mmap) {
1688 magic_is_first_mmap = 0;
1689 padding_type = MAGIC_STATE_MAP | MAGIC_ASR_FLAG_INIT;
1690 } else {
1691 padding_type = MAGIC_STATE_MAP;
1693 padding_size = start ? 0 : magic_asr_get_padding_size(padding_type);
1695 assert(MAGIC_SIZE_TO_REAL(length) <= page_size + length);
1696 aligned_start = start ? ((char *)start) - page_size : NULL;
1697 alloc_length = length + (length % page_size == 0 ? 0 : page_size - (length % page_size));
1698 #if 0
1699 if (_magic_vars->do_skip_mmap) {
1700 ptr = cached_dsentry ? ((char *)cached_dsentry) - (padding_size + page_size - MAGIC_SIZE_TO_REAL(0)) : NULL;
1701 } else
1702 #endif
1703 if (!(flags & MAP_ANONYMOUS) && !(flags & MAP_SHARED) && ((prot & magic_mmap_dsentry_header_prot) == magic_mmap_dsentry_header_prot)) {
1704 ptr = mmap(aligned_start, page_size + alloc_length + padding_size, prot, flags, fd, offset);
1706 else {
1707 /* Preallocate memory for metadata + data. */
1708 ptr = mmap(aligned_start, page_size + alloc_length + padding_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE | (flags & MAP_FIXED), -1, 0);
1710 /* Remap the data part the way the caller wants us to. */
1711 if (ptr != MAP_FAILED) {
1712 new_start = ((char *)ptr) + page_size;
1713 new_ptr = mmap(new_start, length, prot, flags | MAP_FIXED, fd, offset);
1714 if (new_ptr == MAP_FAILED) {
1715 munmap(ptr, page_size + alloc_length + padding_size);
1716 ptr = MAP_FAILED;
1720 aligned_ptr = ptr;
1721 MAGIC_MEM_PRINTF("magic_mmap: ptr = mmap(start, length, prot, flags, fd, offset) <-> 0x%08x = mmap(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) aligned_ptr, aligned_start, page_size + length, prot, flags, fd, offset);
1722 if (ptr != MAP_FAILED) {
1723 ptr = ((char *)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
1725 else {
1726 ptr = NULL;
1728 if (flags & MAP_SHARED)
1729 dsentry_flags |= MAGIC_STATE_SHM;
1730 data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags);
1731 if (data_ptr == MAGIC_MEM_FAILED) {
1732 munmap(aligned_ptr, page_size + alloc_length + padding_size);
1733 data_ptr = NULL;
1735 if (!data_ptr) {
1736 errno = ENOMEM;
1737 data_ptr = MAP_FAILED;
1738 } else {
1739 assert(data_ptr == (char *)aligned_ptr + page_size);
1740 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags;
1741 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot;
1742 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->ext = (void *) padding_size;
1745 else {
1746 data_ptr = MAP_FAILED;
1747 errno = EINVAL;
1750 MAGIC_MEM_WRAPPER_END();
1752 return data_ptr;
1755 /*===========================================================================*
1756 * magic_mmap *
1757 *===========================================================================*/
1758 PUBLIC void *magic_mmap(__MA_ARGS__ void *start, size_t length, int prot, int flags,
1759 int fd, off_t offset)
1761 return magic_mmap_positioned(__MA_VALUES__ start, length, prot, flags, fd, offset, NULL);
1764 /*===========================================================================*
1765 * magic_munmap *
1766 *===========================================================================*/
1767 PUBLIC int magic_munmap(__MD_ARGS__ void *data_ptr, size_t length)
1769 int ret;
1770 void *ptr, *aligned_ptr;
1771 struct _magic_sentry *sentry;
1772 size_t alloc_length, old_size;
1773 size_t page_size = MAGIC_PAGE_SIZE;
1775 MAGIC_MEM_WRAPPER_BEGIN();
1777 if(data_ptr) {
1778 ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1780 /* Check for legitimate non-indexed chunks of memory and skip. */
1781 if((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS)
1782 && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) {
1783 MAGIC_MEM_WRAPPER_END();
1784 return munmap(data_ptr, length);
1787 sentry = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr));
1788 aligned_ptr = ((char*)data_ptr) - page_size;
1789 MAGIC_MEM_PRINTF("magic_munmap: magic_munmap(0x%08x, %d) / unmap(0x%08x, %d)\n", (unsigned) data_ptr, length, (unsigned) aligned_ptr, page_size+length);
1790 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_MAP) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1791 old_size = MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr))->type->size;
1792 alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size));
1794 if(alloc_length != old_size) {
1795 assert(alloc_length >= old_size && "Partial unmapping not supported!");
1796 ret = -1;
1797 errno = EINVAL;
1799 else {
1800 if(magic_allow_dead_dsentries) {
1801 ret = magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_DSENTRY_MSTATE_DEAD);
1802 assert(ret == 0 && "Bad munmap!");
1804 else {
1805 MAGIC_DSENTRY_LOCK();
1806 magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL);
1807 ret = magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr));
1808 assert(ret == 0 && "Bad munmap!");
1809 MAGIC_DSENTRY_UNLOCK();
1813 else {
1814 ret = -1;
1815 errno = EINVAL;
1818 MAGIC_MEM_WRAPPER_END();
1820 return ret;
1823 /*===========================================================================*
1824 * magic_brk *
1825 *===========================================================================*/
1826 PUBLIC int magic_brk(__MA_ARGS__ void *addr)
1828 void *ptr;
1829 void *break_addr;
1830 int ret;
1832 MAGIC_MEM_PRINTF("magic_brk: Warning: somebody calling magic_brk()!");
1833 MAGIC_MEM_WRAPPER_LBLOCK( break_addr = sbrk(0); );
1834 if(addr >= break_addr) {
1835 ptr = magic_sbrk(__MA_VALUES__ (char*)addr - (char*)break_addr);
1836 ret = (ptr == (void*) -1 ? -1 : 0);
1837 if(ret == -1) {
1838 errno = ENOMEM;
1841 else {
1842 magic_free(__MD_VALUES_DEFAULT__ addr);
1843 ret = 0;
1846 return ret;
1849 /*===========================================================================*
1850 * magic_sbrk *
1851 *===========================================================================*/
1852 PUBLIC void *magic_sbrk(__MA_ARGS__ intptr_t increment)
1854 void *ptr;
1856 if(increment == 0) {
1857 MAGIC_MEM_WRAPPER_LBLOCK( ptr = sbrk(0); );
1859 else {
1860 MAGIC_MEM_PRINTF("magic_sbrk: Warning: somebody calling magic_sbrk(), resorting to magic_malloc()!");
1861 ptr = magic_malloc(__MA_VALUES__ increment);
1864 return ptr;
1867 #ifndef __MINIX
1868 /*===========================================================================*
1869 * magic_shmat *
1870 *===========================================================================*/
1871 PUBLIC void *magic_shmat(__MA_ARGS__ int shmid, const void *shmaddr, int shmflg)
1873 void *ptr, *data_ptr, *aligned_shmaddr, *aligned_ptr;
1874 void *new_ptr, *new_shmaddr;
1875 size_t size;
1876 struct shmid_ds buf;
1877 int ret, flags;
1878 size_t page_size = MAGIC_PAGE_SIZE;
1880 MAGIC_MEM_WRAPPER_BEGIN();
1882 assert(!(shmflg & SHM_REMAP) && "Linux-specific SHM_REMAP not supported!");
1883 ret = shmctl(shmid, IPC_STAT, &buf);
1884 if (ret == -1) {
1885 MAGIC_MEM_WRAPPER_END();
1886 return NULL;
1888 size = buf.shm_segsz;
1889 if (size > 0) {
1890 assert(size % page_size == 0);
1891 assert(MAGIC_SIZE_TO_REAL(size) <= size + page_size);
1892 if (shmaddr && (shmflg & SHM_RND)) {
1893 unsigned long shmlba = SHMLBA;
1894 shmflg &= ~SHM_RND;
1895 shmaddr = (void *) ((((unsigned long)shmaddr) / shmlba) * shmlba);
1898 /* Preallocate memory for metadata + data. */
1899 aligned_shmaddr = shmaddr ? ((char *)shmaddr) - page_size : NULL;
1900 flags = MAP_ANONYMOUS | MAP_PRIVATE | (aligned_shmaddr ? MAP_FIXED : 0);
1901 ptr = mmap(aligned_shmaddr, page_size + size, magic_mmap_dsentry_header_prot, flags, -1, 0);
1903 /* Remap the data part the way the caller wants us to. */
1904 if (ptr != MAP_FAILED) {
1905 new_shmaddr = ((char *)ptr) + page_size;
1906 munmap(new_shmaddr, size);
1907 new_ptr = shmat(shmid, new_shmaddr, shmflg);
1908 if(new_ptr == (void *) -1) {
1909 munmap(ptr, page_size);
1910 ptr = MAP_FAILED;
1913 aligned_ptr = ptr;
1914 MAGIC_MEM_PRINTF("magic_shmat: ptr = shmat(shmid, shmaddr, shmflg) <-> 0x%08x = shmat(%d, 0x%08x, 0x%08x)\n", (unsigned) aligned_ptr, shmid, aligned_shmaddr, shmflg);
1915 if (ptr != MAP_FAILED) {
1916 ptr = ((char *)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
1918 else {
1919 ptr = NULL;
1921 data_ptr = magic_alloc(__MA_VALUES__ ptr, size, MAGIC_STATE_SHM | MAGIC_STATE_DETACHED);
1922 if (data_ptr == MAGIC_MEM_FAILED) {
1923 munmap(aligned_ptr, page_size);
1924 munmap(new_ptr, size);
1925 data_ptr = (void *) -1;
1926 errno = ENOMEM;
1928 else {
1929 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_shmat_flags = shmflg;
1930 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_shmat_shmid = shmid;
1933 else {
1934 data_ptr = (void *) -1;
1935 errno = EINVAL;
1938 MAGIC_MEM_WRAPPER_END();
1940 return data_ptr;
1943 /*===========================================================================*
1944 * magic_shmdt *
1945 *===========================================================================*/
1946 PUBLIC int magic_shmdt(__MD_ARGS__ const void *data_ptr)
1948 int ret;
1949 void *ptr, *aligned_ptr;
1950 size_t page_size = MAGIC_PAGE_SIZE;
1952 MAGIC_MEM_WRAPPER_LBEGIN();
1954 if (data_ptr) {
1955 ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1957 /* Check for legitimate non-indexed chunks of memory and skip. */
1958 if ((!magic_libcommon_active || !MAGIC_USE_DYN_MEM_WRAPPERS)
1959 && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr))) {
1960 MAGIC_MEM_WRAPPER_LEND();
1961 return shmdt(data_ptr);
1964 aligned_ptr = ((char*)data_ptr) - page_size;
1965 MAGIC_MEM_PRINTF("magic_shmdt: magic_shmdt(0x%08x) / shmdt(0x%08x)\n", (unsigned) data_ptr, (unsigned) aligned_ptr);
1966 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), MAGIC_STATE_SHM) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1967 ret = shmdt(data_ptr);
1968 if (ret == 0) {
1969 magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr), NULL);
1970 munmap(aligned_ptr, page_size);
1973 else {
1974 ret = -1;
1975 errno = EINVAL;
1978 MAGIC_MEM_WRAPPER_LEND();
1980 return ret;
1983 /*===========================================================================*
1984 * magic_mmap64 *
1985 *===========================================================================*/
1986 PUBLIC void *magic_mmap64(__MA_ARGS__ void *start, size_t length, int prot, int flags,
1987 int fd, off_t pgoffset)
1989 void *ptr, *data_ptr, *aligned_start, *aligned_ptr;
1990 void *new_ptr, *new_start;
1991 int dsentry_flags = MAGIC_STATE_MAP;
1992 size_t alloc_length;
1993 size_t page_size = MAGIC_PAGE_SIZE;
1995 MAGIC_MEM_WRAPPER_BEGIN();
1997 if (flags & MAP_FIXED) {
1998 /* Allow safe overmapping. */
1999 struct _magic_sentry *sentry = magic_sentry_lookup_by_range(start, NULL);
2000 if (sentry && sentry == magic_sentry_lookup_by_range((char*)start+length-1, NULL))
2001 return mmap64(start, length, prot, flags, fd, pgoffset);
2003 assert(!(flags & MAP_FIXED) && "MAP_FIXED may override existing mapping, currently not implemented!");
2004 if(length > 0) {
2005 assert(MAGIC_SIZE_TO_REAL(length) <= page_size+length);
2006 aligned_start = start ? ((char*)start) - page_size : NULL;
2007 alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size));
2008 if((flags & MAP_ANONYMOUS) && !(flags & MAP_SHARED) && ((prot & magic_mmap_dsentry_header_prot) == magic_mmap_dsentry_header_prot)) {
2009 ptr = mmap64(aligned_start, page_size+length, prot, flags, fd, pgoffset);
2011 else {
2012 /* Preallocate memory for metadata + data. */
2013 ptr = mmap64(aligned_start, page_size+alloc_length, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS|MAP_PRIVATE|(flags & MAP_FIXED), -1, 0);
2015 /* Remap the data part the way the caller wants us to. */
2016 if(ptr != MAP_FAILED) {
2017 new_start = ((char*)ptr) + page_size;
2018 new_ptr = mmap64(new_start, length, prot, flags|MAP_FIXED, fd, pgoffset);
2019 if(new_ptr == MAP_FAILED) {
2020 munmap(ptr, page_size+alloc_length);
2021 ptr = MAP_FAILED;
2025 aligned_ptr = ptr;
2026 MAGIC_MEM_PRINTF("magic_mmap64: ptr = mmap64(start, length, prot, flags, fd, pgoffset) <-> 0x%08x = mmap64(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) aligned_ptr, aligned_start, page_size+length, prot, flags, fd, pgoffset);
2027 if(ptr != MAP_FAILED) {
2028 ptr = ((char*)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
2030 else {
2031 ptr = NULL;
2033 if (flags & MAP_SHARED)
2034 dsentry_flags |= MAGIC_STATE_SHM;
2035 data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags);
2036 if(data_ptr == MAGIC_MEM_FAILED) {
2037 munmap(aligned_ptr, page_size+length);
2038 data_ptr = NULL;
2039 errno = ENOMEM;
2041 if(!data_ptr) {
2042 errno = ENOMEM;
2043 data_ptr = MAP_FAILED;
2044 } else {
2045 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags;
2046 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot;
2049 else {
2050 data_ptr = MAP_FAILED;
2051 errno = EINVAL;
2054 MAGIC_MEM_WRAPPER_END();
2056 return data_ptr;
2059 #else
2060 /*===========================================================================*
2061 * magic_vm_map_cacheblock *
2062 *===========================================================================*/
2063 PUBLIC void *magic_vm_map_cacheblock(__MA_ARGS__ dev_t dev, off_t dev_offset,
2064 ino_t ino, off_t ino_offset, u32_t *flags, int length)
2066 void *ptr, *data_ptr, *aligned_ptr;
2067 int dsentry_flags = MAGIC_STATE_MAP;
2068 size_t alloc_length;
2069 size_t page_size = MAGIC_PAGE_SIZE;
2071 MAGIC_MEM_WRAPPER_BEGIN();
2073 if(length > 0) {
2074 assert(MAGIC_SIZE_TO_REAL(length) <= page_size+length);
2075 alloc_length = length + (length % page_size == 0 ? 0 : page_size-(length % page_size));
2076 data_ptr = vm_map_cacheblock(dev, dev_offset, ino, ino_offset, flags, length);
2077 if (data_ptr != MAP_FAILED) {
2078 ptr = mmap((char *)data_ptr-page_size, page_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2079 MAGIC_MEM_PRINTF("vm_map_cacheblock: ptr = mmap(start, length, prot, flags, fd, offset) <-> 0x%08x = mmap(0x%08x, %d, 0x%08x, 0x%08x, %d, %d)\n", (unsigned) ptr, (char *)data_ptr-page_size, page_size, magic_mmap_dsentry_header_prot, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
2080 assert(ptr == (char *)data_ptr-page_size); /* Ensured by VM. */
2081 aligned_ptr = ptr;
2082 ptr = ((char*)ptr) + page_size - MAGIC_SIZE_TO_REAL(0);
2084 else {
2085 aligned_ptr = NULL;
2086 ptr = NULL;
2088 data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, dsentry_flags);
2089 if(data_ptr == MAGIC_MEM_FAILED) {
2090 munmap(aligned_ptr, page_size+length);
2091 data_ptr = NULL;
2093 if(!data_ptr) {
2094 data_ptr = MAP_FAILED;
2095 errno = ENOMEM;
2096 } else {
2097 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = MAP_ANONYMOUS | MAP_PRIVATE;
2098 MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = magic_mmap_dsentry_header_prot;
2101 else {
2102 data_ptr = MAP_FAILED;
2103 errno = EINVAL;
2106 MAGIC_MEM_WRAPPER_END();
2108 return data_ptr;
2111 /*===========================================================================*
2112 * magic_nested_mmap *
2113 *===========================================================================*/
2114 void *
2115 magic_nested_mmap(void *start, size_t length, int prot, int flags,
2116 int fd, off_t offset)
2118 void *ptr;
2119 int i;
2121 ptr = mmap(start, length, prot, flags, fd, offset);
2123 if (ptr != MAP_FAILED) {
2124 MAGIC_MEM_PRINTF("MAGIC: nested mmap (%p, %zu)\n", ptr,
2125 length);
2128 * Find a free entry. We do not expect the malloc code to have
2129 * more than two areas mapped at any time.
2131 for (i = 0; i < MAGIC_UNMAP_MEM_ENTRIES; i++)
2132 if (_magic_unmap_mem[i].length == 0)
2133 break;
2134 assert(i < MAGIC_UNMAP_MEM_ENTRIES);
2136 /* Store the mapping in this entry. */
2137 _magic_unmap_mem[i].start = ptr;
2138 _magic_unmap_mem[i].length = length;
2141 return ptr;
2144 /*===========================================================================*
2145 * magic_nested_munmap *
2146 *===========================================================================*/
2148 magic_nested_munmap(void *start, size_t length)
2150 int i, r;
2152 r = munmap(start, length);
2154 if (r == 0) {
2155 MAGIC_MEM_PRINTF("MAGIC: nested munmap (%p, %zu)\n", start,
2156 length);
2158 /* Find the corresponding entry. This must always succeed. */
2159 for (i = 0; i < MAGIC_UNMAP_MEM_ENTRIES; i++)
2160 if (_magic_unmap_mem[i].start == start &&
2161 _magic_unmap_mem[i].length == length)
2162 break;
2163 assert(i < MAGIC_UNMAP_MEM_ENTRIES);
2165 /* Clear the entry. */
2166 _magic_unmap_mem[i].start = NULL;
2167 _magic_unmap_mem[i].length = 0;
2170 return r;
2172 #endif