xref: /minix/minix/lib/libmagicrt/magic_mem.c (revision d2532d3d)
1 
2 #ifdef _FILE_OFFSET_BITS
3 #undef _FILE_OFFSET_BITS
4 #endif
5 #define _FILE_OFFSET_BITS 64
6 
7 #include <magic_mem.h>
8 #include <stdio.h>
9 #include <errno.h>
10 #include <stdarg.h>
11 #include <magic_asr.h>
12 
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
24 
25 #define DEBUG                           MAGIC_DEBUG_SET(0)
26 #define DEBUG_TYPE_SIZE_MISMATCH        MAGIC_DEBUG_SET(0)
27 
28 #if DEBUG
29 #define MAGIC_MEM_PRINTF _magic_printf
30 #else
31 #define MAGIC_MEM_PRINTF magic_null_printf
32 #endif
33 
34 /* CPU frequency (used for timestamp logging) */
35 PUBLIC double magic_cycles_per_ns = 0;
36 
37 /*
38  * External callbacks.
39  */
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;
43 
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];
48 
49 const char* const MAGIC_MEMPOOL_NAME_UNKNOWN = "_magic_mempool_unknown#";
50 const char* const MAGIC_MEMPOOL_NAME_DETACHED = "_magic_mempool_detached#";
51 
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;
55 
56 #define MAGIC_MEM_FAILED    ((void*) -1)
57 
58 #ifndef SHM_REMAP
59 #define SHM_REMAP 0
60 #endif
61 
62 EXTERN char **environ;
63 
64 PRIVATE magic_dsentry_cb_t magic_destroy_dsentry_ext_cb = NULL;
65 
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;
71 
72 PUBLIC int (*magic_real_posix_memalign)(void **memptr, size_t alignment, size_t size) = &posix_memalign;
73 
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
78 
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;
82 
83 PUBLIC int (*magic_real_brk)(void *addr) = &brk;
84 PUBLIC void *(*magic_real_sbrk)(intptr_t increment) = &sbrk;
85 
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;
89 
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
96 
97 /* Use magic_real* functions in the rest of the file. */
98 #include <magic_real_mem.h>
99 
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)
110 
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
129 
130 /*===========================================================================*
131  *                       magic_mempool_alloc_id                              *
132  *===========================================================================*/
133 MAGIC_MACRO_FUNC short magic_mempool_alloc_id(void)
134 {
135     short i, id = -1;
136 
137     MAGIC_MPDESC_LOCK();
138 
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;
145         }
146     }
147 
148     MAGIC_MPDESC_UNLOCK();
149 
150     assert((id > 0) && (id <= MAGIC_MAX_MEMPOOLS) && "Ran out of memory pool descriptors!");
151 
152     return id;
153 }
154 
155 /*===========================================================================*
156  *                       magic_mempool_create_begin                          *
157  *===========================================================================*/
158 MAGIC_HOOK void magic_mempool_create_begin(__MDEBUG_ARGS__)
159 {
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());
164 }
165 
166 /*===========================================================================*
167  *                       magic_mempool_create_end                            *
168  *===========================================================================*/
169 MAGIC_HOOK void magic_mempool_create_end(void* addr, int indirection)
170 {
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();
176 }
177 
178 /*===========================================================================*
179  *                       magic_mempool_lookup_by_addr                        *
180  *===========================================================================*/
181 MAGIC_MACRO_FUNC short magic_mempool_lookup_by_addr(void* addr)
182 {
183     short i, id = MAGIC_MEMPOOL_ID_UNKNOWN;
184 
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;
190             }
191         }
192     }
193 
194     return id;
195 }
196 
197 /*===========================================================================*
198  *                       magic_mempool_reset                                 *
199  *===========================================================================*/
200 MAGIC_MACRO_FUNC void magic_mempool_reset(const char* mempool_name, int reset_name)
201 {
202     struct _magic_dsentry *prev_dsentry, *dsentry, *block_dsentry;
203     struct _magic_sentry* sentry;
204 
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!");
213             }
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!");
218             }
219             MAGIC_MEM_DEBUG_RESET((char*)dsentry);
220         }
221     );
222 
223     MAGIC_DSENTRY_UNLOCK();
224 }
225 
226 /*===========================================================================*
227  *                       magic_mempool_destroy_begin                         *
228  *===========================================================================*/
229 MAGIC_HOOK void magic_mempool_destroy_begin(void* addr, int memory_reuse)
230 {
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);
235     }
236 }
237 
238 /*===========================================================================*
239  *                       magic_mempool_destroy_end                           *
240  *===========================================================================*/
241 MAGIC_HOOK void magic_mempool_destroy_end()
242 {
243     MAGIC_MPDESC_LOCK();
244 
245     MAGIC_MPDESC_FREE(&_magic_mpdescs[MAGIC_MEMPOOL_GET_ID() - 1]);
246 
247     MAGIC_MPDESC_UNLOCK();
248 
249     magic_mempool_mgmt_end();
250 }
251 
252 /*===========================================================================*
253  *                       magic_mempool_mgmt_begin                            *
254  *===========================================================================*/
255 MAGIC_HOOK void  magic_mempool_mgmt_begin(void* addr)
256 {
257     short id;
258 
259     MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
260     assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
261 
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;
267     }
268     MAGIC_MEMPOOL_SET_ID(id);
269 }
270 
271 /*===========================================================================*
272  *                       magic_mempool_mgmt_end                              *
273  *===========================================================================*/
274 MAGIC_HOOK void magic_mempool_mgmt_end()
275 {
276     MAGIC_MEMPOOL_SET_ID(MAGIC_MEMPOOL_ID_UNKNOWN);
277     assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
278     MAGIC_MEMPOOL_MGMT_UNSET_ACTIVE();
279 }
280 
281 /*===========================================================================*
282  *                       magic_mempool_reset_begin                           *
283  *===========================================================================*/
284 MAGIC_HOOK void magic_mempool_reset_begin(void* addr)
285 {
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);
292         }
293     }
294 }
295 
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)
301 {
302     const char *old_name, *ret;
303 
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!");
314             }
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!");
317         }
318     }
319 }
320 
321 /*===========================================================================*
322  *                       magic_mempool_dsentry_update                        *
323  *===========================================================================*/
324 MAGIC_MACRO_FUNC void magic_mempool_dsentry_update(struct _magic_dsentry* dsentry,
325 	const char* name)
326 {
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);
342     }
343 }
344 
345 /*===========================================================================*
346  *                       mempool_block_alloc_template                        *
347  *===========================================================================*/
348 MAGIC_FUNC void *mempool_block_alloc_template(void* addr, size_t size)
349 {
350     return NULL;
351 }
352 
353 /*===========================================================================*
354  *                       magic_mempool_block_alloc_template                  *
355  *===========================================================================*/
356 PUBLIC void *magic_mempool_block_alloc_template(__MA_ARGS__ void* addr, size_t size)
357 {
358     void *ptr, *data_ptr;
359     struct _magic_sentry* mempool_sentry;
360     struct _magic_dsentry* mempool_dsentry, *next_block_dsentry;
361 
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());
381                 }
382             }
383 
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);
386 
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());
391             }
392             MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr)))->name = mempool_sentry->name;
393 
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);
400 
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());
404             }
405         }
406     }
407     else {
408         /* Some applications return a valid pointer even if size is 0... */
409         data_ptr = mempool_block_alloc_template(addr, size);
410     }
411     magic_mempool_mgmt_end();
412 
413     return data_ptr;
414 }
415 
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)
422 {
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;
429 
430     struct _magic_dsentry *saved_next = dsentry->next;
431     int save_linkage = ((flags & MAGIC_STATE_HEAP) && _magic_vars->fake_malloc);
432 
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();
438     }
439 
440     if (!type) {
441         type = MAGIC_VOID_TYPE;
442     }
443     type_size = type->size;
444     assert(size > 0);
445 
446     memcpy(dsentry, &magic_default_dsentry, sizeof(struct _magic_dsentry));
447 
448     /* Catch variable-sized struct allocation. */
449     if (magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) {
450         is_varsized = 1;
451     }
452 
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;
463     }
464 
465     if (size == type_size && !is_varsized) {
466         sentry->type = type;
467     }
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;
475     }
476 
477     sentry->flags |= flags;
478     sentry->address = data_ptr;
479 
480     if (name) {
481         sentry->name = name;
482     }
483     if (parent_name) {
484         dsentry->parent_name = parent_name;
485     }
486     sentry->id = MAGIC_FAA(&_magic_sentries_next_id, 1);
487     assert(_magic_sentries_next_id < MAGIC_ID_MAX);
488 
489     /*
490      * TODO: Also add per-callsite index to handle the following:
491      * for (;;) { p = malloc(); }
492      */
493     if (magic_mem_create_dsentry_site_id) {
494         MAGIC_MEM_WRAPPER_BEGIN();
495         /*
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.
499          */
500         dsentry->site_id = util_stacktrace_hash_skip((char *)"("MAGIC_PREFIX_STR);
501         MAGIC_MEM_WRAPPER_END();
502     }
503 
504     if (save_linkage) {
505         dsentry->next = saved_next;
506         return 0;
507     }
508 
509     /* Add the new dsentry before the first dsentry atomically.
510      * Skip memblock dsentries to make pool reset/destruction faster.
511      */
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);
517     }
518 
519 #if MAGIC_DSENTRY_ALLOW_PREV
520     next_dsentry = MAGIC_DSENTRY_NEXT(dsentry);
521     if (next_dsentry) {
522         MAGIC_DSENTRY_PREV(next_dsentry) = dsentry;
523     }
524     MAGIC_DSENTRY_PREV(dsentry) = NULL;
525 #endif
526 
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);
533     }
534     magic_update_dsentry_ranges = 1;
535 
536     if (magic_mem_create_dsentry_cb)
537         magic_mem_create_dsentry_cb(dsentry);
538 
539     return 0;
540 }
541 
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)
548 {
549     struct _magic_obdsentry *obdsentry = NULL;
550     int i, ret;
551 
552     /* Check name. */
553     if(!name || !strcmp(name, "")) {
554         return NULL;
555     }
556     else if(strlen(name) >= MAGIC_MAX_OBDSENTRY_NAME_LEN) {
557         return NULL;
558     }
559 
560     /* Check parent name. */
561     if(!parent_name || !strcmp(parent_name, "")) {
562         parent_name = MAGIC_OBDSENTRY_DEFAULT_PARENT_NAME;
563     }
564     if(strlen(parent_name) >= MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN) {
565         return NULL;
566     }
567 
568     MAGIC_MEM_WRAPPER_LBEGIN();
569 
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;
575         }
576     }
577     if(!obdsentry) {
578         MAGIC_MEM_WRAPPER_LEND();
579         return NULL;
580     }
581 
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);
588 
589     MAGIC_MEM_WRAPPER_LEND();
590 
591     if(ret < 0) {
592         return NULL;
593     }
594     assert(!MAGIC_OBDSENTRY_IS_FREE(obdsentry));
595 
596     return obdsentry;
597 }
598 
599 /*===========================================================================*
600  *                       magic_update_dsentry_state                          *
601  *===========================================================================*/
602 PUBLIC int magic_update_dsentry_state(struct _magic_dsentry *dsentry,
603     unsigned long state)
604 {
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;
610 
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;
618             }
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);
623             }
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;
633             }
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();
643                 }
644             }
645         break;
646         default:
647             ret = MAGIC_EINVAL;
648         break;
649     }
650 
651     return ret;
652 }
653 
654 /*===========================================================================*
655  *                            magic_free_dsentry                             *
656  *===========================================================================*/
657 PRIVATE int magic_free_dsentry(struct _magic_dsentry *dsentry)
658 {
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);
667 
668     if (!from_wrapper) {
669         MAGIC_MEM_WRAPPER_BEGIN();
670     }
671 
672     if (magic_mem_heap_free_cb) {
673         ret = magic_mem_heap_free_cb(dsentry);
674         if (ret != MAGIC_ENOENT)
675             return ret;
676 
677         /*
678          * If the callback returned MAGIC_ENOENT, fallback to
679          * the default behavior.
680          */
681         ret = 0;
682     }
683 
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;
698 
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);
703             }
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);
713             }
714             if (ret != 0) {
715                 ret = MAGIC_EBADENT;
716             }
717         break;
718         default:
719             ret = MAGIC_EBADENT;
720         break;
721     }
722     if (!from_wrapper) {
723         MAGIC_MEM_WRAPPER_END();
724     }
725 
726     return ret;
727 }
728 
729 /*===========================================================================*
730  *                    magic_free_dead_dsentries                              *
731  *===========================================================================*/
732 PUBLIC void magic_free_dead_dsentries()
733 {
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;
739 
740     MAGIC_DSENTRY_LOCK();
741 
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--;
749         }
750     }
751 
752     if(!next_first_dsentry || num_dead_dsentries == 0) {
753         MAGIC_DSENTRY_UNLOCK();
754         return;
755     }
756 
757     MAGIC_MEM_PRINTF("magic_free_dead_dsentries: Freeing %d dead dsentries...\n", num_dead_dsentries);
758 
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");
774                 }
775                 num_dead_dsentries--;
776                 dead_dsentries_left = 1;
777                 break;
778             }
779         );
780     } while(dead_dsentries_left && num_dead_dsentries > 0);
781     assert(num_dead_dsentries == 0);
782 
783     MAGIC_DSENTRY_UNLOCK();
784 }
785 
786 /*===========================================================================*
787  *                      magic_destroy_dsentry                                *
788  *===========================================================================*/
789 PUBLIC void magic_destroy_dsentry(struct _magic_dsentry *dsentry,
790     struct _magic_dsentry *prev_dsentry)
791 {
792     struct _magic_dsentry *next_dsentry, *next_mempool_dsentry, *prev_mempool_dsentry = NULL;
793     int dsentry_destroyed, mempool_dsentry_destroyed;
794 
795     if(magic_destroy_dsentry_ext_cb && MAGIC_DSENTRY_HAS_EXT(dsentry)) {
796         magic_destroy_dsentry_ext_cb(dsentry);
797     }
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!");
804                 }
805             }
806             if(prev_mempool_dsentry) {
807                 MAGIC_DSENTRY_NEXT_MEMPOOL(prev_mempool_dsentry) = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry);
808                 mempool_dsentry_destroyed = 1;
809             }
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);
815             }
816         } while(!mempool_dsentry_destroyed);
817         MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry) = NULL;
818     }
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!");
827             }
828         }
829 #endif
830 
831         if(prev_dsentry) {
832             MAGIC_DSENTRY_NEXT(prev_dsentry) = MAGIC_DSENTRY_NEXT(dsentry);
833             dsentry_destroyed = 1;
834         }
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);
840         }
841     } while(!dsentry_destroyed);
842 
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);
847     }
848     MAGIC_DSENTRY_PREV(dsentry) = NULL;
849 #endif
850 
851     dsentry->magic_number = MAGIC_DSENTRY_MNUM_NULL;
852     MAGIC_DSENTRY_NEXT(dsentry) = NULL;
853 }
854 
855 /*===========================================================================*
856  *                       magic_destroy_obdsentry_by_addr                     *
857  *===========================================================================*/
858 PUBLIC int magic_destroy_obdsentry_by_addr(void *data_ptr)
859 {
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);
864 
865     MAGIC_MEM_WRAPPER_LBEGIN();
866 
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;
872     }
873     dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
874     obdsentry = MAGIC_OBDSENTRY_FROM_DSENTRY(dsentry);
875 
876     /* Destroy it and free obdsentry slot. */
877     magic_destroy_dsentry(dsentry, NULL);
878     MAGIC_OBDSENTRY_FREE(obdsentry);
879 
880     MAGIC_MEM_WRAPPER_LEND();
881 
882     return 0;
883 }
884 
885 /*===========================================================================*
886  *                       magic_destroy_dsentry_set_ext_cb                    *
887  *===========================================================================*/
888 PUBLIC void magic_destroy_dsentry_set_ext_cb(const magic_dsentry_cb_t cb)
889 {
890     magic_destroy_dsentry_ext_cb = cb;
891 }
892 
893 /*===========================================================================*
894  *                            magic_update_dsentry                           *
895  *===========================================================================*/
896 PUBLIC int magic_update_dsentry(void* addr, struct _magic_type *type)
897 {
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;
903 
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;
909 
910             /* Catch variable-sized struct allocation. */
911             if(magic_type_alloc_needs_varsized_array(type, size, &num_vsa_elements)) {
912                 is_varsized = 1;
913             }
914 
915             if(size % type_size != 0 && !is_varsized) {
916                 return MAGIC_EBADENT;
917             }
918             if(size == type_size && !is_varsized) {
919                 sentry->type = type;
920             }
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;
928             }
929             return 0;
930         }
931     );
932     MAGIC_DSENTRY_UNLOCK();
933 
934     return MAGIC_ENOENT;
935 }
936 
937 /*===========================================================================*
938  *                              magic_stack_init                             *
939  *===========================================================================*/
940 PUBLIC void magic_stack_init()
941 {
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;
949 
950     assert(!_magic_first_stack_dsentry && !_magic_last_stack_dsentry);
951 
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
958          */
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.
963          */
964         ptr--;
965     }
966 
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--;
977         }
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;
984     }
985     size = (size_t)initial_stack_bottom - (size_t)initial_stack_top + 1;
986 
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);
992 }
993 
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, */ ...)
1000 {
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;
1009 
1010     assert(num_dsentries > 0);
1011 
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);
1036 
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.
1040             */
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;
1048             }
1049             if (!max_data_ptr || max_data_ptr < (char *) data_ptr) {
1050                 max_data_ptr = (char *) data_ptr;
1051             }
1052         }
1053     }
1054 
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);
1058     }
1059 #endif
1060 
1061     _magic_last_stack_dsentry = dsentry;
1062     MAGIC_DSENTRY_UNLOCK();
1063 
1064     va_end(va);
1065 }
1066 
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, */ ...)
1073 {
1074     int i;
1075     struct _magic_dsentry *dsentry;
1076     va_list va;
1077 
1078     assert(num_dsentries > 0);
1079 
1080     MAGIC_MEM_WRAPPER_LBEGIN();
1081 
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);
1087     }
1088     va_end(va);
1089 
1090     MAGIC_MEM_WRAPPER_LEND();
1091 }
1092 
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)
1099 {
1100     struct _magic_function *function = MAGIC_DFUNCTION_TO_FUNCTION(dfunction);
1101 
1102     if(!type) {
1103         type = MAGIC_VOID_TYPE;
1104     }
1105 
1106     memcpy(dfunction, &magic_default_dfunction, sizeof(struct _magic_dfunction));
1107 
1108     assert(!(type->flags & MAGIC_TYPE_DYNAMIC) && "bad type!");
1109 
1110     function->type = type;
1111     function->flags |= flags;
1112     function->address = data_ptr;
1113     if(name) {
1114         function->name = name;
1115     }
1116     if(parent_name) {
1117         dfunction->parent_name = parent_name;
1118     }
1119     function->id = MAGIC_FAA(&_magic_functions_next_id, 1);
1120     assert(_magic_functions_next_id < MAGIC_ID_MAX);
1121 
1122     if(_magic_first_dfunction) {
1123         assert(_magic_last_dfunction);
1124         MAGIC_DFUNCTION_NEXT(_magic_last_dfunction) = dfunction;
1125     }
1126     else {
1127         assert(!_magic_last_dfunction);
1128         assert(_magic_dfunctions_num == 0);
1129         _magic_first_dfunction = dfunction;
1130     }
1131     MAGIC_DFUNCTION_PREV(dfunction) = _magic_last_dfunction;
1132     MAGIC_DFUNCTION_NEXT(dfunction) = NULL;
1133     _magic_last_dfunction = dfunction;
1134     _magic_dfunctions_num++;
1135 
1136     assert(magic_check_dfunction(dfunction, 0) && "Bad magic dfunction created!");
1137     magic_update_dfunction_ranges = 1;
1138 
1139     return 0;
1140 }
1141 
1142 /*===========================================================================*
1143  *                         magic_destroy_dfunction                           *
1144  *===========================================================================*/
1145 PUBLIC void magic_destroy_dfunction(struct _magic_dfunction *dfunction)
1146 {
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);
1150     }
1151     else {
1152         _magic_last_dfunction = MAGIC_DFUNCTION_PREV(dfunction);
1153     }
1154     if(MAGIC_DFUNCTION_HAS_PREV(dfunction)) {
1155         MAGIC_DFUNCTION_NEXT(MAGIC_DFUNCTION_PREV(dfunction)) = MAGIC_DFUNCTION_NEXT(dfunction);
1156     }
1157     else {
1158         _magic_first_dfunction = MAGIC_DFUNCTION_NEXT(dfunction);
1159     }
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);
1165     }
1166     else {
1167         assert(_magic_first_dfunction && _magic_last_dfunction);
1168     }
1169 }
1170 
1171 /*===========================================================================*
1172  *                          magic_create_sodesc                              *
1173  *===========================================================================*/
1174 PUBLIC int magic_create_sodesc(struct _magic_sodesc *sodesc)
1175 {
1176     if(_magic_first_sodesc) {
1177         assert(_magic_last_sodesc);
1178         MAGIC_SODESC_NEXT(_magic_last_sodesc) = sodesc;
1179     }
1180     else {
1181         assert(!_magic_last_sodesc);
1182         assert(_magic_sodescs_num == 0);
1183         _magic_first_sodesc = sodesc;
1184     }
1185     MAGIC_SODESC_PREV(sodesc) = _magic_last_sodesc;
1186     MAGIC_SODESC_NEXT(sodesc) = NULL;
1187     _magic_last_sodesc = sodesc;
1188     _magic_sodescs_num++;
1189 
1190     return 0;
1191 }
1192 
1193 /*===========================================================================*
1194  *                          magic_destroy_sodesc                             *
1195  *===========================================================================*/
1196 PUBLIC int magic_destroy_sodesc(struct _magic_sodesc *sodesc)
1197 {
1198     /*
1199      * NB!: This function requires the calling thread to already
1200      * hold the DSENTRY and DFUNCTION locks.
1201      */
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;
1207 
1208     /*
1209      * Time to destroy all the dsentries and dfunctions
1210      * linked to the descriptor.
1211      */
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;
1219     );
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;
1227     );
1228     if(last_dfunction) magic_destroy_dfunction(last_dfunction);
1229 
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);
1234     }
1235     else {
1236         _magic_last_sodesc = MAGIC_SODESC_PREV(sodesc);
1237     }
1238     if (MAGIC_SODESC_HAS_PREV(sodesc)) {
1239         MAGIC_SODESC_NEXT(MAGIC_SODESC_PREV(sodesc)) =
1240             MAGIC_SODESC_NEXT(sodesc);
1241     }
1242     else {
1243         _magic_first_sodesc = MAGIC_SODESC_NEXT(sodesc);
1244     }
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);
1250     }
1251     else {
1252         assert(_magic_first_sodesc && _magic_last_sodesc);
1253     }
1254 
1255     /*
1256      * Unmap the memory area that contained the dsentries and dfunctions
1257      * of this descriptor.
1258      */
1259     ret = munmap(sodesc->lib.alloc_address, sodesc->lib.alloc_size);
1260     assert(ret == 0 && "Unable to unmap SODESC memory segment!");
1261 
1262     return 0;
1263 }
1264 
1265 /*===========================================================================*
1266  *                          magic_create_dsodesc                             *
1267  *===========================================================================*/
1268 PUBLIC int magic_create_dsodesc(struct _magic_dsodesc *dsodesc)
1269 {
1270     /*
1271      * NB!: This function requires the calling thread to already
1272      * hold the DSODESC lock.
1273      */
1274     if (_magic_first_dsodesc) {
1275         assert(_magic_last_dsodesc);
1276         MAGIC_DSODESC_NEXT(_magic_last_dsodesc) = dsodesc;
1277     }
1278     else {
1279         assert(!_magic_last_dsodesc);
1280         assert(_magic_dsodescs_num == 0);
1281         _magic_first_dsodesc = dsodesc;
1282     }
1283     MAGIC_DSODESC_PREV(dsodesc) = _magic_last_dsodesc;
1284     MAGIC_DSODESC_NEXT(dsodesc) = NULL;
1285     _magic_last_dsodesc = dsodesc;
1286     _magic_dsodescs_num++;
1287 
1288     return 0;
1289 }
1290 
1291 /*===========================================================================*
1292  *                          magic_destroy_dsodesc                            *
1293  *===========================================================================*/
1294 PUBLIC int magic_destroy_dsodesc(struct _magic_dsodesc *dsodesc)
1295 {
1296     /*
1297      * NB!: This function requires the calling thread to already
1298      * hold the DSENTRY, DFUNCTION and DSODESC locks.
1299      */
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;
1305 
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;
1310     }
1311 
1312     /*
1313      * Time to destroy all the dsentries and dfunctions
1314      * linked to the descriptor.
1315      */
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;
1323     );
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;
1331     );
1332     if (last_dfunction)
1333         magic_destroy_dfunction(last_dfunction);
1334 
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);
1339     }
1340     else {
1341         _magic_last_dsodesc = MAGIC_DSODESC_PREV(dsodesc);
1342     }
1343     if (MAGIC_DSODESC_HAS_PREV(dsodesc)) {
1344         MAGIC_DSODESC_NEXT(MAGIC_DSODESC_PREV(dsodesc)) =
1345             MAGIC_DSODESC_NEXT(dsodesc);
1346     }
1347     else {
1348         _magic_first_dsodesc = MAGIC_DSODESC_NEXT(dsodesc);
1349     }
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);
1355     }
1356     else {
1357         assert(_magic_first_dsodesc && _magic_last_dsodesc);
1358     }
1359 
1360     /*
1361      * Unmap the memory area that contained the dsentries and dfunctions
1362      * of this descriptor.
1363      */
1364     ret = munmap(dsodesc->lib.alloc_address, dsodesc->lib.alloc_size);
1365     assert(ret == 0 && "Unable to unmap DSODESC memory segment!");
1366 
1367     return 0; /* no more references, descriptor is gone. */
1368 }
1369 
1370 /*===========================================================================*
1371  *                              magic_alloc                                  *
1372  *===========================================================================*/
1373 PUBLIC void *magic_alloc(__MA_ARGS__ void *ptr, size_t size, int flags)
1374 {
1375     int ret;
1376     void *data_ptr;
1377     struct _magic_dsentry *dsentry;
1378 
1379     if(ptr == NULL) {
1380         return NULL;
1381     }
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();
1388     }
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;
1393     }
1394 
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)));
1398     }
1399 
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
1405 
1406     MAGIC_MEM_PRINTF("magic_alloc: return 0x%08x\n", (unsigned) data_ptr);
1407 
1408     return data_ptr;
1409 }
1410 
1411 /*===========================================================================*
1412  *                           magic_malloc_positioned                         *
1413  *===========================================================================*/
1414 PUBLIC void *magic_malloc_positioned(__MA_ARGS__ size_t size, void *ptr)
1415 {
1416     void *data_ptr;
1417     int dsentry_flags = MAGIC_STATE_HEAP;
1418 
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
1425 
1426     MAGIC_MEM_WRAPPER_BEGIN();
1427 
1428     if(size > 0) {
1429         if (!ptr || !_magic_vars->fake_malloc) {
1430             /*
1431              * Check the external callback first.
1432              */
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);
1435 
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));
1439         }
1440         data_ptr = magic_alloc(__MA_VALUES__ ptr, size, dsentry_flags);
1441         if (data_ptr == MAGIC_MEM_FAILED) {
1442             /*
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.
1447              */
1448             free(ptr);
1449             data_ptr = NULL;
1450             errno = ENOMEM;
1451         }
1452         magic_heap_end = ((char *)sbrk(0)) - 1;
1453     }
1454     else {
1455         data_ptr = NULL;
1456     }
1457 
1458     MAGIC_MEM_WRAPPER_END();
1459 
1460     return data_ptr;
1461 }
1462 
1463 /*===========================================================================*
1464  *                               magic_malloc                                *
1465  *===========================================================================*/
1466 PUBLIC void *magic_malloc(__MA_ARGS__ size_t size)
1467 {
1468     return magic_malloc_positioned(__MA_VALUES__ size, NULL);
1469 }
1470 
1471 /*===========================================================================*
1472  *                               magic_calloc                                *
1473  *===========================================================================*/
1474 PUBLIC void *magic_calloc(__MA_ARGS__ size_t nmemb, size_t size)
1475 {
1476     void *ptr = NULL, *data_ptr;
1477     size_t real_size;
1478     int dsentry_flags = MAGIC_STATE_HEAP;
1479 
1480     MAGIC_MEM_WRAPPER_BEGIN();
1481 
1482     if(size > 0) {
1483         real_size = MAGIC_SIZE_TO_REAL(size*nmemb);
1484         /*
1485          * Check the external callback first.
1486          */
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);
1489 
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) {
1495             /*
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.
1500              */
1501             free(ptr);
1502             data_ptr = NULL;
1503             errno = ENOMEM;
1504         }
1505         magic_heap_end = ((char*)sbrk(0))-1;
1506     }
1507     else {
1508         data_ptr = NULL;
1509     }
1510 
1511     MAGIC_MEM_WRAPPER_END();
1512 
1513     return data_ptr;
1514 }
1515 
1516 /*===========================================================================*
1517  *                                magic_free                                 *
1518  *===========================================================================*/
1519 PUBLIC void magic_free(__MD_ARGS__ void *data_ptr)
1520 {
1521     void *ptr;
1522     int ret;
1523 
1524     MAGIC_MEM_WRAPPER_BEGIN();
1525 
1526     if(data_ptr) {
1527         ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1528 
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;
1535         }
1536 
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?");
1539 
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!");
1543         }
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();
1550         }
1551     }
1552 
1553     MAGIC_MEM_WRAPPER_END();
1554 }
1555 
1556 /*===========================================================================*
1557  *                              magic_realloc                                *
1558  *===========================================================================*/
1559 PUBLIC void *magic_realloc(__MA_ARGS__ void *data_ptr, size_t size)
1560 {
1561     void *ptr, *new_ptr, *new_data_ptr;
1562     size_t old_size;
1563 
1564     if(!data_ptr) {
1565         return magic_malloc(__MA_VALUES__ size);
1566     }
1567     if(size == 0) {
1568         magic_free(__MD_VALUES_DEFAULT__ data_ptr);
1569         return NULL;
1570     }
1571 
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;
1576     }
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));
1580 
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);
1584 
1585     return new_data_ptr;
1586 }
1587 
1588 /*===========================================================================*
1589  *                           magic_posix_memalign                            *
1590  *===========================================================================*/
1591 PUBLIC int magic_posix_memalign(__MA_ARGS__ void **memptr, size_t alignment, size_t size)
1592 {
1593     int ret = 0;
1594     void *ptr = NULL, *data_ptr;
1595     int dsentry_flags = MAGIC_STATE_HEAP;
1596 
1597     MAGIC_MEM_WRAPPER_BEGIN();
1598 
1599     if(size > 0) {
1600         /*
1601          * Check the external callback first.
1602          */
1603         if (magic_mem_heap_alloc_cb)
1604             ptr = magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size), name, parent_name);
1605 
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) {
1612                 /*
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.
1617                  */
1618                 free(ptr);
1619                 ret = ENOMEM;
1620             }
1621             else {
1622                 *memptr = data_ptr;
1623 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1624                 memset(data_ptr, 0, size);
1625 #endif
1626             }
1627             magic_heap_end = ((char*)sbrk(0))-1;
1628         }
1629     }
1630     else {
1631         ret = EINVAL;
1632     }
1633 
1634     MAGIC_MEM_WRAPPER_END();
1635 
1636     return ret;
1637 }
1638 
1639 #ifndef __MINIX
1640 /*===========================================================================*
1641  *                              magic_valloc                                 *
1642  *===========================================================================*/
1643 PUBLIC void *magic_valloc(__MA_ARGS__ size_t size)
1644 {
1645     return magic_memalign(__MA_VALUES__ MAGIC_PAGE_SIZE, size);
1646 }
1647 
1648 /*===========================================================================*
1649  *                              magic_memalign                               *
1650  *===========================================================================*/
1651 PUBLIC void *magic_memalign(__MA_ARGS__ size_t boundary, size_t size)
1652 {
1653     void *ptr;
1654     int ret = magic_posix_memalign(__MA_VALUES__ &ptr, boundary, size);
1655     if(ret != 0) {
1656         return NULL;
1657     }
1658     return ptr;
1659 }
1660 
1661 #endif
1662 
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)
1668 {
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;
1676 
1677     MAGIC_MEM_WRAPPER_BEGIN();
1678 
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);
1684     }
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;
1692         }
1693         padding_size = start ? 0 : magic_asr_get_padding_size(padding_type);
1694 
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);
1705         }
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);
1709 
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;
1717                 }
1718             }
1719         }
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);
1724         }
1725         else {
1726             ptr = NULL;
1727         }
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;
1734         }
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;
1743         }
1744     }
1745     else {
1746         data_ptr = MAP_FAILED;
1747         errno = EINVAL;
1748     }
1749 
1750     MAGIC_MEM_WRAPPER_END();
1751 
1752     return data_ptr;
1753 }
1754 
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)
1760 {
1761     return magic_mmap_positioned(__MA_VALUES__ start, length, prot, flags, fd, offset, NULL);
1762 }
1763 
1764 /*===========================================================================*
1765  *                              magic_munmap                                 *
1766  *===========================================================================*/
1767 PUBLIC int magic_munmap(__MD_ARGS__ void *data_ptr, size_t length)
1768 {
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;
1774 
1775     MAGIC_MEM_WRAPPER_BEGIN();
1776 
1777     if(data_ptr) {
1778         ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1779 
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);
1785         }
1786 
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));
1793 
1794         if(alloc_length != old_size) {
1795             assert(alloc_length >= old_size && "Partial unmapping not supported!");
1796             ret = -1;
1797             errno = EINVAL;
1798         }
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!");
1803             }
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();
1810             }
1811         }
1812     }
1813     else {
1814         ret = -1;
1815         errno = EINVAL;
1816     }
1817 
1818     MAGIC_MEM_WRAPPER_END();
1819 
1820     return ret;
1821 }
1822 
1823 /*===========================================================================*
1824  *                               magic_brk                                   *
1825  *===========================================================================*/
1826 PUBLIC int magic_brk(__MA_ARGS__ void *addr)
1827 {
1828     void *ptr;
1829     void *break_addr;
1830     int ret;
1831 
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;
1839         }
1840     }
1841     else {
1842         magic_free(__MD_VALUES_DEFAULT__ addr);
1843         ret = 0;
1844     }
1845 
1846     return ret;
1847 }
1848 
1849 /*===========================================================================*
1850  *                              magic_sbrk                                   *
1851  *===========================================================================*/
1852 PUBLIC void *magic_sbrk(__MA_ARGS__ intptr_t increment)
1853 {
1854     void *ptr;
1855 
1856     if(increment == 0) {
1857         MAGIC_MEM_WRAPPER_LBLOCK( ptr = sbrk(0); );
1858     }
1859     else {
1860         MAGIC_MEM_PRINTF("magic_sbrk: Warning: somebody calling magic_sbrk(), resorting to magic_malloc()!");
1861         ptr = magic_malloc(__MA_VALUES__ increment);
1862     }
1863 
1864     return ptr;
1865 }
1866 
1867 #ifndef __MINIX
1868 /*===========================================================================*
1869  *                             magic_shmat                                   *
1870  *===========================================================================*/
1871 PUBLIC void *magic_shmat(__MA_ARGS__ int shmid, const void *shmaddr, int shmflg)
1872 {
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;
1879 
1880     MAGIC_MEM_WRAPPER_BEGIN();
1881 
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;
1887     }
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);
1896         }
1897 
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);
1902 
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;
1911             }
1912         }
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);
1917         }
1918         else {
1919             ptr = NULL;
1920         }
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;
1927         }
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;
1931         }
1932     }
1933     else {
1934         data_ptr = (void *) -1;
1935         errno = EINVAL;
1936     }
1937 
1938     MAGIC_MEM_WRAPPER_END();
1939 
1940     return data_ptr;
1941 }
1942 
1943 /*===========================================================================*
1944  *                             magic_shmdt                                   *
1945  *===========================================================================*/
1946 PUBLIC int magic_shmdt(__MD_ARGS__ const void *data_ptr)
1947 {
1948     int ret;
1949     void *ptr, *aligned_ptr;
1950     size_t page_size = MAGIC_PAGE_SIZE;
1951 
1952     MAGIC_MEM_WRAPPER_LBEGIN();
1953 
1954     if (data_ptr) {
1955         ptr = MAGIC_PTR_FROM_DATA(data_ptr);
1956 
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);
1962         }
1963 
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);
1971         }
1972     }
1973     else {
1974         ret = -1;
1975         errno = EINVAL;
1976     }
1977 
1978     MAGIC_MEM_WRAPPER_LEND();
1979 
1980     return ret;
1981 }
1982 
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)
1988 {
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;
1994 
1995     MAGIC_MEM_WRAPPER_BEGIN();
1996 
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);
2002     }
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);
2010         }
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);
2014 
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;
2022                 }
2023             }
2024         }
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);
2029         }
2030         else {
2031             ptr = NULL;
2032         }
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;
2040         }
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;
2047         }
2048     }
2049     else {
2050         data_ptr = MAP_FAILED;
2051         errno = EINVAL;
2052     }
2053 
2054     MAGIC_MEM_WRAPPER_END();
2055 
2056     return data_ptr;
2057 }
2058 
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)
2065 {
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;
2070 
2071     MAGIC_MEM_WRAPPER_BEGIN();
2072 
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);
2083         }
2084         else {
2085             aligned_ptr = NULL;
2086             ptr = NULL;
2087         }
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;
2092         }
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;
2099         }
2100     }
2101     else {
2102         data_ptr = MAP_FAILED;
2103         errno = EINVAL;
2104     }
2105 
2106     MAGIC_MEM_WRAPPER_END();
2107 
2108     return data_ptr;
2109 }
2110 
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)
2117 {
2118 	void *ptr;
2119 	int i;
2120 
2121 	ptr = mmap(start, length, prot, flags, fd, offset);
2122 
2123 	if (ptr != MAP_FAILED) {
2124 		MAGIC_MEM_PRINTF("MAGIC: nested mmap (%p, %zu)\n", ptr,
2125 		    length);
2126 
2127 		/*
2128 		 * Find a free entry.  We do not expect the malloc code to have
2129 		 * more than two areas mapped at any time.
2130 		 */
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);
2135 
2136 		/* Store the mapping in this entry. */
2137 		_magic_unmap_mem[i].start = ptr;
2138 		_magic_unmap_mem[i].length = length;
2139 	}
2140 
2141 	return ptr;
2142 }
2143 
2144 /*===========================================================================*
2145  *				magic_nested_munmap			     *
2146  *===========================================================================*/
2147 int
2148 magic_nested_munmap(void *start, size_t length)
2149 {
2150 	int i, r;
2151 
2152 	r = munmap(start, length);
2153 
2154 	if (r == 0) {
2155 		MAGIC_MEM_PRINTF("MAGIC: nested munmap (%p, %zu)\n", start,
2156 		    length);
2157 
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);
2164 
2165 		/* Clear the entry. */
2166 		_magic_unmap_mem[i].start = NULL;
2167 		_magic_unmap_mem[i].length = 0;
2168 	}
2169 
2170 	return r;
2171 }
2172 #endif
2173 
2174