2 #ifdef _FILE_OFFSET_BITS
3 #undef _FILE_OFFSET_BITS
5 #define _FILE_OFFSET_BITS 64
11 #include <magic_asr.h>
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
20 #include <common/util/stacktrace.h>
21 #include <common/util/time.h>
22 #include <common/util/string.h>
25 #define DEBUG MAGIC_DEBUG_SET(0)
26 #define DEBUG_TYPE_SIZE_MISMATCH MAGIC_DEBUG_SET(0)
29 #define MAGIC_MEM_PRINTF _magic_printf
31 #define MAGIC_MEM_PRINTF magic_null_printf
34 /* CPU frequency (used for timestamp logging) */
35 PUBLIC
double magic_cycles_per_ns
= 0;
40 PUBLIC magic_mem_heap_alloc_cb_t magic_mem_heap_alloc_cb
= NULL
;
41 PUBLIC magic_mem_create_dsentry_cb_t magic_mem_create_dsentry_cb
= NULL
;
42 PUBLIC magic_mem_heap_free_cb_t magic_mem_heap_free_cb
= NULL
;
44 PUBLIC
short magic_mem_create_dsentry_site_id
= 0;
45 PUBLIC THREAD_LOCAL
short magic_mem_wrapper_active
= 0;
46 PUBLIC THREAD_LOCAL
short magic_mempool_mgmt_active_level
= 0;
47 PUBLIC THREAD_LOCAL
short magic_mempool_ids
[MAGIC_MEMPOOL_MAX_FUNC_RECURSIONS
];
49 const char* const MAGIC_MEMPOOL_NAME_UNKNOWN
= "_magic_mempool_unknown#";
50 const char* const MAGIC_MEMPOOL_NAME_DETACHED
= "_magic_mempool_detached#";
52 __attribute__((weak
)) int magic_mempool_allow_reset
= 1;
53 __attribute__((weak
)) int magic_mempool_allow_reuse
= 1;
54 __attribute__((weak
)) int magic_mempool_allow_external_alloc
= 0;
56 #define MAGIC_MEM_FAILED ((void*) -1)
62 EXTERN
char **environ
;
64 PRIVATE magic_dsentry_cb_t magic_destroy_dsentry_ext_cb
= NULL
;
66 /* Magic real mem function definitions. */
67 PUBLIC
void *(*magic_real_malloc
)(size_t size
) = &malloc
;
68 PUBLIC
void *(*magic_real_calloc
)(size_t nmemb
, size_t size
) = &calloc
;
69 PUBLIC
void (*magic_real_free
)(void *ptr
) = &free
;
70 PUBLIC
void *(*magic_real_realloc
)(void *ptr
, size_t size
) = &realloc
;
72 PUBLIC
int (*magic_real_posix_memalign
)(void **memptr
, size_t alignment
, size_t size
) = &posix_memalign
;
75 PUBLIC
void *(*magic_real_valloc
)(size_t size
) = &valloc
;
76 PUBLIC
void *(*magic_real_memalign
)(size_t boundary
, size_t size
) = &memalign
;
79 PUBLIC
void *(*magic_real_mmap
)(void *start
, size_t length
, int prot
, int flags
,
80 int fd
, off_t offset
) = &mmap
;
81 PUBLIC
int (*magic_real_munmap
)(void *start
, size_t length
) = &munmap
;
83 PUBLIC
int (*magic_real_brk
)(void *addr
) = &brk
;
84 PUBLIC
void *(*magic_real_sbrk
)(intptr_t increment
) = &sbrk
;
87 PUBLIC
void *(*magic_real_shmat
)(int shmid
, const void *shmaddr
, int shmflg
) = &shmat
;
88 PUBLIC
int (*magic_real_shmdt
)(const void *shmaddr
) = &shmdt
;
90 PUBLIC
void *(*magic_real_mmap64
)(void *start
, size_t length
, int prot
, int flags
,
91 int fd
, off_t pgoffset
) = &mmap64
;
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
;
97 /* Use magic_real* functions in the rest of the file. */
98 #include <magic_real_mem.h>
100 /* Macros for memory usage logging. */
101 #if MAGIC_MEM_USAGE_OUTPUT_CTL
102 #define MAGIC_MEM_DEBUG_PREFIX "MEM_USAGE: "
103 #define TIMESTAMP_STR "%llu"
104 #define TIMESTAMP_ARG (util_time_tsc_read_ns(magic_cycles_per_ns))
105 #define MAGIC_MEM_DEBUG_EVENT(EVENT, FORMAT, ...) \
106 _magic_printf(MAGIC_MEM_DEBUG_PREFIX TIMESTAMP_STR " " #EVENT " " FORMAT "\n", TIMESTAMP_ARG, __VA_ARGS__)
107 #define MAGIC_MEM_DEBUG_EVENT_1(event, ptr) MAGIC_MEM_DEBUG_EVENT(event, "%u", (unsigned) ptr)
108 #define MAGIC_MEM_DEBUG_EVENT_2(event, ptr, type) MAGIC_MEM_DEBUG_EVENT(event, "%u %lu", (unsigned) ptr, type)
109 #define MAGIC_MEM_DEBUG_EVENT_3(event, ptr, type, size) MAGIC_MEM_DEBUG_EVENT(event, "%u %lu %d", (unsigned) ptr, type, size)
111 #if (MAGIC_MEM_USAGE_OUTPUT_CTL == 1)
112 /* use the hash of the name (extended with line number & file name) as dynamic type */
113 #define MAGIC_MEM_GET_DTYPE() util_strhash(0, name)
114 #elif (MAGIC_MEM_USAGE_OUTPUT_CTL == 2)
115 /* use the hash of the stacktrace as a dynamic type */
116 #define MAGIC_MEM_GET_DTYPE() util_stacktrace_hash()
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)
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)
130 /*===========================================================================*
131 * magic_mempool_alloc_id *
132 *===========================================================================*/
133 MAGIC_MACRO_FUNC
short magic_mempool_alloc_id(void)
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
]);
148 MAGIC_MPDESC_UNLOCK();
150 assert((id
> 0) && (id
<= MAGIC_MAX_MEMPOOLS
) && "Ran out of memory pool descriptors!");
155 /*===========================================================================*
156 * magic_mempool_create_begin *
157 *===========================================================================*/
158 MAGIC_HOOK
void magic_mempool_create_begin(__MDEBUG_ARGS__
)
160 MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
161 assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
162 MAGIC_MEMPOOL_SET_ID(magic_mempool_alloc_id());
163 MAGIC_MEMPOOL_SET_DTYPE(MAGIC_MEM_GET_DTYPE());
166 /*===========================================================================*
167 * magic_mempool_create_end *
168 *===========================================================================*/
169 MAGIC_HOOK
void magic_mempool_create_end(void* addr
, int indirection
)
172 pool
= (indirection
&& addr
) ? *((void**)addr
) : addr
;
173 assert(pool
&& "Cannot have a NULL pool pointer.");
174 _magic_mpdescs
[MAGIC_MEMPOOL_GET_ID() - 1].addr
= pool
;
175 magic_mempool_mgmt_end();
178 /*===========================================================================*
179 * magic_mempool_lookup_by_addr *
180 *===========================================================================*/
181 MAGIC_MACRO_FUNC
short magic_mempool_lookup_by_addr(void* addr
)
183 short i
, id
= MAGIC_MEMPOOL_ID_UNKNOWN
;
186 for(i
= 0; i
< MAGIC_MAX_MEMPOOLS
; i
++) {
187 if(_magic_mpdescs
[i
].addr
== addr
) {
197 /*===========================================================================*
198 * magic_mempool_reset *
199 *===========================================================================*/
200 MAGIC_MACRO_FUNC
void magic_mempool_reset(const char* mempool_name
, int reset_name
)
202 struct _magic_dsentry
*prev_dsentry
, *dsentry
, *block_dsentry
;
203 struct _magic_sentry
* sentry
;
205 MAGIC_DSENTRY_LOCK();
206 MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(_magic_first_mempool_dsentry
, prev_dsentry
, dsentry
, sentry
,
207 if (sentry
->name
== mempool_name
) {
208 block_dsentry
= MAGIC_DSENTRY_NEXT_MEMBLOCK(dsentry
);
209 if (block_dsentry
!= NULL
) {
210 struct _magic_dsentry
*tmp_block_dsentry
=
211 MAGIC_PCAS(&MAGIC_DSENTRY_NEXT_MEMBLOCK(dsentry
), block_dsentry
, NULL
);
212 assert(tmp_block_dsentry
== block_dsentry
&& "New blocks have been allocated from a reseted mempool!");
215 const char *tmp_name
=
216 MAGIC_PCAS(&sentry
->name
, mempool_name
, MAGIC_MEMPOOL_NAME_UNKNOWN
);
217 assert(tmp_name
== mempool_name
&& "The name of the mempool has changed while being reseted!");
219 MAGIC_MEM_DEBUG_RESET((char*)dsentry
);
223 MAGIC_DSENTRY_UNLOCK();
226 /*===========================================================================*
227 * magic_mempool_destroy_begin *
228 *===========================================================================*/
229 MAGIC_HOOK
void magic_mempool_destroy_begin(void* addr
, int memory_reuse
)
231 magic_mempool_mgmt_begin(addr
);
232 if (addr
&& memory_reuse
) {
233 assert(MAGIC_MEMPOOL_ID_IS_SET() && "Cannot destroy a pool with an unknown id.");
234 magic_mempool_reset(MAGIC_MEMPOOL_GET_NAME(), TRUE
);
238 /*===========================================================================*
239 * magic_mempool_destroy_end *
240 *===========================================================================*/
241 MAGIC_HOOK
void magic_mempool_destroy_end()
245 MAGIC_MPDESC_FREE(&_magic_mpdescs
[MAGIC_MEMPOOL_GET_ID() - 1]);
247 MAGIC_MPDESC_UNLOCK();
249 magic_mempool_mgmt_end();
252 /*===========================================================================*
253 * magic_mempool_mgmt_begin *
254 *===========================================================================*/
255 MAGIC_HOOK
void magic_mempool_mgmt_begin(void* addr
)
259 MAGIC_MEMPOOL_MGMT_SET_ACTIVE();
260 assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
262 id
= magic_mempool_lookup_by_addr(addr
);
263 /* For some reason, this mempool has not been registered yet, reserve a new slot in the mempool array. */
264 if (addr
&& (id
== MAGIC_MEMPOOL_ID_UNKNOWN
)) {
265 id
= magic_mempool_alloc_id();
266 _magic_mpdescs
[id
- 1].addr
= addr
;
268 MAGIC_MEMPOOL_SET_ID(id
);
271 /*===========================================================================*
272 * magic_mempool_mgmt_end *
273 *===========================================================================*/
274 MAGIC_HOOK
void magic_mempool_mgmt_end()
276 MAGIC_MEMPOOL_SET_ID(MAGIC_MEMPOOL_ID_UNKNOWN
);
277 assert(MAGIC_MEMPOOL_MGMT_IS_ACTIVE());
278 MAGIC_MEMPOOL_MGMT_UNSET_ACTIVE();
281 /*===========================================================================*
282 * magic_mempool_reset_begin *
283 *===========================================================================*/
284 MAGIC_HOOK
void magic_mempool_reset_begin(void* addr
)
286 magic_mempool_mgmt_begin(addr
);
287 /* skip reset when it has been disabled by the application. */
288 if (magic_mempool_allow_reset
) {
290 assert(MAGIC_MEMPOOL_ID_IS_SET() && "Cannot reset a pool with an unknown id.");
291 magic_mempool_reset(MAGIC_MEMPOOL_GET_NAME(), TRUE
);
296 /*===========================================================================*
297 * magic_mempool_dsentry_set_name *
298 *===========================================================================*/
299 MAGIC_MACRO_FUNC
void magic_mempool_dsentry_set_name(struct _magic_dsentry
* dsentry
,
302 const char *old_name
, *ret
;
304 if ((name
== MAGIC_MEMPOOL_NAME_UNKNOWN
) || (name
== MAGIC_MEMPOOL_NAME_DETACHED
)) {
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
);
309 old_name
= MAGIC_DSENTRY_TO_SENTRY(dsentry
)->name
;
310 if (old_name
!= name
) {
311 if (!strncmp(old_name
, MAGIC_MEMPOOL_NAME_PREFIX
, strlen(MAGIC_MEMPOOL_NAME_PREFIX
))) {
312 assert(((old_name
== MAGIC_MEMPOOL_NAME_UNKNOWN
) || (old_name
== MAGIC_MEMPOOL_NAME_DETACHED
))
313 && "Cannot overwrite an already existing valid memory pool name!");
315 ret
= MAGIC_CAS(&MAGIC_DSENTRY_TO_SENTRY(dsentry
)->name
, old_name
, name
);
316 assert((ret
== old_name
|| ret
== name
) && "Cannot overwrite an already existing valid memory pool name!");
321 /*===========================================================================*
322 * magic_mempool_dsentry_update *
323 *===========================================================================*/
324 MAGIC_MACRO_FUNC
void magic_mempool_dsentry_update(struct _magic_dsentry
* dsentry
,
327 struct _magic_sentry
* sentry
= MAGIC_DSENTRY_TO_SENTRY(dsentry
);
328 struct _magic_dsentry
* next_mempool_dsentry
;
330 /* set the magic state mempool flag atomically */
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. */
339 next_mempool_dsentry
= _magic_first_mempool_dsentry
;
340 MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry
) = next_mempool_dsentry
;
341 } while(MAGIC_CAS(&_magic_first_mempool_dsentry
, next_mempool_dsentry
, dsentry
) != next_mempool_dsentry
);
345 /*===========================================================================*
346 * mempool_block_alloc_template *
347 *===========================================================================*/
348 MAGIC_FUNC
void *mempool_block_alloc_template(void* addr
, size_t size
)
353 /*===========================================================================*
354 * magic_mempool_block_alloc_template *
355 *===========================================================================*/
356 PUBLIC
void *magic_mempool_block_alloc_template(__MA_ARGS__
void* addr
, size_t size
)
358 void *ptr
, *data_ptr
;
359 struct _magic_sentry
* mempool_sentry
;
360 struct _magic_dsentry
* mempool_dsentry
, *next_block_dsentry
;
362 magic_mempool_mgmt_begin(addr
);
363 /* don't set the memory wrapper flag, this function is supposed to allocate memory from a pool
364 and not using the standard allocators. it might also call other memory pool management functions */
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 */
375 /* lookup the pool buffer dsentry from which this block was allocated */
376 mempool_sentry
= magic_mempool_sentry_lookup_by_range(ptr
, NULL
);
377 if (!mempool_sentry
&& magic_mempool_allow_external_alloc
) {
378 mempool_sentry
= magic_sentry_lookup_by_range(ptr
, NULL
);
379 if (mempool_sentry
) {
380 magic_mempool_dsentry_update(MAGIC_DSENTRY_FROM_SENTRY(mempool_sentry
), MAGIC_MEMPOOL_GET_NAME());
384 assert(mempool_sentry
&& "XXX Mempool dsentry not found for this memblock dsentry: memory not allocated from a memory pool management function?");
385 mempool_dsentry
= MAGIC_DSENTRY_FROM_SENTRY(mempool_sentry
);
387 /* Reuse of buffers across pools - propagate the new pool name */
388 if (MAGIC_MEMPOOL_ID_IS_SET() && (mempool_sentry
->name
!= MAGIC_MEMPOOL_GET_NAME())) {
389 assert(magic_mempool_allow_reuse
&& "Pool memory reuse is disabled!");
390 magic_mempool_dsentry_set_name(mempool_dsentry
, MAGIC_MEMPOOL_GET_NAME());
392 MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr
)))->name
= mempool_sentry
->name
;
394 /* Add the new dsentry before the first block dsentry chained to the memory pool dsentry, atomically.
395 The list should be circular - the last block dsentry (first one added) points to the memory pool dsentry. */
397 next_block_dsentry
= MAGIC_DSENTRY_NEXT_MEMBLOCK(mempool_dsentry
);
398 MAGIC_DSENTRY_NEXT_MEMBLOCK(MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr
))) = next_block_dsentry
? next_block_dsentry
: mempool_dsentry
;
399 }while(MAGIC_CAS(&(MAGIC_DSENTRY_NEXT_MEMBLOCK(mempool_dsentry
)), next_block_dsentry
, MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr
))) != next_block_dsentry
);
401 /* First write to this pool buffer, potential reuse */
402 if (next_block_dsentry
== NULL
) {
403 MAGIC_MEM_DEBUG_REUSE((char*)mempool_dsentry
, MAGIC_MEMPOOL_GET_DTYPE());
408 /* Some applications return a valid pointer even if size is 0... */
409 data_ptr
= mempool_block_alloc_template(addr
, size
);
411 magic_mempool_mgmt_end();
416 /*===========================================================================*
417 * magic_create_dsentry *
418 *===========================================================================*/
419 PUBLIC
int magic_create_dsentry(struct _magic_dsentry
*dsentry
,
420 void *data_ptr
, struct _magic_type
*type
, size_t size
, int flags
,
421 const char *name
, const char *parent_name
)
423 /* This function does not require any dsentry locking. */
424 struct _magic_sentry
*sentry
= MAGIC_DSENTRY_TO_SENTRY(dsentry
);
425 struct _magic_dsentry
*next_dsentry
, *next_mempool_dsentry
;
428 int num_vsa_elements
= 0;
430 struct _magic_dsentry
*saved_next
= dsentry
->next
;
431 int save_linkage
= ((flags
& MAGIC_STATE_HEAP
) && _magic_vars
->fake_malloc
);
433 MAGIC_MEM_PRINTF("Dsentry created from stacktrace:\n");
434 if (MAGIC_MEM_PRINTF
!= magic_null_printf
) {
435 MAGIC_MEM_WRAPPER_BEGIN();
436 util_stacktrace_print_custom(MAGIC_MEM_PRINTF
);
437 MAGIC_MEM_WRAPPER_END();
441 type
= MAGIC_VOID_TYPE
;
443 type_size
= type
->size
;
446 memcpy(dsentry
, &magic_default_dsentry
, sizeof(struct _magic_dsentry
));
448 /* Catch variable-sized struct allocation. */
449 if (magic_type_alloc_needs_varsized_array(type
, size
, &num_vsa_elements
)) {
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
);
460 type
= MAGIC_VOID_TYPE
;
461 type_size
= type
->size
;
462 flags
|= MAGIC_STATE_TYPE_SIZE_MISMATCH
;
465 if (size
== type_size
&& !is_varsized
) {
469 struct _magic_type
*array_type
= &(dsentry
->type
);
470 MAGIC_TYPE_ARRAY_CREATE_FROM_SIZE(array_type
, type
,
471 MAGIC_DSENTRY_TO_TYPE_ARR(dsentry
), size
, num_vsa_elements
);
472 array_type
->id
= MAGIC_FAA(&_magic_types_next_id
, 1);
473 assert(_magic_types_next_id
< MAGIC_ID_MAX
);
474 sentry
->type
= array_type
;
477 sentry
->flags
|= flags
;
478 sentry
->address
= data_ptr
;
484 dsentry
->parent_name
= parent_name
;
486 sentry
->id
= MAGIC_FAA(&_magic_sentries_next_id
, 1);
487 assert(_magic_sentries_next_id
< MAGIC_ID_MAX
);
490 * TODO: Also add per-callsite index to handle the following:
491 * for (;;) { p = malloc(); }
493 if (magic_mem_create_dsentry_site_id
) {
494 MAGIC_MEM_WRAPPER_BEGIN();
496 * XXX: This is so damn ugly, but we don't want to include
497 * any magic_* functions in the stacktrace hash.
498 * This should probably be done in a much more elegant manner.
500 dsentry
->site_id
= util_stacktrace_hash_skip((char *)"("MAGIC_PREFIX_STR
);
501 MAGIC_MEM_WRAPPER_END();
505 dsentry
->next
= saved_next
;
509 /* Add the new dsentry before the first dsentry atomically.
510 * Skip memblock dsentries to make pool reset/destruction faster.
512 if (!MAGIC_STATE_FLAG(sentry
, MAGIC_STATE_MEMBLOCK
)) {
514 next_dsentry
= _magic_first_dsentry
;
515 MAGIC_DSENTRY_NEXT(dsentry
) = next_dsentry
;
516 } while(MAGIC_CAS(&_magic_first_dsentry
, next_dsentry
, dsentry
) != next_dsentry
);
519 #if MAGIC_DSENTRY_ALLOW_PREV
520 next_dsentry
= MAGIC_DSENTRY_NEXT(dsentry
);
522 MAGIC_DSENTRY_PREV(next_dsentry
) = dsentry
;
524 MAGIC_DSENTRY_PREV(dsentry
) = NULL
;
527 if (MAGIC_STATE_FLAG(sentry
, MAGIC_STATE_MEMPOOL
)) {
528 /* Add the new dsentry before the first mempool dsentry atomically. */
530 next_mempool_dsentry
= _magic_first_mempool_dsentry
;
531 MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry
) = next_mempool_dsentry
;
532 } while(MAGIC_CAS(&_magic_first_mempool_dsentry
, next_mempool_dsentry
, dsentry
) != next_mempool_dsentry
);
534 magic_update_dsentry_ranges
= 1;
536 if (magic_mem_create_dsentry_cb
)
537 magic_mem_create_dsentry_cb(dsentry
);
542 /*===========================================================================*
543 * magic_create_obdsentry *
544 *===========================================================================*/
545 PUBLIC
struct _magic_obdsentry
* magic_create_obdsentry(void *data_ptr
,
546 struct _magic_type
*type
, size_t size
, int flags
,
547 const char *name
, const char *parent_name
)
549 struct _magic_obdsentry
*obdsentry
= NULL
;
553 if(!name
|| !strcmp(name
, "")) {
556 else if(strlen(name
) >= MAGIC_MAX_OBDSENTRY_NAME_LEN
) {
560 /* Check parent name. */
561 if(!parent_name
|| !strcmp(parent_name
, "")) {
562 parent_name
= MAGIC_OBDSENTRY_DEFAULT_PARENT_NAME
;
564 if(strlen(parent_name
) >= MAGIC_MAX_OBDSENTRY_PARENT_NAME_LEN
) {
568 MAGIC_MEM_WRAPPER_LBEGIN();
570 /* Find a free slot. */
571 for(i
=0;i
<MAGIC_MAX_OBDSENTRIES
;i
++) {
572 if(MAGIC_OBDSENTRY_IS_FREE(&_magic_obdsentries
[i
])) {
573 obdsentry
= &_magic_obdsentries
[i
];
578 MAGIC_MEM_WRAPPER_LEND();
582 /* Create the dsentry. */
583 strcpy(obdsentry
->name
, name
);
584 strcpy(obdsentry
->parent_name
, parent_name
);
585 flags
|= MAGIC_STATE_OUT_OF_BAND
;
586 ret
= magic_create_dsentry(MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry
), data_ptr
, type
,
587 size
, flags
, obdsentry
->name
, obdsentry
->parent_name
);
589 MAGIC_MEM_WRAPPER_LEND();
594 assert(!MAGIC_OBDSENTRY_IS_FREE(obdsentry
));
599 /*===========================================================================*
600 * magic_update_dsentry_state *
601 *===========================================================================*/
602 PUBLIC
int magic_update_dsentry_state(struct _magic_dsentry
*dsentry
,
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
;
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
;
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
);
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
;
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();
654 /*===========================================================================*
655 * magic_free_dsentry *
656 *===========================================================================*/
657 PRIVATE
int magic_free_dsentry(struct _magic_dsentry
*dsentry
)
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
);
669 MAGIC_MEM_WRAPPER_BEGIN();
672 if (magic_mem_heap_free_cb
) {
673 ret
= magic_mem_heap_free_cb(dsentry
);
674 if (ret
!= MAGIC_ENOENT
)
678 * If the callback returned MAGIC_ENOENT, fallback to
679 * the default behavior.
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
;
688 case MAGIC_STATE_HEAP
:
689 MAGIC_MEM_DEBUG_FREE(ptr
);
692 case MAGIC_STATE_MAP
:
693 case MAGIC_STATE_SHM
:
694 page_size
= MAGIC_PAGE_SIZE
;
695 size
= MAGIC_DSENTRY_TO_SENTRY(dsentry
)->type
->size
;
696 data_ptr
= MAGIC_PTR_TO_DATA(ptr
);
697 aligned_ptr
= ((char *)data_ptr
) - page_size
;
699 if (!MAGIC_STATE_FLAG(sentry
, MAGIC_STATE_DETACHED
)) {
700 size_t padding_size
= (size_t) dsentry
->ext
;
701 MAGIC_MEM_DEBUG_FREE(ptr
);
702 ret
= munmap((char *)aligned_ptr
, page_size
+ size
+ padding_size
);
706 if (MAGIC_STATE_FLAG(sentry
, MAGIC_STATE_SHM
))
707 ret
= shmdt(data_ptr
);
710 ret
= munmap(data_ptr
, size
);
711 MAGIC_MEM_DEBUG_FREE(ptr
);
712 munmap(aligned_ptr
, page_size
);
723 MAGIC_MEM_WRAPPER_END();
729 /*===========================================================================*
730 * magic_free_dead_dsentries *
731 *===========================================================================*/
732 PUBLIC
void magic_free_dead_dsentries()
734 struct _magic_dsentry
*prev_dsentry
, *dsentry
, *next_first_dsentry
, *skipped_dsentry
;
735 struct _magic_sentry
*sentry
;
736 unsigned long num_dead_dsentries
;
737 int dead_dsentries_left
;
740 MAGIC_DSENTRY_LOCK();
742 skipped_dsentry
= NULL
;
743 num_dead_dsentries
= magic_num_dead_dsentries
;
744 next_first_dsentry
= _magic_first_dsentry
;
745 if (next_first_dsentry
) {
746 /* if the first dsentry is dead, skip it to eliminate contention on the list head */
747 if (next_first_dsentry
->magic_state
== MAGIC_DSENTRY_MSTATE_DEAD
){
748 num_dead_dsentries
--;
752 if(!next_first_dsentry
|| num_dead_dsentries
== 0) {
753 MAGIC_DSENTRY_UNLOCK();
757 MAGIC_MEM_PRINTF("magic_free_dead_dsentries: Freeing %d dead dsentries...\n", num_dead_dsentries
);
759 /* Eliminate the dead dsentries but always skip the first one to eliminate contention on the head. */
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
;
768 magic_destroy_dsentry(dsentry
, prev_dsentry
);
769 ret
= magic_free_dsentry(dsentry
);
771 _magic_printf("Warning: magic_free_dsentry failed with return code %d for: ", ret
);
772 MAGIC_DSENTRY_PRINT(dsentry
, MAGIC_EXPAND_TYPE_STR
);
773 MAGIC_MEM_PRINTF("\n");
775 num_dead_dsentries
--;
776 dead_dsentries_left
= 1;
780 } while(dead_dsentries_left
&& num_dead_dsentries
> 0);
781 assert(num_dead_dsentries
== 0);
783 MAGIC_DSENTRY_UNLOCK();
786 /*===========================================================================*
787 * magic_destroy_dsentry *
788 *===========================================================================*/
789 PUBLIC
void magic_destroy_dsentry(struct _magic_dsentry
*dsentry
,
790 struct _magic_dsentry
*prev_dsentry
)
792 struct _magic_dsentry
*next_dsentry
, *next_mempool_dsentry
, *prev_mempool_dsentry
= NULL
;
793 int dsentry_destroyed
, mempool_dsentry_destroyed
;
795 if(magic_destroy_dsentry_ext_cb
&& MAGIC_DSENTRY_HAS_EXT(dsentry
)) {
796 magic_destroy_dsentry_ext_cb(dsentry
);
798 if (MAGIC_STATE_FLAG(MAGIC_DSENTRY_TO_SENTRY(dsentry
), MAGIC_STATE_MEMPOOL
)) {
800 if(!prev_mempool_dsentry
) {
801 if(MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry
) != MAGIC_DSENTRY_NEXT_MEMPOOL(_magic_first_mempool_dsentry
)) {
802 prev_mempool_dsentry
= magic_mempool_dsentry_prev_lookup(dsentry
);
803 assert(prev_mempool_dsentry
!= (struct _magic_dsentry
*) MAGIC_ENOPTR
&& "Dsentry not found!");
806 if(prev_mempool_dsentry
) {
807 MAGIC_DSENTRY_NEXT_MEMPOOL(prev_mempool_dsentry
) = MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry
);
808 mempool_dsentry_destroyed
= 1;
811 /* Remove the first dsentry atomically. */
812 next_mempool_dsentry
= MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry
);
813 mempool_dsentry_destroyed
= (MAGIC_CAS(&_magic_first_mempool_dsentry
,
814 dsentry
, next_mempool_dsentry
) == dsentry
);
816 } while(!mempool_dsentry_destroyed
);
817 MAGIC_DSENTRY_NEXT_MEMPOOL(dsentry
) = NULL
;
820 #if MAGIC_DSENTRY_ALLOW_PREV
821 prev_dsentry
= MAGIC_DSENTRY_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!");
832 MAGIC_DSENTRY_NEXT(prev_dsentry
) = MAGIC_DSENTRY_NEXT(dsentry
);
833 dsentry_destroyed
= 1;
836 /* Remove the first dsentry atomically. */
837 next_dsentry
= MAGIC_DSENTRY_NEXT(dsentry
);
838 dsentry_destroyed
= (MAGIC_CAS(&_magic_first_dsentry
,
839 dsentry
, next_dsentry
) == dsentry
);
841 } while(!dsentry_destroyed
);
843 #if MAGIC_DSENTRY_ALLOW_PREV
844 next_dsentry
= MAGIC_DSENTRY_NEXT(dsentry
);
846 MAGIC_DSENTRY_PREV(next_dsentry
) = MAGIC_DSENTRY_PREV(dsentry
);
848 MAGIC_DSENTRY_PREV(dsentry
) = NULL
;
851 dsentry
->magic_number
= MAGIC_DSENTRY_MNUM_NULL
;
852 MAGIC_DSENTRY_NEXT(dsentry
) = NULL
;
855 /*===========================================================================*
856 * magic_destroy_obdsentry_by_addr *
857 *===========================================================================*/
858 PUBLIC
int magic_destroy_obdsentry_by_addr(void *data_ptr
)
860 struct _magic_sentry
*sentry
;
861 struct _magic_dsentry
*dsentry
;
862 struct _magic_obdsentry
*obdsentry
;
863 int obflags
= (MAGIC_STATE_DYNAMIC
|MAGIC_STATE_OUT_OF_BAND
);
865 MAGIC_MEM_WRAPPER_LBEGIN();
867 /* Lookup the obdsentry. */
868 sentry
= magic_sentry_lookup_by_addr(data_ptr
, NULL
);
869 if(!sentry
|| ((sentry
->flags
& obflags
) != obflags
)) {
870 MAGIC_MEM_WRAPPER_LEND();
873 dsentry
= MAGIC_DSENTRY_FROM_SENTRY(sentry
);
874 obdsentry
= MAGIC_OBDSENTRY_FROM_DSENTRY(dsentry
);
876 /* Destroy it and free obdsentry slot. */
877 magic_destroy_dsentry(dsentry
, NULL
);
878 MAGIC_OBDSENTRY_FREE(obdsentry
);
880 MAGIC_MEM_WRAPPER_LEND();
885 /*===========================================================================*
886 * magic_destroy_dsentry_set_ext_cb *
887 *===========================================================================*/
888 PUBLIC
void magic_destroy_dsentry_set_ext_cb(const magic_dsentry_cb_t cb
)
890 magic_destroy_dsentry_ext_cb
= cb
;
893 /*===========================================================================*
894 * magic_update_dsentry *
895 *===========================================================================*/
896 PUBLIC
int magic_update_dsentry(void* addr
, struct _magic_type
*type
)
898 struct _magic_dsentry
*prev_dsentry
, *dsentry
;
899 struct _magic_sentry
* sentry
;
900 size_t size
, type_size
;
902 int num_vsa_elements
= 0;
904 MAGIC_DSENTRY_LOCK();
905 MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry
, prev_dsentry
, dsentry
, sentry
,
906 if(sentry
->address
== addr
) {
907 size
= sentry
->type
->size
;
908 type_size
= type
->size
;
910 /* Catch variable-sized struct allocation. */
911 if(magic_type_alloc_needs_varsized_array(type
, size
, &num_vsa_elements
)) {
915 if(size
% type_size
!= 0 && !is_varsized
) {
916 return MAGIC_EBADENT
;
918 if(size
== type_size
&& !is_varsized
) {
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
;
932 MAGIC_DSENTRY_UNLOCK();
937 /*===========================================================================*
939 *===========================================================================*/
940 PUBLIC
void magic_stack_init()
942 struct _magic_obdsentry
*obdsentry
;
945 void *initial_stack_bottom
, *initial_stack_top
;
946 unsigned long* word_ptr
;
950 assert(!_magic_first_stack_dsentry
&& !_magic_last_stack_dsentry
);
952 /* Find initial stack bottom and top, this should be portable enough */
953 for (ptr
= environ
; *ptr
; ptr
++);
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
961 /* environment is not empty. decrement the pointer,
962 * because the for loop walked past the last env variable pointer.
968 initial_stack_bottom
= *ptr
+strlen(*ptr
)+1;
969 word_ptr
= (unsigned long*) environ
;
971 assert(*word_ptr
== 0); /* argv terminator */
974 while(*word_ptr
!= (unsigned long) argc
) {
978 argv
= (char**) (word_ptr
+1);
979 initial_stack_top
= argv
;
981 /* Environ and argv empty?. Resort to defaults. */
982 initial_stack_top
= ptr
;
983 initial_stack_bottom
= environ
;
985 size
= (size_t)initial_stack_bottom
- (size_t)initial_stack_top
+ 1;
987 /* Create the first stack dsentry. */
988 obdsentry
= magic_create_obdsentry(initial_stack_top
, MAGIC_VOID_TYPE
,
989 size
, MAGIC_STATE_STACK
, MAGIC_ALLOC_INITIAL_STACK_NAME
, NULL
);
991 _magic_first_stack_dsentry
= _magic_last_stack_dsentry
= MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry
);
994 /*===========================================================================*
995 * magic_stack_dsentries_create *
996 *===========================================================================*/
997 PUBLIC
void magic_stack_dsentries_create(
998 struct _magic_dsentry
**prev_last_stack_dsentry
, int num_dsentries
,
999 /* struct _magic_dsentry *dsentry, struct _magic_type *type, void* data_ptr, const char* function_name, const char* name, */ ...)
1002 struct _magic_dsentry
*dsentry
;
1003 struct _magic_type
*type
;
1005 const char* function_name
;
1007 char *min_data_ptr
= NULL
, *max_data_ptr
= NULL
;
1010 assert(num_dsentries
> 0);
1012 MAGIC_DSENTRY_LOCK();
1013 assert(_magic_first_stack_dsentry
&& "First stack dsentry not found!");
1014 va_start(va
, num_dsentries
);
1015 *prev_last_stack_dsentry
= _magic_last_stack_dsentry
;
1016 for (i
= 0 ; i
< num_dsentries
; i
++) {
1017 dsentry
= va_arg(va
, struct _magic_dsentry
*);
1018 type
= va_arg(va
, struct _magic_type
*);
1019 data_ptr
= va_arg(va
, void *);
1020 function_name
= va_arg(va
, const char *);
1021 name
= va_arg(va
, const char *);
1022 if (i
== num_dsentries
- 1) {
1023 /* Return address. */
1024 int *value_set
= (void*) type
;
1025 data_ptr
= MAGIC_FRAMEADDR_TO_RETADDR_PTR(data_ptr
);
1026 type
= &(dsentry
->type
);
1027 magic_create_dsentry(dsentry
, data_ptr
, MAGIC_VOID_TYPE
, MAGIC_VOID_TYPE
->size
,
1028 MAGIC_STATE_STACK
| MAGIC_STATE_CONSTANT
| MAGIC_STATE_ADDR_NOT_TAKEN
,
1029 name
, function_name
);
1030 memcpy(type
, &magic_default_ret_addr_type
, sizeof(struct _magic_type
));
1031 type
->contained_types
= MAGIC_DSENTRY_TO_TYPE_ARR(dsentry
);
1032 type
->contained_types
[0] = MAGIC_VOID_TYPE
;
1033 type
->value_set
= value_set
;
1035 value_set
[1] = *((int *)data_ptr
);
1037 /* Safe to override the type non-atomically.
1038 * The new type is only more restrictive, and nobody could
1039 * have touched this stack dsentry in the meantime.
1041 MAGIC_DSENTRY_TO_SENTRY(dsentry
)->type
= type
;
1043 /* Local variable. */
1044 magic_create_dsentry(dsentry
, data_ptr
, type
, type
->size
,
1045 MAGIC_STATE_STACK
, name
, function_name
);
1046 if (!min_data_ptr
|| min_data_ptr
> (char *) data_ptr
) {
1047 min_data_ptr
= (char *) data_ptr
;
1049 if (!max_data_ptr
|| max_data_ptr
< (char *) data_ptr
) {
1050 max_data_ptr
= (char *) data_ptr
;
1055 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1056 if (min_data_ptr
&& max_data_ptr
) {
1057 memset(min_data_ptr
, 0, max_data_ptr
- min_data_ptr
+ 1);
1061 _magic_last_stack_dsentry
= dsentry
;
1062 MAGIC_DSENTRY_UNLOCK();
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, */ ...)
1075 struct _magic_dsentry
*dsentry
;
1078 assert(num_dsentries
> 0);
1080 MAGIC_MEM_WRAPPER_LBEGIN();
1082 va_start(va
, num_dsentries
);
1083 _magic_last_stack_dsentry
= *prev_last_stack_dsentry
;
1084 for (i
= 0 ; i
< num_dsentries
; i
++) {
1085 dsentry
= va_arg(va
, struct _magic_dsentry
*);
1086 magic_destroy_dsentry(dsentry
, NULL
);
1090 MAGIC_MEM_WRAPPER_LEND();
1093 /*===========================================================================*
1094 * magic_create_dfunction *
1095 *===========================================================================*/
1096 PUBLIC
int magic_create_dfunction(struct _magic_dfunction
*dfunction
,
1097 void *data_ptr
, struct _magic_type
*type
, int flags
,
1098 const char *name
, const char *parent_name
)
1100 struct _magic_function
*function
= MAGIC_DFUNCTION_TO_FUNCTION(dfunction
);
1103 type
= MAGIC_VOID_TYPE
;
1106 memcpy(dfunction
, &magic_default_dfunction
, sizeof(struct _magic_dfunction
));
1108 assert(!(type
->flags
& MAGIC_TYPE_DYNAMIC
) && "bad type!");
1110 function
->type
= type
;
1111 function
->flags
|= flags
;
1112 function
->address
= data_ptr
;
1114 function
->name
= name
;
1117 dfunction
->parent_name
= parent_name
;
1119 function
->id
= MAGIC_FAA(&_magic_functions_next_id
, 1);
1120 assert(_magic_functions_next_id
< MAGIC_ID_MAX
);
1122 if(_magic_first_dfunction
) {
1123 assert(_magic_last_dfunction
);
1124 MAGIC_DFUNCTION_NEXT(_magic_last_dfunction
) = dfunction
;
1127 assert(!_magic_last_dfunction
);
1128 assert(_magic_dfunctions_num
== 0);
1129 _magic_first_dfunction
= dfunction
;
1131 MAGIC_DFUNCTION_PREV(dfunction
) = _magic_last_dfunction
;
1132 MAGIC_DFUNCTION_NEXT(dfunction
) = NULL
;
1133 _magic_last_dfunction
= dfunction
;
1134 _magic_dfunctions_num
++;
1136 assert(magic_check_dfunction(dfunction
, 0) && "Bad magic dfunction created!");
1137 magic_update_dfunction_ranges
= 1;
1142 /*===========================================================================*
1143 * magic_destroy_dfunction *
1144 *===========================================================================*/
1145 PUBLIC
void magic_destroy_dfunction(struct _magic_dfunction
*dfunction
)
1147 dfunction
->magic_number
= MAGIC_DFUNCTION_MNUM_NULL
;
1148 if(MAGIC_DFUNCTION_HAS_NEXT(dfunction
)) {
1149 MAGIC_DFUNCTION_PREV(MAGIC_DFUNCTION_NEXT(dfunction
)) = MAGIC_DFUNCTION_PREV(dfunction
);
1152 _magic_last_dfunction
= MAGIC_DFUNCTION_PREV(dfunction
);
1154 if(MAGIC_DFUNCTION_HAS_PREV(dfunction
)) {
1155 MAGIC_DFUNCTION_NEXT(MAGIC_DFUNCTION_PREV(dfunction
)) = MAGIC_DFUNCTION_NEXT(dfunction
);
1158 _magic_first_dfunction
= MAGIC_DFUNCTION_NEXT(dfunction
);
1160 MAGIC_DFUNCTION_NEXT(dfunction
) = NULL
;
1161 MAGIC_DFUNCTION_PREV(dfunction
) = NULL
;
1162 _magic_dfunctions_num
--;
1163 if(_magic_dfunctions_num
== 0) {
1164 assert(!_magic_first_dfunction
&& !_magic_last_dfunction
);
1167 assert(_magic_first_dfunction
&& _magic_last_dfunction
);
1171 /*===========================================================================*
1172 * magic_create_sodesc *
1173 *===========================================================================*/
1174 PUBLIC
int magic_create_sodesc(struct _magic_sodesc
*sodesc
)
1176 if(_magic_first_sodesc
) {
1177 assert(_magic_last_sodesc
);
1178 MAGIC_SODESC_NEXT(_magic_last_sodesc
) = sodesc
;
1181 assert(!_magic_last_sodesc
);
1182 assert(_magic_sodescs_num
== 0);
1183 _magic_first_sodesc
= sodesc
;
1185 MAGIC_SODESC_PREV(sodesc
) = _magic_last_sodesc
;
1186 MAGIC_SODESC_NEXT(sodesc
) = NULL
;
1187 _magic_last_sodesc
= sodesc
;
1188 _magic_sodescs_num
++;
1193 /*===========================================================================*
1194 * magic_destroy_sodesc *
1195 *===========================================================================*/
1196 PUBLIC
int magic_destroy_sodesc(struct _magic_sodesc
*sodesc
)
1199 * NB!: This function requires the calling thread to already
1200 * hold the DSENTRY and DFUNCTION locks.
1204 struct _magic_dsentry
*prev_dsentry
, *dsentry
, *last_dsentry
;
1205 struct _magic_sentry
*sentry
;
1206 struct _magic_dfunction
*dfunction
, *last_dfunction
;
1209 * Time to destroy all the dsentries and dfunctions
1210 * linked to the descriptor.
1212 name
= sodesc
->lib
.name
;
1213 last_dsentry
= NULL
;
1214 MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry
, prev_dsentry
,
1217 magic_destroy_dsentry(last_dsentry
, NULL
);
1218 last_dsentry
= dsentry
->parent_name
== name
? dsentry
: NULL
;
1221 magic_destroy_dsentry(last_dsentry
, NULL
);
1222 last_dfunction
= NULL
;
1223 MAGIC_DFUNCTION_ITER(_magic_first_dfunction
, dfunction
,
1225 magic_destroy_dfunction(last_dfunction
);
1226 last_dfunction
= dfunction
->parent_name
== name
? dfunction
: NULL
;
1228 if(last_dfunction
) magic_destroy_dfunction(last_dfunction
);
1230 /* Now get rid of the descriptor. */
1231 if (MAGIC_SODESC_HAS_NEXT(sodesc
)) {
1232 MAGIC_SODESC_PREV(MAGIC_SODESC_NEXT(sodesc
)) =
1233 MAGIC_SODESC_PREV(sodesc
);
1236 _magic_last_sodesc
= MAGIC_SODESC_PREV(sodesc
);
1238 if (MAGIC_SODESC_HAS_PREV(sodesc
)) {
1239 MAGIC_SODESC_NEXT(MAGIC_SODESC_PREV(sodesc
)) =
1240 MAGIC_SODESC_NEXT(sodesc
);
1243 _magic_first_sodesc
= MAGIC_SODESC_NEXT(sodesc
);
1245 MAGIC_SODESC_NEXT(sodesc
) = NULL
;
1246 MAGIC_SODESC_PREV(sodesc
) = NULL
;
1247 _magic_sodescs_num
--;
1248 if (_magic_sodescs_num
== 0) {
1249 assert(!_magic_first_sodesc
&& !_magic_last_sodesc
);
1252 assert(_magic_first_sodesc
&& _magic_last_sodesc
);
1256 * Unmap the memory area that contained the dsentries and dfunctions
1257 * of this descriptor.
1259 ret
= munmap(sodesc
->lib
.alloc_address
, sodesc
->lib
.alloc_size
);
1260 assert(ret
== 0 && "Unable to unmap SODESC memory segment!");
1265 /*===========================================================================*
1266 * magic_create_dsodesc *
1267 *===========================================================================*/
1268 PUBLIC
int magic_create_dsodesc(struct _magic_dsodesc
*dsodesc
)
1271 * NB!: This function requires the calling thread to already
1272 * hold the DSODESC lock.
1274 if (_magic_first_dsodesc
) {
1275 assert(_magic_last_dsodesc
);
1276 MAGIC_DSODESC_NEXT(_magic_last_dsodesc
) = dsodesc
;
1279 assert(!_magic_last_dsodesc
);
1280 assert(_magic_dsodescs_num
== 0);
1281 _magic_first_dsodesc
= dsodesc
;
1283 MAGIC_DSODESC_PREV(dsodesc
) = _magic_last_dsodesc
;
1284 MAGIC_DSODESC_NEXT(dsodesc
) = NULL
;
1285 _magic_last_dsodesc
= dsodesc
;
1286 _magic_dsodescs_num
++;
1291 /*===========================================================================*
1292 * magic_destroy_dsodesc *
1293 *===========================================================================*/
1294 PUBLIC
int magic_destroy_dsodesc(struct _magic_dsodesc
*dsodesc
)
1297 * NB!: This function requires the calling thread to already
1298 * hold the DSENTRY, DFUNCTION and DSODESC locks.
1302 struct _magic_dsentry
*prev_dsentry
, *dsentry
, *last_dsentry
;
1303 struct _magic_sentry
*sentry
;
1304 struct _magic_dfunction
*dfunction
, *last_dfunction
;
1306 dsodesc
->ref_count
--;
1307 /* Don't destroy the DSO descriptor quite yet, we still have references. */
1308 if (dsodesc
->ref_count
> 0) {
1309 return dsodesc
->ref_count
;
1313 * Time to destroy all the dsentries and dfunctions
1314 * linked to the descriptor.
1316 name
= dsodesc
->lib
.name
;
1317 last_dsentry
= NULL
;
1318 MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry
, prev_dsentry
,
1321 magic_destroy_dsentry(last_dsentry
, NULL
);
1322 last_dsentry
= dsentry
->parent_name
== name
? dsentry
: NULL
;
1325 magic_destroy_dsentry(last_dsentry
, NULL
);
1326 last_dfunction
= NULL
;
1327 MAGIC_DFUNCTION_ITER(_magic_first_dfunction
, dfunction
,
1329 magic_destroy_dfunction(last_dfunction
);
1330 last_dfunction
= dfunction
->parent_name
== name
? dfunction
: NULL
;
1333 magic_destroy_dfunction(last_dfunction
);
1335 /* Now get rid of the descriptor. */
1336 if (MAGIC_DSODESC_HAS_NEXT(dsodesc
)) {
1337 MAGIC_DSODESC_PREV(MAGIC_DSODESC_NEXT(dsodesc
)) =
1338 MAGIC_DSODESC_PREV(dsodesc
);
1341 _magic_last_dsodesc
= MAGIC_DSODESC_PREV(dsodesc
);
1343 if (MAGIC_DSODESC_HAS_PREV(dsodesc
)) {
1344 MAGIC_DSODESC_NEXT(MAGIC_DSODESC_PREV(dsodesc
)) =
1345 MAGIC_DSODESC_NEXT(dsodesc
);
1348 _magic_first_dsodesc
= MAGIC_DSODESC_NEXT(dsodesc
);
1350 MAGIC_DSODESC_NEXT(dsodesc
) = NULL
;
1351 MAGIC_DSODESC_PREV(dsodesc
) = NULL
;
1352 _magic_dsodescs_num
--;
1353 if (_magic_dsodescs_num
== 0) {
1354 assert(!_magic_first_dsodesc
&& !_magic_last_dsodesc
);
1357 assert(_magic_first_dsodesc
&& _magic_last_dsodesc
);
1361 * Unmap the memory area that contained the dsentries and dfunctions
1362 * of this descriptor.
1364 ret
= munmap(dsodesc
->lib
.alloc_address
, dsodesc
->lib
.alloc_size
);
1365 assert(ret
== 0 && "Unable to unmap DSODESC memory segment!");
1367 return 0; /* no more references, descriptor is gone. */
1370 /*===========================================================================*
1372 *===========================================================================*/
1373 PUBLIC
void *magic_alloc(__MA_ARGS__
void *ptr
, size_t size
, int flags
)
1377 struct _magic_dsentry
*dsentry
;
1382 data_ptr
= MAGIC_PTR_TO_DATA(ptr
);
1383 dsentry
= MAGIC_PTR_TO_DSENTRY(ptr
);
1384 /* Catch pool allocations and update the name & flags */
1385 if (MAGIC_MEMPOOL_MGMT_IS_ACTIVE() && !(flags
& MAGIC_STATE_MEMBLOCK
)) {
1386 flags
|= MAGIC_STATE_MEMPOOL
;
1387 name
= MAGIC_MEMPOOL_GET_NAME();
1389 ret
= magic_create_dsentry(dsentry
, data_ptr
, type
, size
, flags
, name
, parent_name
);
1390 MAGIC_MEM_PRINTF("magic_alloc: ret = magic_create_dsentry(dsentry, data_ptr, type, size, flags, NULL, NULL) <-> %d = magic_create_dsentry(0x%08x, 0x%08x, 0x%08x, %d, 0x%08x, NULL, NULL)\n", ret
, (unsigned) dsentry
, (unsigned) data_ptr
, type
, size
, flags
);
1392 return MAGIC_MEM_FAILED
;
1395 /* this way we skip the memory pool blocks -they are not real allocations and should not be logged */
1396 if (!(flags
& MAGIC_STATE_MEMBLOCK
)) {
1397 MAGIC_MEM_DEBUG_ALLOC(ptr
, (MAGIC_SIZE_TO_REAL(size
)));
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");
1406 MAGIC_MEM_PRINTF("magic_alloc: return 0x%08x\n", (unsigned) data_ptr
);
1411 /*===========================================================================*
1412 * magic_malloc_positioned *
1413 *===========================================================================*/
1414 PUBLIC
void *magic_malloc_positioned(__MA_ARGS__
size_t size
, void *ptr
)
1417 int dsentry_flags
= MAGIC_STATE_HEAP
;
1419 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1420 assert(!_magic_vars
->fake_malloc
);
1422 return magic_calloc(__MA_VALUES__ size
, 1);
1426 MAGIC_MEM_WRAPPER_BEGIN();
1429 if (!ptr
|| !_magic_vars
->fake_malloc
) {
1431 * Check the external callback first.
1433 if (magic_mem_heap_alloc_cb
)
1434 ptr
= magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size
) + magic_asr_get_padding_size(MAGIC_STATE_HEAP
), name
, parent_name
);
1437 ptr
= malloc(MAGIC_SIZE_TO_REAL(size
) + magic_asr_get_padding_size(MAGIC_STATE_HEAP
));
1438 MAGIC_MEM_PRINTF("magic_malloc: ptr = malloc(size) <-> 0x%08x = malloc(%d)\n", (unsigned) ptr
, MAGIC_SIZE_TO_REAL(size
));
1440 data_ptr
= magic_alloc(__MA_VALUES__ ptr
, size
, dsentry_flags
);
1441 if (data_ptr
== MAGIC_MEM_FAILED
) {
1443 * XXX: This doesn't seem likely to happen. However, if it does,
1444 * we need to distinguish between regular malloc() memory
1445 * and super-objects. See llvm/shared/libst/include/heap.h for
1452 magic_heap_end
= ((char *)sbrk(0)) - 1;
1458 MAGIC_MEM_WRAPPER_END();
1463 /*===========================================================================*
1465 *===========================================================================*/
1466 PUBLIC
void *magic_malloc(__MA_ARGS__
size_t size
)
1468 return magic_malloc_positioned(__MA_VALUES__ size
, NULL
);
1471 /*===========================================================================*
1473 *===========================================================================*/
1474 PUBLIC
void *magic_calloc(__MA_ARGS__
size_t nmemb
, size_t size
)
1476 void *ptr
= NULL
, *data_ptr
;
1478 int dsentry_flags
= MAGIC_STATE_HEAP
;
1480 MAGIC_MEM_WRAPPER_BEGIN();
1483 real_size
= MAGIC_SIZE_TO_REAL(size
*nmemb
);
1485 * Check the external callback first.
1487 if (magic_mem_heap_alloc_cb
)
1488 ptr
= magic_mem_heap_alloc_cb(real_size
+ magic_asr_get_padding_size(MAGIC_STATE_HEAP
), name
, parent_name
);
1491 ptr
= calloc(real_size
+ magic_asr_get_padding_size(MAGIC_STATE_HEAP
), 1);
1492 MAGIC_MEM_PRINTF("magic_calloc: ptr = calloc(nmemb, size) <-> 0x%08x = calloc(%d, %d)\n", (unsigned) ptr
, nmemb
, real_size
);
1493 data_ptr
= magic_alloc(__MA_VALUES__ ptr
, size
*nmemb
, dsentry_flags
);
1494 if(data_ptr
== MAGIC_MEM_FAILED
) {
1496 * XXX: This doesn't seem likely to happen. However, if it does,
1497 * we need to distinguish between regular malloc() memory
1498 * and super-objects. See llvm/shared/libst/include/heap.h for
1505 magic_heap_end
= ((char*)sbrk(0))-1;
1511 MAGIC_MEM_WRAPPER_END();
1516 /*===========================================================================*
1518 *===========================================================================*/
1519 PUBLIC
void magic_free(__MD_ARGS__
void *data_ptr
)
1524 MAGIC_MEM_WRAPPER_BEGIN();
1527 ptr
= MAGIC_PTR_FROM_DATA(data_ptr
);
1529 /* Check for legitimate non-indexed chunks of memory and skip. */
1530 if((!magic_libcommon_active
|| !MAGIC_USE_DYN_MEM_WRAPPERS
)
1531 && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr
))) {
1532 MAGIC_MEM_WRAPPER_END();
1537 MAGIC_MEM_PRINTF("magic_free: magic_free(0x%08x) / free(0x%08x)\n", (unsigned) data_ptr
, (unsigned) ptr
);
1538 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
), MAGIC_STATE_HEAP
) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1540 if(magic_allow_dead_dsentries
) {
1541 ret
= magic_update_dsentry_state(MAGIC_PTR_TO_DSENTRY(ptr
), MAGIC_DSENTRY_MSTATE_DEAD
);
1542 assert(ret
== 0 && "Bad free!");
1545 MAGIC_DSENTRY_LOCK();
1546 magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
), NULL
);
1547 ret
= magic_free_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
));
1548 assert(ret
== 0 && "Bad free!");
1549 MAGIC_DSENTRY_UNLOCK();
1553 MAGIC_MEM_WRAPPER_END();
1556 /*===========================================================================*
1558 *===========================================================================*/
1559 PUBLIC
void *magic_realloc(__MA_ARGS__
void *data_ptr
, size_t size
)
1561 void *ptr
, *new_ptr
, *new_data_ptr
;
1565 return magic_malloc(__MA_VALUES__ size
);
1568 magic_free(__MD_VALUES_DEFAULT__ data_ptr
);
1572 ptr
= MAGIC_PTR_FROM_DATA(data_ptr
);
1573 new_data_ptr
= magic_malloc(__MA_VALUES__ size
);
1577 new_ptr
= MAGIC_PTR_FROM_DATA(new_data_ptr
);
1578 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
), MAGIC_STATE_HEAP
) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1579 MAGIC_MEM_PRINTF("magic_realloc: ptr = realloc(ptr, size) <-> 0x%08x = realloc(0x%08x, %d)\n", (unsigned) new_ptr
, (unsigned) ptr
, MAGIC_SIZE_TO_REAL(size
));
1581 old_size
= MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr
))->type
->size
;
1582 memcpy(new_data_ptr
, data_ptr
, old_size
< size
? old_size
: size
);
1583 magic_free(__MD_VALUES_DEFAULT__ data_ptr
);
1585 return new_data_ptr
;
1588 /*===========================================================================*
1589 * magic_posix_memalign *
1590 *===========================================================================*/
1591 PUBLIC
int magic_posix_memalign(__MA_ARGS__
void **memptr
, size_t alignment
, size_t size
)
1594 void *ptr
= NULL
, *data_ptr
;
1595 int dsentry_flags
= MAGIC_STATE_HEAP
;
1597 MAGIC_MEM_WRAPPER_BEGIN();
1601 * Check the external callback first.
1603 if (magic_mem_heap_alloc_cb
)
1604 ptr
= magic_mem_heap_alloc_cb(MAGIC_SIZE_TO_REAL(size
), name
, parent_name
);
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
));
1610 data_ptr
= magic_alloc(__MA_VALUES__ ptr
, size
, dsentry_flags
);
1611 if(data_ptr
== MAGIC_MEM_FAILED
) {
1613 * XXX: This doesn't seem likely to happen. However, if it does,
1614 * we need to distinguish between regular malloc() memory
1615 * and super-objects. See llvm/shared/libst/include/heap.h for
1623 #if MAGIC_FORCE_DYN_MEM_ZERO_INIT
1624 memset(data_ptr
, 0, size
);
1627 magic_heap_end
= ((char*)sbrk(0))-1;
1634 MAGIC_MEM_WRAPPER_END();
1640 /*===========================================================================*
1642 *===========================================================================*/
1643 PUBLIC
void *magic_valloc(__MA_ARGS__
size_t size
)
1645 return magic_memalign(__MA_VALUES__ MAGIC_PAGE_SIZE
, size
);
1648 /*===========================================================================*
1650 *===========================================================================*/
1651 PUBLIC
void *magic_memalign(__MA_ARGS__
size_t boundary
, size_t size
)
1654 int ret
= magic_posix_memalign(__MA_VALUES__
&ptr
, boundary
, size
);
1663 /*===========================================================================*
1664 * magic_mmap_positioned *
1665 *===========================================================================*/
1666 PUBLIC
void *magic_mmap_positioned(__MA_ARGS__
void *start
, size_t length
, int prot
, int flags
,
1667 int fd
, off_t offset
, struct _magic_dsentry
*cached_dsentry
)
1669 void *ptr
, *data_ptr
, *aligned_start
, *aligned_ptr
;
1670 void *new_ptr
, *new_start
;
1671 int dsentry_flags
= MAGIC_STATE_MAP
;
1672 size_t alloc_length
;
1673 size_t page_size
= MAGIC_PAGE_SIZE
;
1674 int padding_type
, padding_size
;
1675 static THREAD_LOCAL
int magic_is_first_mmap
= 1;
1677 MAGIC_MEM_WRAPPER_BEGIN();
1679 if (flags
& MAP_FIXED
) {
1680 /* Allow safe overmapping. */
1681 struct _magic_sentry
*sentry
= magic_sentry_lookup_by_range(start
, NULL
);
1682 if (sentry
&& sentry
== magic_sentry_lookup_by_range((char*)start
+length
-1, NULL
))
1683 return mmap(start
, length
, prot
, flags
, fd
, offset
);
1685 assert(!(flags
& MAP_FIXED
) && "MAP_FIXED may override existing mapping, currently not implemented!");
1687 if (magic_is_first_mmap
) {
1688 magic_is_first_mmap
= 0;
1689 padding_type
= MAGIC_STATE_MAP
| MAGIC_ASR_FLAG_INIT
;
1691 padding_type
= MAGIC_STATE_MAP
;
1693 padding_size
= start
? 0 : magic_asr_get_padding_size(padding_type
);
1695 assert(MAGIC_SIZE_TO_REAL(length
) <= page_size
+ length
);
1696 aligned_start
= start
? ((char *)start
) - page_size
: NULL
;
1697 alloc_length
= length
+ (length
% page_size
== 0 ? 0 : page_size
- (length
% page_size
));
1699 if (_magic_vars
->do_skip_mmap
) {
1700 ptr
= cached_dsentry
? ((char *)cached_dsentry
) - (padding_size
+ page_size
- MAGIC_SIZE_TO_REAL(0)) : NULL
;
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
);
1707 /* Preallocate memory for metadata + data. */
1708 ptr
= mmap(aligned_start
, page_size
+ alloc_length
+ padding_size
, magic_mmap_dsentry_header_prot
, MAP_ANONYMOUS
| MAP_PRIVATE
| (flags
& MAP_FIXED
), -1, 0);
1710 /* Remap the data part the way the caller wants us to. */
1711 if (ptr
!= MAP_FAILED
) {
1712 new_start
= ((char *)ptr
) + page_size
;
1713 new_ptr
= mmap(new_start
, length
, prot
, flags
| MAP_FIXED
, fd
, offset
);
1714 if (new_ptr
== MAP_FAILED
) {
1715 munmap(ptr
, page_size
+ alloc_length
+ padding_size
);
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);
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
);
1737 data_ptr
= MAP_FAILED
;
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
;
1746 data_ptr
= MAP_FAILED
;
1750 MAGIC_MEM_WRAPPER_END();
1755 /*===========================================================================*
1757 *===========================================================================*/
1758 PUBLIC
void *magic_mmap(__MA_ARGS__
void *start
, size_t length
, int prot
, int flags
,
1759 int fd
, off_t offset
)
1761 return magic_mmap_positioned(__MA_VALUES__ start
, length
, prot
, flags
, fd
, offset
, NULL
);
1764 /*===========================================================================*
1766 *===========================================================================*/
1767 PUBLIC
int magic_munmap(__MD_ARGS__
void *data_ptr
, size_t length
)
1770 void *ptr
, *aligned_ptr
;
1771 struct _magic_sentry
*sentry
;
1772 size_t alloc_length
, old_size
;
1773 size_t page_size
= MAGIC_PAGE_SIZE
;
1775 MAGIC_MEM_WRAPPER_BEGIN();
1778 ptr
= MAGIC_PTR_FROM_DATA(data_ptr
);
1780 /* Check for legitimate non-indexed chunks of memory and skip. */
1781 if((!magic_libcommon_active
|| !MAGIC_USE_DYN_MEM_WRAPPERS
)
1782 && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr
))) {
1783 MAGIC_MEM_WRAPPER_END();
1784 return munmap(data_ptr
, length
);
1787 sentry
= MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr
));
1788 aligned_ptr
= ((char*)data_ptr
) - page_size
;
1789 MAGIC_MEM_PRINTF("magic_munmap: magic_munmap(0x%08x, %d) / unmap(0x%08x, %d)\n", (unsigned) data_ptr
, length
, (unsigned) aligned_ptr
, page_size
+length
);
1790 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
), MAGIC_STATE_MAP
) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1791 old_size
= MAGIC_DSENTRY_TO_SENTRY(MAGIC_PTR_TO_DSENTRY(ptr
))->type
->size
;
1792 alloc_length
= length
+ (length
% page_size
== 0 ? 0 : page_size
-(length
% page_size
));
1794 if(alloc_length
!= old_size
) {
1795 assert(alloc_length
>= old_size
&& "Partial unmapping not supported!");
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!");
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();
1818 MAGIC_MEM_WRAPPER_END();
1823 /*===========================================================================*
1825 *===========================================================================*/
1826 PUBLIC
int magic_brk(__MA_ARGS__
void *addr
)
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);
1842 magic_free(__MD_VALUES_DEFAULT__ addr
);
1849 /*===========================================================================*
1851 *===========================================================================*/
1852 PUBLIC
void *magic_sbrk(__MA_ARGS__
intptr_t increment
)
1856 if(increment
== 0) {
1857 MAGIC_MEM_WRAPPER_LBLOCK( ptr
= sbrk(0); );
1860 MAGIC_MEM_PRINTF("magic_sbrk: Warning: somebody calling magic_sbrk(), resorting to magic_malloc()!");
1861 ptr
= magic_malloc(__MA_VALUES__ increment
);
1868 /*===========================================================================*
1870 *===========================================================================*/
1871 PUBLIC
void *magic_shmat(__MA_ARGS__
int shmid
, const void *shmaddr
, int shmflg
)
1873 void *ptr
, *data_ptr
, *aligned_shmaddr
, *aligned_ptr
;
1874 void *new_ptr
, *new_shmaddr
;
1876 struct shmid_ds buf
;
1878 size_t page_size
= MAGIC_PAGE_SIZE
;
1880 MAGIC_MEM_WRAPPER_BEGIN();
1882 assert(!(shmflg
& SHM_REMAP
) && "Linux-specific SHM_REMAP not supported!");
1883 ret
= shmctl(shmid
, IPC_STAT
, &buf
);
1885 MAGIC_MEM_WRAPPER_END();
1888 size
= buf
.shm_segsz
;
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
;
1895 shmaddr
= (void *) ((((unsigned long)shmaddr
) / shmlba
) * shmlba
);
1898 /* Preallocate memory for metadata + data. */
1899 aligned_shmaddr
= shmaddr
? ((char *)shmaddr
) - page_size
: NULL
;
1900 flags
= MAP_ANONYMOUS
| MAP_PRIVATE
| (aligned_shmaddr
? MAP_FIXED
: 0);
1901 ptr
= mmap(aligned_shmaddr
, page_size
+ size
, magic_mmap_dsentry_header_prot
, flags
, -1, 0);
1903 /* Remap the data part the way the caller wants us to. */
1904 if (ptr
!= MAP_FAILED
) {
1905 new_shmaddr
= ((char *)ptr
) + page_size
;
1906 munmap(new_shmaddr
, size
);
1907 new_ptr
= shmat(shmid
, new_shmaddr
, shmflg
);
1908 if(new_ptr
== (void *) -1) {
1909 munmap(ptr
, page_size
);
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);
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;
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
;
1934 data_ptr
= (void *) -1;
1938 MAGIC_MEM_WRAPPER_END();
1943 /*===========================================================================*
1945 *===========================================================================*/
1946 PUBLIC
int magic_shmdt(__MD_ARGS__
const void *data_ptr
)
1949 void *ptr
, *aligned_ptr
;
1950 size_t page_size
= MAGIC_PAGE_SIZE
;
1952 MAGIC_MEM_WRAPPER_LBEGIN();
1955 ptr
= MAGIC_PTR_FROM_DATA(data_ptr
);
1957 /* Check for legitimate non-indexed chunks of memory and skip. */
1958 if ((!magic_libcommon_active
|| !MAGIC_USE_DYN_MEM_WRAPPERS
)
1959 && !MAGIC_DSENTRY_MNUM_OK(MAGIC_PTR_TO_DSENTRY(ptr
))) {
1960 MAGIC_MEM_WRAPPER_LEND();
1961 return shmdt(data_ptr
);
1964 aligned_ptr
= ((char*)data_ptr
) - page_size
;
1965 MAGIC_MEM_PRINTF("magic_shmdt: magic_shmdt(0x%08x) / shmdt(0x%08x)\n", (unsigned) data_ptr
, (unsigned) aligned_ptr
);
1966 assert(magic_check_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
), MAGIC_STATE_SHM
) && "XXX Bad magic dsentry: corruption or memory not allocated from a magic wrapper?");
1967 ret
= shmdt(data_ptr
);
1969 magic_destroy_dsentry(MAGIC_PTR_TO_DSENTRY(ptr
), NULL
);
1970 munmap(aligned_ptr
, page_size
);
1978 MAGIC_MEM_WRAPPER_LEND();
1983 /*===========================================================================*
1985 *===========================================================================*/
1986 PUBLIC
void *magic_mmap64(__MA_ARGS__
void *start
, size_t length
, int prot
, int flags
,
1987 int fd
, off_t pgoffset
)
1989 void *ptr
, *data_ptr
, *aligned_start
, *aligned_ptr
;
1990 void *new_ptr
, *new_start
;
1991 int dsentry_flags
= MAGIC_STATE_MAP
;
1992 size_t alloc_length
;
1993 size_t page_size
= MAGIC_PAGE_SIZE
;
1995 MAGIC_MEM_WRAPPER_BEGIN();
1997 if (flags
& MAP_FIXED
) {
1998 /* Allow safe overmapping. */
1999 struct _magic_sentry
*sentry
= magic_sentry_lookup_by_range(start
, NULL
);
2000 if (sentry
&& sentry
== magic_sentry_lookup_by_range((char*)start
+length
-1, NULL
))
2001 return mmap64(start
, length
, prot
, flags
, fd
, pgoffset
);
2003 assert(!(flags
& MAP_FIXED
) && "MAP_FIXED may override existing mapping, currently not implemented!");
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
);
2012 /* Preallocate memory for metadata + data. */
2013 ptr
= mmap64(aligned_start
, page_size
+alloc_length
, magic_mmap_dsentry_header_prot
, MAP_ANONYMOUS
|MAP_PRIVATE
|(flags
& MAP_FIXED
), -1, 0);
2015 /* Remap the data part the way the caller wants us to. */
2016 if(ptr
!= MAP_FAILED
) {
2017 new_start
= ((char*)ptr
) + page_size
;
2018 new_ptr
= mmap64(new_start
, length
, prot
, flags
|MAP_FIXED
, fd
, pgoffset
);
2019 if(new_ptr
== MAP_FAILED
) {
2020 munmap(ptr
, page_size
+alloc_length
);
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);
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
);
2043 data_ptr
= MAP_FAILED
;
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
;
2050 data_ptr
= MAP_FAILED
;
2054 MAGIC_MEM_WRAPPER_END();
2060 /*===========================================================================*
2061 * magic_vm_map_cacheblock *
2062 *===========================================================================*/
2063 PUBLIC
void *magic_vm_map_cacheblock(__MA_ARGS__ dev_t dev
, off_t dev_offset
,
2064 ino_t ino
, off_t ino_offset
, u32_t
*flags
, int length
)
2066 void *ptr
, *data_ptr
, *aligned_ptr
;
2067 int dsentry_flags
= MAGIC_STATE_MAP
;
2068 size_t alloc_length
;
2069 size_t page_size
= MAGIC_PAGE_SIZE
;
2071 MAGIC_MEM_WRAPPER_BEGIN();
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. */
2082 ptr
= ((char*)ptr
) + page_size
- MAGIC_SIZE_TO_REAL(0);
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
);
2094 data_ptr
= MAP_FAILED
;
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
;
2102 data_ptr
= MAP_FAILED
;
2106 MAGIC_MEM_WRAPPER_END();
2111 /*===========================================================================*
2112 * magic_nested_mmap *
2113 *===========================================================================*/
2115 magic_nested_mmap(void *start
, size_t length
, int prot
, int flags
,
2116 int fd
, off_t offset
)
2121 ptr
= mmap(start
, length
, prot
, flags
, fd
, offset
);
2123 if (ptr
!= MAP_FAILED
) {
2124 MAGIC_MEM_PRINTF("MAGIC: nested mmap (%p, %zu)\n", ptr
,
2128 * Find a free entry. We do not expect the malloc code to have
2129 * more than two areas mapped at any time.
2131 for (i
= 0; i
< MAGIC_UNMAP_MEM_ENTRIES
; i
++)
2132 if (_magic_unmap_mem
[i
].length
== 0)
2134 assert(i
< MAGIC_UNMAP_MEM_ENTRIES
);
2136 /* Store the mapping in this entry. */
2137 _magic_unmap_mem
[i
].start
= ptr
;
2138 _magic_unmap_mem
[i
].length
= length
;
2144 /*===========================================================================*
2145 * magic_nested_munmap *
2146 *===========================================================================*/
2148 magic_nested_munmap(void *start
, size_t length
)
2152 r
= munmap(start
, length
);
2155 MAGIC_MEM_PRINTF("MAGIC: nested munmap (%p, %zu)\n", start
,
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
)
2163 assert(i
< MAGIC_UNMAP_MEM_ENTRIES
);
2165 /* Clear the entry. */
2166 _magic_unmap_mem
[i
].start
= NULL
;
2167 _magic_unmap_mem
[i
].length
= 0;