David van Moolenbroek b2ed49a5d8 libmagicrt: integrate into build system
The magic runtime library is now built as part of the regular build, if
the MKMAGIC=yes flag is passed to the build system.  The library has
been renamed from "magic" to "magicrt" to resolve a name clash with BSD
file(1)'s libmagic.  All its level-5 LLVM warnings have been resolved.
 The final library, "libmagicrt.bcc", is now stored in the destination
library directory rather than in the source tree.

Change-Id: Iebd4b93a2cafbb59f95d938ad1edb8b4f6e729f6
2016-01-13 20:32:32 +01:00

2595 lines
96 KiB
C

#include <magic.h>
#include <magic_mem.h>
#include <magic_asr.h>
#include <magic_eval.h>
#include <magic_analysis.h>
#include <magic_splay_tree.h>
#include <stdarg.h>
#if MAGIC_MEM_USAGE_OUTPUT_CTL
#include <common/util/time.h>
#endif
/* Workaround for extern-only structs. */
#ifndef __MINIX
#include <stdio.h>
EXTERN FILE *stdout;
PUBLIC FILE **UNUSED(_____magic_instr_FILE_unused) = &stdout;
#include <ncurses.h>
PUBLIC WINDOW *UNUSED(_____magic_instr_WINDOW_unused);
#endif
#include <netinet/in.h>
PUBLIC struct in6_addr *UNUSED(_____magic_instr_in6_addr_unused);
/* Magic printf. */
MAGIC_VAR printf_ptr_t _magic_printf = MAGIC_PRINTF_DEFAULT;
/* Magic lock primitives. */
PUBLIC magic_lock_t magic_dsentry_lock = NULL;
PUBLIC magic_unlock_t magic_dsentry_unlock = NULL;
PUBLIC void *magic_dsentry_lock_args = NULL;
PUBLIC void *magic_dsentry_unlock_args = NULL;
PUBLIC magic_lock_t magic_dfunction_lock = NULL;
PUBLIC magic_unlock_t magic_dfunction_unlock = NULL;
PUBLIC void *magic_dfunction_lock_args = NULL;
PUBLIC void *magic_dfunction_unlock_args = NULL;
PUBLIC magic_lock_t magic_dsodesc_lock = NULL;
PUBLIC magic_unlock_t magic_dsodesc_unlock = NULL;
PUBLIC void *magic_dsodesc_lock_args = NULL;
PUBLIC void *magic_dsodesc_unlock_args = NULL;
PUBLIC magic_lock_t magic_mpdesc_lock = NULL;
PUBLIC magic_unlock_t magic_mpdesc_unlock = NULL;
PUBLIC void *magic_mpdesc_lock_args = NULL;
PUBLIC void *magic_mpdesc_unlock_args = NULL;
/* Magic vars references. */
MAGIC_VAR struct _magic_vars_t _magic_vars_buff = {
/* Address Space Randomization (ASRPass) */
0, /* asr_seed */
0, /* asr_heap_map_do_permutate */
0, /* asr_heap_max_offset */
0, /* asr_heap_max_padding */
0, /* asr_map_max_offset_pages */
0, /* asr_map_max_padding_pages */
/* Runtime flags. */
0, /* no_mem_inst */
/* Magic type array. */
NULL, /* types */
0, /* types_num */
0, /* types_next_id */
/* Magic function array. */
NULL, /* functions */
0, /* functions_num */
0, /* functions_next_id */
/* Magic state entry array. */
NULL, /* sentries */
0, /* sentries_num */
0, /* sentries_str_num */
0, /* sentries_next_id */
/* Magic dynamic state index array. */
NULL, /* dsindexes */
0, /* dsindexes_num */
/* Magic dynamic state entry list. */
NULL, /* first_dsentry */
0, /* num_dead_sentries */
0, /* size_dead_dsentries */
/* Magic memory pool dynamic state entry list. */
NULL, /* first_mempool_dsentry */
/* Magic dynamic function list. */
NULL, /* first_dfunction */
NULL, /* last_dfunction */
0, /* dfunctions_num */
/* Magic SO library descriptor list. */
NULL, /* first_sodesc */
NULL, /* last_sodesc */
0, /* sodescs_num */
/* Magic DSO library descriptor list. */
NULL, /* first_dsodesc */
NULL, /* last_dsodesc */
0, /* dsodescs_num */
/* Magic stack-related variables. */
NULL, /* first_stack_dsentry */
NULL, /* last_stack_dsentry */
/* Magic memory ranges */
{ (void*) ULONG_MAX, (void*) 0 }, /* *null_range[2] */
{0,0}, /* *data_range[2] */
{0,0}, /* *heap_range[2] */
{0,0}, /* *map_range[2] */
{0,0}, /* *shm_range[2] */
{0,0}, /* *stack_range[2] */
{0,0}, /* *text_range[2] */
{0,0}, /* *sentry_range[2] */
{0,0}, /* *function_range[2] */
{0,0}, /* *dfunction_range[2] */
NULL, /* *heap_start */
NULL, /* *heap_end */
1, /* update_dsentry_ranges */
1, /* update_dfunction_ranges */
#ifdef __MINIX
{ { NULL, 0 } }, /* unmap_mem */
#endif
NULL, /* sentry_rl_buff */
0, /* sentry_rl_buff_offset */
0, /* sentry_rl_buff_size */
NULL, /* sentry_rl_index */
NULL, /* sentry_hash_buff */
0, /* sentry_hash_buff_offset */
0, /* sentry_hash_buff_size */
NULL, /* sentry_hash_head */
NULL, /* function_hash_buff */
0, /* function_hash_buff_offset */
0, /* function_hash_buff_size */
NULL, /* function_hash_head */
0 /* fake_malloc */
};
PUBLIC struct _magic_vars_t *_magic_vars = &_magic_vars_buff;
/* Magic void ptr and array (force at the least 1 void* and 1 void array in the list of globals). */
PUBLIC void* MAGIC_VOID_PTR = NULL;
PUBLIC char MAGIC_VOID_ARRAY[1];
/* Magic special types. */
MAGIC_VAR struct _magic_type *MAGIC_VOID_PTR_TYPE = NULL;
MAGIC_VAR struct _magic_type *MAGIC_VOID_PTR_INT_CAST_TYPE = NULL;
MAGIC_VAR struct _magic_type *MAGIC_VOID_ARRAY_TYPE = NULL;
MAGIC_VAR struct _magic_type *MAGIC_PTRINT_TYPE = NULL;
MAGIC_VAR struct _magic_type *MAGIC_PTRINT_ARRAY_TYPE = NULL;
/* Magic annotations. */
MAGIC_VAR VOLATILE int MAGIC_CALL_ANNOTATION_VAR;
/* Magic status variables. */
PUBLIC int magic_init_done = 0;
PUBLIC int magic_libcommon_active = 0;
PUBLIC int magic_lookup_nested_dsentries = 1;
PUBLIC int magic_allow_dead_dsentries = MAGIC_ALLOW_DEAD_DSENTRIES_DEFAULT;
PUBLIC int magic_ignore_dead_dsentries = 0;
PUBLIC int magic_mmap_dsentry_header_prot = PROT_READ | PROT_WRITE;
MAGIC_VAR int _magic_enabled = 0;
MAGIC_VAR int _magic_checkpoint_enabled = 0;
MAGIC_VAR int _magic_lazy_checkpoint_enabled = 0;
/* Magic out-of-band dsentries. */
PUBLIC struct _magic_obdsentry _magic_obdsentries[MAGIC_MAX_OBDSENTRIES];
/* Pool management data. */
PUBLIC struct _magic_mpdesc _magic_mpdescs[MAGIC_MAX_MEMPOOLS];
/* Magic page size. */
PUBLIC unsigned long magic_sys_pagesize = 0;
/* Private variables. */
PUBLIC int magic_type_str_print_style = MAGIC_TYPE_STR_PRINT_STYLE_DEFAULT;
PRIVATE THREAD_LOCAL const struct _magic_type* magic_nested_types[MAGIC_MAX_RECURSIVE_TYPES] = {0};
PRIVATE THREAD_LOCAL const struct _magic_type* magic_nested_types2[MAGIC_MAX_RECURSIVE_TYPES] = {0};
PRIVATE THREAD_LOCAL unsigned magic_level = 0;
PRIVATE THREAD_LOCAL unsigned magic_counter;
PRIVATE THREAD_LOCAL struct _magic_dsentry magic_dsentry_buff;
PRIVATE THREAD_LOCAL struct _magic_dfunction magic_dfunction_buff;
/* Magic default stubs. */
PUBLIC struct _magic_type magic_default_type = {
0, "", NULL, 0, "", 0, 0, NULL, NULL, NULL, NULL, NULL, MAGIC_TYPE_OPAQUE, 0, 0, NULL
};
PUBLIC struct _magic_dsentry magic_default_dsentry = {
MAGIC_DSENTRY_MNUM, /* magic_number */
"", /* parent_name */
{ 0 }, /* name_ext_buff */
{ 0, "", NULL, MAGIC_STATE_DYNAMIC, NULL, NULL }, /* sentry */
{ 0, "", NULL, 0, "", 0, 0, NULL, NULL, NULL, NULL, NULL, MAGIC_TYPE_ARRAY, MAGIC_TYPE_IS_ROOT|MAGIC_TYPE_DYNAMIC, 0, NULL }, /* type */
{ NULL }, /* type_array */
#if MAGIC_DSENTRY_ALLOW_PREV
NULL, /* prev */
#endif
NULL, /* next */
NULL, /* next_mpool */
NULL, /* next_mblock */
#ifndef __MINIX
NULL, /* next_sobject */
NULL, /* sobject_base_addr */
#endif
NULL, /* ext */
MAGIC_DSENTRY_MSTATE_ALIVE, /* magic_state */
{ { 0, 0 } }, /* alloc_flags */
0 /* site_id */
};
PUBLIC struct _magic_dfunction magic_default_dfunction = {
MAGIC_DFUNCTION_MNUM,
"",
{ 0, "", NULL, MAGIC_STATE_DYNAMIC|MAGIC_STATE_TEXT|MAGIC_STATE_CONSTANT, NULL },
NULL,
NULL
};
PUBLIC struct _magic_type magic_default_ret_addr_type = {
0, "", NULL, 0, "", sizeof(void*), 1, NULL, NULL, NULL, NULL, NULL, MAGIC_TYPE_POINTER, MAGIC_TYPE_IS_ROOT|MAGIC_TYPE_DYNAMIC|MAGIC_TYPE_INT_CAST|MAGIC_TYPE_STRICT_VALUE_SET, 0, NULL
};
/* Magic code reentrant flag. */
PRIVATE int magic_reentrant = 1;
/*===========================================================================*
* _magic_vars_addr *
*===========================================================================*/
void *_magic_vars_addr()
{
return _magic_vars;
}
/*===========================================================================*
* _magic_vars_size *
*===========================================================================*/
size_t _magic_vars_size()
{
return sizeof(struct _magic_vars_t);
}
/*===========================================================================*
* magic_null_printf *
*===========================================================================*/
PUBLIC int magic_null_printf(const char *format, ...)
{
return 0;
}
#ifndef __MINIX
/*===========================================================================*
* magic_err_printf *
*===========================================================================*/
PUBLIC int magic_err_printf(const char *format, ...)
{
va_list va;
int ret;
va_start(va, format);
ret = vfprintf(stderr, format, va);
va_end(va);
return ret;
}
#endif
/*===========================================================================*
* magic_set_printf *
*===========================================================================*/
PUBLIC void magic_set_printf(printf_ptr_t func_ptr)
{
assert(func_ptr);
_magic_printf = func_ptr;
}
/*===========================================================================*
* magic_get_printf *
*===========================================================================*/
PUBLIC printf_ptr_t magic_get_printf(void)
{
return _magic_printf;
}
/*===========================================================================*
* magic_reentrant_enable *
*===========================================================================*/
PUBLIC void magic_reentrant_enable(void)
{
magic_reentrant = 1;
}
/*===========================================================================*
* magic_reentrant_disable *
*===========================================================================*/
PUBLIC void magic_reentrant_disable(void)
{
magic_reentrant = 0;
}
/*===========================================================================*
* magic_assert_failed *
*===========================================================================*/
PUBLIC void __dead magic_assert_failed(const char *assertion, const char *file,
const char *function, const int line)
{
_magic_printf("Assertion '%s' failed in file %s, function %s(), line %d, pid %d\n",
assertion, file, function, line, getpid());
abort();
}
/*===========================================================================*
* magic_get_sys_pagesize *
*===========================================================================*/
PUBLIC unsigned long magic_get_sys_pagesize()
{
if(!magic_sys_pagesize) {
magic_sys_pagesize = SYS_PAGESIZE;
}
return magic_sys_pagesize;
}
/*===========================================================================*
* magic_dsentry_set_lock_primitives *
*===========================================================================*/
PUBLIC void magic_dsentry_set_lock_primitives(magic_lock_t lock,
magic_unlock_t unlock, void *lock_args, void *unlock_args)
{
assert(lock && unlock);
magic_dsentry_lock = lock;
magic_dsentry_unlock = unlock;
magic_dsentry_lock_args = lock_args;
magic_dsentry_unlock_args = unlock_args;
}
/*===========================================================================*
* magic_dfunction_set_lock_primitives *
*===========================================================================*/
PUBLIC void magic_dfunction_set_lock_primitives(magic_lock_t lock,
magic_unlock_t unlock, void *lock_args, void *unlock_args)
{
assert(lock && unlock);
magic_dfunction_lock = lock;
magic_dfunction_unlock = unlock;
magic_dfunction_lock_args = lock_args;
magic_dfunction_unlock_args = unlock_args;
}
/*===========================================================================*
* magic_dsodesc_set_lock_primitives *
*===========================================================================*/
PUBLIC void magic_dsodesc_set_lock_primitives(magic_lock_t lock,
magic_unlock_t unlock, void *lock_args, void *unlock_args)
{
assert(lock && unlock);
magic_dsodesc_lock = lock;
magic_dsodesc_unlock = unlock;
magic_dsodesc_lock_args = lock_args;
magic_dsodesc_unlock_args = unlock_args;
}
/*===========================================================================*
* magic_mpdesc_set_lock_primitives *
*===========================================================================*/
PUBLIC void magic_mpdesc_set_lock_primitives(magic_lock_t lock,
magic_unlock_t unlock, void *lock_args, void *unlock_args)
{
assert(lock && unlock);
magic_mpdesc_lock = lock;
magic_mpdesc_unlock = unlock;
magic_mpdesc_lock_args = lock_args;
magic_mpdesc_unlock_args = unlock_args;
}
/*===========================================================================*
* magic_types_init *
*===========================================================================*/
PRIVATE void magic_types_init()
{
static struct _magic_type _magic_void_ptr_type_buff;
static struct _magic_type _magic_void_array_type_buff;
static struct _magic_type *_magic_void_array_type_contained_types[1];
static struct _magic_type _magic_ptrint_type_buff;
static const char* _magic_ptrint_type_name = "ptrint";
static char _magic_ptrint_type_str_buff[8];
static struct _magic_type _magic_ptrint_array_type_buff;
static struct _magic_type *_magic_ptrint_array_type_contained_types[1];
assert(MAGIC_VOID_PTR_TYPE);
assert(MAGIC_VOID_PTR_TYPE->size == sizeof(void*));
assert(MAGIC_VOID_TYPE->size == sizeof(char));
MAGIC_VOID_PTR_INT_CAST_TYPE = &_magic_void_ptr_type_buff;
*MAGIC_VOID_PTR_INT_CAST_TYPE = *MAGIC_VOID_PTR_TYPE;
MAGIC_VOID_PTR_INT_CAST_TYPE->flags |= MAGIC_TYPE_INT_CAST;
MAGIC_VOID_ARRAY_TYPE = &_magic_void_array_type_buff;
*MAGIC_VOID_ARRAY_TYPE = magic_default_type;
MAGIC_TYPE_ARRAY_CREATE_FROM_N(MAGIC_VOID_ARRAY_TYPE, MAGIC_VOID_TYPE,
_magic_void_array_type_contained_types, 1);
MAGIC_PTRINT_TYPE = &_magic_ptrint_type_buff;
*MAGIC_PTRINT_TYPE = magic_default_type;
MAGIC_TYPE_INT_CREATE(MAGIC_PTRINT_TYPE, MAGIC_VOID_PTR_TYPE->size,
_magic_ptrint_type_name, _magic_ptrint_type_str_buff);
MAGIC_PTRINT_ARRAY_TYPE = &_magic_ptrint_array_type_buff;
*MAGIC_PTRINT_ARRAY_TYPE = magic_default_type;
MAGIC_TYPE_ARRAY_CREATE_FROM_N(MAGIC_PTRINT_ARRAY_TYPE, MAGIC_PTRINT_TYPE,
_magic_ptrint_array_type_contained_types, 1);
}
/*===========================================================================*
* magic_data_init *
*===========================================================================*/
MAGIC_FUNC void magic_data_init(void)
{
MAGIC_FUNC_BODY();
}
/*===========================================================================*
* magic_init *
*===========================================================================*/
PUBLIC void magic_init(void)
{
unsigned i;
if(magic_init_done || !_magic_enabled) {
return;
}
/* Initialize magic data structures first. */
magic_data_init();
/* Initialize asr support. */
magic_asr_init();
/* Initialize eval support. */
magic_eval_init();
/* Initialize magic obdsentries. */
memset(_magic_obdsentries, 0, MAGIC_MAX_OBDSENTRIES * sizeof(struct _magic_obdsentry));
/* Initialize memory pool descriptors. */
for (i = 0; i < MAGIC_MAX_MEMPOOLS; i++) {
snprintf(_magic_mpdescs[i].name, sizeof(_magic_mpdescs[i].name), "%s%d%s", MAGIC_MEMPOOL_NAME_PREFIX, i, MAGIC_ALLOC_NAME_SUFFIX);
}
/* Initialize special types. */
magic_types_init();
/* Initialize magic ranges. */
magic_ranges_init();
/* Perform stack-related initialization. */
magic_stack_init();
#if MAGIC_MEM_USAGE_OUTPUT_CTL
/* Initialize CPU frequency - used for timestamp logging. */
magic_cycles_per_ns = util_time_get_cycles_per_ns(1);
#endif
/* Checks. */
assert(magic_check_sentries() && "Bad sentries!");
assert(magic_check_dsentries_safe() && "Bad dsentries!");
/* All done. */
magic_init_done = 1;
}
/*===========================================================================*
* magic_do_check_dfunction *
*===========================================================================*/
PRIVATE INLINE int magic_do_check_dfunction(struct _magic_dfunction *dfunction, int flags)
{
struct _magic_function *function;
int is_mnum_ok, is_flags_ok, is_prev_ok, is_next_ok;
assert(dfunction && "NULL dfunction found!");
function = MAGIC_DFUNCTION_TO_FUNCTION(dfunction);
assert(function && "NULL function found!");
is_mnum_ok = MAGIC_DFUNCTION_MNUM_OK(dfunction);
if(!is_mnum_ok) {
return FALSE;
}
is_flags_ok = ((function->flags & flags) == flags) && (function->flags & MAGIC_STATE_DYNAMIC) && (MAGIC_STATE_REGION(function) & MAGIC_STATE_TEXT);
is_prev_ok = (dfunction->prev ? dfunction->prev->next && dfunction->prev->next == dfunction : dfunction == _magic_first_dfunction);
is_next_ok = (dfunction->next ? dfunction->next->prev && dfunction->next->prev == dfunction : dfunction == _magic_last_dfunction);
if(!is_flags_ok || !is_prev_ok || !is_next_ok) {
_magic_printf("magic_do_check_dfunction: bad dfunction, checks: %d %d %d\n", is_flags_ok, is_prev_ok, is_next_ok);
MAGIC_DFUNCTION_PRINT(dfunction, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
return FALSE;
}
return TRUE;
}
/*===========================================================================*
* magic_check_dfunction *
*===========================================================================*/
PUBLIC int magic_check_dfunction(struct _magic_dfunction *dfunction, int flags)
{
int check;
check = magic_do_check_dfunction(dfunction, flags);
if(!check) {
return FALSE;
}
#if MAGIC_CHECK_LEVEL == 2
check = magic_check_dfunctions();
if(!check) {
_magic_printf("magic_check_dfunction: bad other dfunction\n");
return FALSE;
}
#endif
return TRUE;
}
/*===========================================================================*
* magic_check_dfunctions *
*===========================================================================*/
PUBLIC int magic_check_dfunctions()
{
int magic_dfunctions_found = 0;
struct _magic_dfunction* dfunction = NULL;
struct _magic_function* function = NULL;
int ret, check = TRUE;
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
ret = magic_do_check_dfunction(dfunction, 0);
if(ret == FALSE) {
check = FALSE;
}
magic_dfunctions_found++;
);
if(magic_dfunctions_found != _magic_dfunctions_num) {
_magic_printf("magic_check_dfunctions: magic_dfunctions_found=%d != _magic_dfunctions_num%d\n", magic_dfunctions_found, _magic_dfunctions_num);
check = FALSE;
}
if(dfunction != _magic_last_dfunction) {
_magic_printf("magic_check_dfunctions: dfunction=0x%08x != _magic_last_dfunction=0x%08x\n", dfunction, _magic_last_dfunction);
check = FALSE;
}
return check;
}
/*===========================================================================*
* magic_check_dfunctions_safe *
*===========================================================================*/
PUBLIC int magic_check_dfunctions_safe()
{
int ret;
MAGIC_DFUNCTION_LOCK();
ret = magic_check_dfunctions();
MAGIC_DFUNCTION_UNLOCK();
return ret;
}
/*===========================================================================*
* magic_print_dfunction *
*===========================================================================*/
PUBLIC void magic_print_dfunction(struct _magic_dfunction *dfunction)
{
MAGIC_DFUNCTION_PRINT(dfunction, MAGIC_EXPAND_TYPE_STR);
}
/*===========================================================================*
* magic_print_dfunctions *
*===========================================================================*/
PUBLIC void magic_print_dfunctions()
{
int magic_dfunctions_found = 0;
struct _magic_dfunction* dfunction;
struct _magic_function* function;
_magic_printf("magic_print_dfunctions: Printing %d functions\n", _magic_dfunctions_num);
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
MAGIC_DFUNCTION_PRINT(dfunction, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
magic_dfunctions_found++;
);
if(magic_dfunctions_found != _magic_dfunctions_num) {
_magic_printf("magic_print_dfunctions: magic_dfunctions_found=%d != _magic_dfunctions_num%d\n", magic_dfunctions_found, _magic_dfunctions_num);
}
}
/*===========================================================================*
* magic_print_dfunctions_safe *
*===========================================================================*/
PUBLIC void magic_print_dfunctions_safe()
{
MAGIC_DFUNCTION_LOCK();
magic_print_dfunctions();
MAGIC_DFUNCTION_UNLOCK();
}
/*===========================================================================*
* magic_copy_dfunction *
*===========================================================================*/
PUBLIC void magic_copy_dfunction(struct _magic_dfunction *dfunction,
struct _magic_dfunction *dst_dfunction)
{
/* Raw copy. */
memcpy(dst_dfunction, dfunction, sizeof(struct _magic_dfunction));
}
/*===========================================================================*
* magic_print_dsindex *
*===========================================================================*/
PUBLIC void magic_print_dsindex(struct _magic_dsindex *dsindex)
{
MAGIC_DSINDEX_PRINT(dsindex, MAGIC_EXPAND_TYPE_STR);
}
/*===========================================================================*
* magic_print_dsindexes *
*===========================================================================*/
PUBLIC void magic_print_dsindexes()
{
int i;
struct _magic_dsindex* dsindex;
_magic_printf("magic_print_dsindexes: Printing %d indexes\n", _magic_dsindexes_num);
for(i=0;i<_magic_dsindexes_num;i++) {
dsindex = &_magic_dsindexes[i];
MAGIC_DSINDEX_PRINT(dsindex, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
}
}
/*===========================================================================*
* magic_do_check_dsentry *
*===========================================================================*/
PRIVATE INLINE int magic_do_check_dsentry(struct _magic_dsentry *dsentry, int flags)
{
struct _magic_sentry *sentry;
int is_mnum_ok, is_mstate_ok, is_flags_ok;
assert(dsentry && "NULL dsentry found!");
sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
assert(sentry && "NULL sentry found!");
is_mnum_ok = MAGIC_DSENTRY_MNUM_OK(dsentry);
if(!is_mnum_ok) {
_magic_printf("magic_do_check_dsentry: bad ~mnum %08x\n", ~(dsentry->magic_number));
return FALSE;
}
is_mstate_ok = MAGIC_DSENTRY_MSTATE_OK(dsentry);
is_flags_ok = ((sentry->flags & flags) == flags) && (sentry->flags & MAGIC_STATE_DYNAMIC) && MAGIC_STATE_REGION(sentry);
if(!is_mstate_ok || !is_flags_ok) {
_magic_printf("magic_do_check_dsentry: bad dsentry, checks: %d %d\n", is_mstate_ok, is_flags_ok);
MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
return FALSE;
}
return TRUE;
}
/*===========================================================================*
* magic_check_dsentry *
*===========================================================================*/
PUBLIC int magic_check_dsentry(struct _magic_dsentry *dsentry, int flags)
{
#if MAGIC_CHECK_LEVEL >= 1
int check;
check = magic_do_check_dsentry(dsentry, flags);
if(!check) {
return FALSE;
}
#endif
#if MAGIC_CHECK_LEVEL == 2
check = magic_check_dsentries();
if(!check) {
_magic_printf("magic_check_dsentry: bad other dsentry\n");
return FALSE;
}
#endif
return TRUE;
}
/*===========================================================================*
* magic_check_dsentries *
*===========================================================================*/
PUBLIC int magic_check_dsentries()
{
struct _magic_dsentry *prev_dsentry, *dsentry;
struct _magic_sentry* sentry;
int ret, check = TRUE;
MAGIC_DSENTRY_NESTED_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
ret = magic_do_check_dsentry(dsentry, 0);
if(ret == FALSE) {
check = FALSE;
}
);
return check;
}
/*===========================================================================*
* magic_check_dsentries_safe *
*===========================================================================*/
PUBLIC int magic_check_dsentries_safe()
{
int ret;
MAGIC_DSENTRY_LOCK();
ret = magic_check_dsentries();
MAGIC_DSENTRY_UNLOCK();
return ret;
}
/*===========================================================================*
* magic_print_dsentry *
*===========================================================================*/
PUBLIC void magic_print_dsentry(struct _magic_dsentry *dsentry)
{
MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
}
/*===========================================================================*
* magic_print_dsentries *
*===========================================================================*/
PUBLIC void magic_print_dsentries()
{
struct _magic_dsentry *prev_dsentry, *dsentry;
struct _magic_sentry* sentry;
int magic_dsentries_num = 0;
_magic_printf("magic_print_dsentries: Printing entries\n");
MAGIC_DSENTRY_NESTED_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
magic_dsentries_num++;
);
_magic_printf("magic_print_dsentries: %d entries found\n", magic_dsentries_num);
}
/*===========================================================================*
* magic_print_dsentries_safe *
*===========================================================================*/
PUBLIC void magic_print_dsentries_safe()
{
MAGIC_DSENTRY_LOCK();
magic_print_dsentries();
MAGIC_DSENTRY_UNLOCK();
}
/*===========================================================================*
* magic_copy_dsentry *
*===========================================================================*/
PUBLIC void magic_copy_dsentry(struct _magic_dsentry *dsentry,
struct _magic_dsentry *dst_dsentry)
{
struct _magic_sentry *sentry;
/* Raw copy. */
memcpy(dst_dsentry, dsentry, sizeof(struct _magic_dsentry));
/* Adjust pointers. */
sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
if(sentry->type == &dsentry->type) {
MAGIC_DSENTRY_TO_SENTRY(dst_dsentry)->type = &dst_dsentry->type;
if(sentry->type->contained_types == dsentry->type_array) {
MAGIC_DSENTRY_TO_SENTRY(dst_dsentry)->type->contained_types = dst_dsentry->type_array;
}
}
}
/*===========================================================================*
* magic_print_sodesc *
*===========================================================================*/
PUBLIC void magic_print_sodesc(struct _magic_sodesc *sodesc)
{
MAGIC_SODESC_PRINT(sodesc);
}
/*===========================================================================*
* magic_print_sodescs *
*===========================================================================*/
PUBLIC void magic_print_sodescs()
{
int magic_sodescs_found = 0;
struct _magic_sodesc* sodesc;
_magic_printf("magic_print_sodescs: Printing %d sodescs\n", _magic_sodescs_num);
MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
MAGIC_SODESC_PRINT(sodesc);
_magic_printf("\n");
magic_sodescs_found++;
);
if(magic_sodescs_found != _magic_sodescs_num) {
_magic_printf("magic_print_sodescs: magic_sodescs_found=%d != _magic_sodescs_num%d\n", magic_sodescs_found, _magic_sodescs_num);
}
}
/*===========================================================================*
* magic_print_dsodesc *
*===========================================================================*/
PUBLIC void magic_print_dsodesc(struct _magic_dsodesc *dsodesc)
{
MAGIC_DSODESC_PRINT(dsodesc);
}
/*===========================================================================*
* magic_print_dsodescs *
*===========================================================================*/
PUBLIC void magic_print_dsodescs()
{
int magic_dsodescs_found = 0;
struct _magic_dsodesc* dsodesc;
_magic_printf("magic_print_dsodescs: Printing %d dsodescs\n", _magic_dsodescs_num);
MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
MAGIC_DSODESC_PRINT(dsodesc);
_magic_printf("\n");
magic_dsodescs_found++;
);
if(magic_dsodescs_found != _magic_dsodescs_num) {
_magic_printf("magic_print_dsodescs: magic_dsodescs_found=%d != _magic_dsodescs_num%d\n", magic_dsodescs_found, _magic_dsodescs_num);
}
}
/*===========================================================================*
* magic_print_dsodescs_safe *
*===========================================================================*/
PUBLIC void magic_print_dsodescs_safe()
{
MAGIC_DSODESC_LOCK();
magic_print_dsodescs();
MAGIC_DSODESC_UNLOCK();
}
/*===========================================================================*
* magic_print_sections *
*===========================================================================*/
PUBLIC void magic_print_sections(void)
{
_magic_printf("magic_print_sections: data=[0x%08x;0x%08x], ro=[0x%08x;0x%08x], text=[0x%08x;0x%08x], st_data=[0x%08x;0x%08x], st_ro=[0x%08x;0x%08x], st_text=[0x%08x;0x%08x]",
(unsigned long) MAGIC_DATA_SECTION_START, (unsigned long) MAGIC_DATA_SECTION_END,
(unsigned long) MAGIC_DATA_RO_SECTION_START, (unsigned long) MAGIC_DATA_RO_SECTION_END,
(unsigned long) MAGIC_TEXT_SECTION_START, (unsigned long) MAGIC_TEXT_SECTION_END,
(unsigned long) MAGIC_ST_DATA_SECTION_START, (unsigned long) MAGIC_ST_DATA_SECTION_END,
(unsigned long) MAGIC_ST_DATA_RO_SECTION_START, (unsigned long) MAGIC_ST_DATA_RO_SECTION_END,
(unsigned long) MAGIC_ST_TEXT_SECTION_START, (unsigned long) MAGIC_ST_TEXT_SECTION_END);
}
/*===========================================================================*
* magic_mempool_sentry_lookup_by_addr *
*===========================================================================*/
PUBLIC struct _magic_sentry* magic_mempool_sentry_lookup_by_range(void *addr, struct _magic_dsentry *dsentry_buff)
{
struct _magic_dsentry *prev_dsentry, *dsentry;
struct _magic_sentry* sentry;
struct _magic_sentry* entry = NULL;
void *start_address, *end_address;
MAGIC_DSENTRY_LOCK();
MAGIC_DSENTRY_MEMPOOL_ALIVE_ITER(_magic_first_mempool_dsentry, prev_dsentry, dsentry, sentry,
start_address = sentry->address;
end_address = (void*) (((char*)sentry->address) + sentry->type->size - 1);
if(MAGIC_ADDR_IS_WITHIN(addr, start_address, end_address)) {
if(dsentry_buff) {
magic_copy_dsentry(dsentry, dsentry_buff);
entry = MAGIC_DSENTRY_TO_SENTRY(dsentry_buff);
}
else {
entry = sentry;
}
break;
}
);
MAGIC_DSENTRY_UNLOCK();
return entry;
}
/*===========================================================================*
* magic_dsindex_lookup_by_name *
*===========================================================================*/
PUBLIC struct _magic_dsindex*
magic_dsindex_lookup_by_name(const char *parent_name, const char *name)
{
int i;
struct _magic_dsindex* index = NULL;
assert(parent_name && name);
/* Scan all the indexes and return the one matching the provided names. */
for(i=0;i<_magic_dsindexes_num;i++) {
if(!strcmp(_magic_dsindexes[i].parent_name, parent_name)
&& !strcmp(_magic_dsindexes[i].name, name)) {
index = &_magic_dsindexes[i];
break;
}
}
return index;
}
/*===========================================================================*
* magic_dsentry_prev_lookup *
*===========================================================================*/
PUBLIC struct _magic_dsentry* magic_dsentry_prev_lookup(struct _magic_dsentry* dsentry)
{
struct _magic_dsentry *prev_dsentry, *it_dsentry;
struct _magic_sentry *sentry;
int found = 0;
#if MAGIC_DSENTRY_ALLOW_PREV
return dsentry->prev;
#else
MAGIC_DSENTRY_ITER(_magic_first_dsentry, prev_dsentry, it_dsentry, sentry,
if(dsentry == it_dsentry) {
found = 1;
break;
}
);
if(!found) {
return (struct _magic_dsentry*) MAGIC_ENOPTR;
}
return prev_dsentry;
#endif
}
/*===========================================================================*
* magic_mempool_dsentry_prev_lookup *
*===========================================================================*/
PUBLIC struct _magic_dsentry* magic_mempool_dsentry_prev_lookup(struct _magic_dsentry* dsentry)
{
struct _magic_dsentry *prev_dsentry, *it_dsentry;
struct _magic_sentry *sentry;
int found = 0;
MAGIC_DSENTRY_MEMPOOL_ITER(_magic_first_mempool_dsentry, prev_dsentry, it_dsentry, sentry,
if(dsentry == it_dsentry) {
found = 1;
break;
}
);
if(!found) {
return (struct _magic_dsentry*) MAGIC_ENOPTR;
}
return prev_dsentry;
}
/*===========================================================================*
* magic_function_lookup_by_id *
*===========================================================================*/
PUBLIC struct _magic_function* magic_function_lookup_by_id(_magic_id_t id,
struct _magic_dfunction *dfunction_buff)
{
struct _magic_function* entry = NULL;
struct _magic_function* function;
struct _magic_dfunction* dfunction;
if(id <= 0) {
return NULL;
}
/* O(1) ID lookup for functions. */
#if MAGIC_LOOKUP_FUNCTION
if((int)id <= _magic_functions_num) {
return &_magic_functions[id - 1];
}
#endif
/* O(N) ID lookup for dfunctions. */
#if MAGIC_LOOKUP_DFUNCTION
MAGIC_DFUNCTION_LOCK();
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
if(function->id == id) {
if(dfunction_buff) {
magic_copy_dfunction(dfunction, dfunction_buff);
entry = MAGIC_DFUNCTION_TO_FUNCTION(dfunction_buff);
}
else {
entry = function;
}
break;
}
);
MAGIC_DFUNCTION_UNLOCK();
#endif
return entry;
}
/*===========================================================================*
* magic_function_lookup_by_addr *
*===========================================================================*/
PUBLIC struct _magic_function* magic_function_lookup_by_addr(void *addr,
struct _magic_dfunction *dfunction_buff)
{
int i;
struct _magic_function *entry = NULL;
struct _magic_function *function;
struct _magic_dfunction *dfunction;
#if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
if (magic_function_hash_head) {
return magic_function_lookup_by_addr_hash(addr, dfunction_buff);
}
#endif
/* Scan all the entries and return the one matching the provided address. */
#if MAGIC_LOOKUP_FUNCTION
if (MAGIC_ADDR_IS_IN_RANGE(addr, magic_function_range)) {
for (i = 0 ; i < _magic_functions_num ; i++) {
if (_magic_functions[i].address == addr) {
entry = &_magic_functions[i];
break;
}
}
}
#endif
#if MAGIC_LOOKUP_DFUNCTION
MAGIC_DFUNCTION_LOCK();
if(!MAGIC_ADDR_LOOKUP_USE_DFUNCTION_RANGES || magic_range_is_dfunction(addr)) {
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
if(function->address == addr) {
if(dfunction_buff) {
magic_copy_dfunction(dfunction, dfunction_buff);
entry = MAGIC_DFUNCTION_TO_FUNCTION(dfunction_buff);
}
else {
entry = function;
}
break;
}
);
}
MAGIC_DFUNCTION_UNLOCK();
#endif
return entry;
}
/*===========================================================================*
* magic_function_lookup_by_name *
*===========================================================================*/
PUBLIC struct _magic_function*
magic_function_lookup_by_name(const char *parent_name, const char *name)
{
int i;
struct _magic_function* entry = NULL;
/* Scan all the entries and return the one matching the provided name(s). */
#if MAGIC_LOOKUP_FUNCTION
for (i = 0 ; i < _magic_functions_num ; i++) {
if (!strcmp(_magic_functions[i].name, name)) {
if (!parent_name || !strcmp(MAGIC_FUNCTION_PARENT(&_magic_functions[i]), parent_name)) {
entry = &_magic_functions[i];
break;
}
}
}
#endif
return entry;
}
/*===========================================================================*
* magic_function_hash_insert *
*===========================================================================*/
PRIVATE void magic_function_hash_insert(struct _magic_function_hash **head,
struct _magic_function_hash *elem)
{
if (head != NULL) {
struct _magic_function_hash *tmp;
HASH_FIND_PTR(*head, &elem->key, tmp);
/* Skip inserting this function if an identical one already exists. */
if (tmp)
return;
}
/*
* **** START UTHASH SPECIFIC DEFINITIONS ****
*/
#undef uthash_malloc
#undef uthash_free
#define uthash_malloc(size) magic_function_hash_alloc(size)
#define uthash_free(addr, size) magic_function_hash_dealloc(addr, size)
/*
* Since we have a limited buffer, we need to stop bucket expansion when
* reaching a certain limit.
*/
#undef uthash_expand_fyi
#define uthash_expand_fyi(tbl) \
do { \
if (tbl->num_buckets == MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS) { \
_magic_printf("Warning! Function address hash maximum bucket " \
"number reached! Consider increasing " \
"MAGIC_FUNCTION_ADDR_EST_MAX_BUCKETS, unless you are " \
"comfortable with the current performance.\n"); \
tbl->noexpand = 1; \
} \
} while(0);
/*
* **** FINISH UTHASH SPECIFIC DEFINITIONS ****
*/
HASH_ADD_PTR(*head, key, elem);
/*
* **** START UTHASH DEFINITION REMOVAL ****
*/
#undef uthash_malloc
#undef uthash_free
#undef uthash_expand_fyi
/*
* **** FINISH UTHASH DEFINITION REMOVAL ****
*/
}
/*===========================================================================*
* magic_function_hash_build *
*===========================================================================*/
PUBLIC void magic_function_hash_build(void *buff, size_t buff_size)
{
/*
* XXX:
* Warning: this implementation is thread unsafe and also makes
* magic_function_lookup_by_addr thread unsafe!
*/
int i;
struct _magic_dfunction *dfunction;
struct _magic_function *function;
struct _magic_function_hash *function_hash, *head;
assert(buff && buff_size > 0);
magic_function_hash_buff = buff;
magic_function_hash_buff_offset = 0;
magic_function_hash_buff_size = buff_size;
head = NULL;
/* Add all the functions to the hash. */
#if MAGIC_LOOKUP_FUNCTION
for(i = 0 ; i < _magic_functions_num ; i++) {
function_hash = (struct _magic_function_hash *)
magic_function_hash_alloc(sizeof(struct _magic_function_hash));
function = &_magic_functions[i];
MAGIC_FUNCTION_TO_HASH_EL(function, function_hash);
magic_function_hash_insert(&head, function_hash);
}
#endif
/* Add all the dfunctions to the hash. */
#if MAGIC_LOOKUP_DFUNCTION
MAGIC_DFUNCTION_LOCK();
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
function_hash = (struct _magic_function_hash *)
magic_function_hash_alloc(sizeof(struct _magic_function_hash));
MAGIC_DFUNCTION_TO_HASH_EL(dfunction, function, function_hash);
magic_function_hash_insert(&head, function_hash);
);
MAGIC_DFUNCTION_UNLOCK();
#endif
magic_function_hash_head = (void *)head;
assert(magic_function_hash_head);
}
/*===========================================================================*
* magic_function_hash_destroy *
*===========================================================================*/
PUBLIC void magic_function_hash_destroy(void)
{
magic_function_hash_buff = NULL;
magic_function_hash_buff_offset = 0;
magic_function_hash_buff_size = 0;
magic_function_hash_head = NULL;
}
/*===========================================================================*
* magic_function_hash_estimate_buff_size *
*===========================================================================*/
PUBLIC size_t magic_function_hash_estimate_buff_size(int functions_num)
{
if (functions_num == 0) {
functions_num = _magic_dfunctions_num;
functions_num += _magic_functions_num;
}
return (functions_num * sizeof(struct _magic_function_hash)) +
MAGIC_FUNCTION_ADDR_HASH_OVERHEAD;
}
/*===========================================================================*
* magic_function_hash_alloc *
*===========================================================================*/
PUBLIC void* magic_function_hash_alloc(size_t size)
{
void *addr;
assert(magic_function_hash_buff);
assert(magic_function_hash_buff_offset + size <=
magic_function_hash_buff_size);
addr = (char*) magic_function_hash_buff + magic_function_hash_buff_offset;
magic_function_hash_buff_offset += size;
return addr;
}
/*===========================================================================*
* magic_function_hash_dealloc *
*===========================================================================*/
PUBLIC void magic_function_hash_dealloc(UNUSED(void *object), UNUSED(size_t sz))
{
return;
}
/*===========================================================================*
* magic_function_lookup_by_addr_hash *
*===========================================================================*/
PUBLIC struct _magic_function *magic_function_lookup_by_addr_hash(
void *addr, struct _magic_dfunction *dfunction_buff)
{
/*
* Warning: this implementation is thread unsafe!
*/
struct _magic_function_hash *res, *head;
head = (struct _magic_function_hash *) magic_function_hash_head;
HASH_FIND_PTR(head, &addr, res);
if (res == NULL)
return NULL;
if (MAGIC_STATE_FLAG(res->function, MAGIC_STATE_DYNAMIC) &&
dfunction_buff != NULL) {
magic_copy_dfunction(MAGIC_DFUNCTION_FROM_FUNCTION(res->function),
dfunction_buff);
}
return res->function;
}
/*===========================================================================*
* magic_type_lookup_by_name *
*===========================================================================*/
PUBLIC struct _magic_type* magic_type_lookup_by_name(const char *name)
{
int i;
unsigned int j;
struct _magic_type* entry = NULL;
/* Scan all the entries and return the one matching the provided name. */
#if MAGIC_LOOKUP_TYPE
for (i = 0 ; i < _magic_types_num ; i++) {
if (!strcmp(_magic_types[i].name, name)) {
entry = &_magic_types[i];
break;
}
if (_magic_types[i].names) {
for (j = 0 ; j < _magic_types[i].num_names ; j++) {
if (!strcmp(_magic_types[i].names[j], name)) {
entry = &_magic_types[i];
break;
}
}
if (entry) {
break;
}
}
}
#endif
return entry;
}
/*===========================================================================*
* magic_dsodesc_lookup_by_handle *
*===========================================================================*/
PUBLIC struct _magic_dsodesc* magic_dsodesc_lookup_by_handle(void *handle)
{
struct _magic_dsodesc* desc = NULL;
struct _magic_dsodesc* dsodesc;
/*
* Scan all the descriptors and return the one matching the provided handle.
* Note that there is no locking here. The caller has to explicitely call
* MAGIC_DSODESC_LOCK/UNLOCK before/after invoking this function.
*/
MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
if(dsodesc->handle == handle) {
desc = dsodesc;
break;
}
);
return desc;
}
/*===========================================================================*
* magic_print_function *
*===========================================================================*/
PUBLIC void magic_print_function(struct _magic_function *function)
{
MAGIC_FUNCTION_PRINT(function, MAGIC_EXPAND_TYPE_STR);
}
/*===========================================================================*
* magic_print_functions *
*===========================================================================*/
PUBLIC void magic_print_functions()
{
int i;
struct _magic_function* function;
_magic_printf("magic_print_functions: Printing %d entries\n", _magic_functions_num);
for(i=0;i<_magic_functions_num;i++) {
function = &_magic_functions[i];
MAGIC_FUNCTION_PRINT(function, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
}
}
/*===========================================================================*
* magic_print_type *
*===========================================================================*/
PUBLIC void magic_print_type(const struct _magic_type* type)
{
MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
}
/*===========================================================================*
* magic_print_types *
*===========================================================================*/
PUBLIC void magic_print_types()
{
int i;
struct _magic_type* type;
_magic_printf("magic_print_types: Printing %d types\n", _magic_types_num);
for(i=0;i<_magic_types_num;i++) {
type = &_magic_types[i];
MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
_magic_printf("\n");
}
}
/*===========================================================================*
* magic_type_str_set_print_style *
*===========================================================================*/
PUBLIC void magic_type_str_set_print_style(const int style)
{
magic_type_str_print_style = style;
}
/*===========================================================================*
* magic_type_str_get_print_style *
*===========================================================================*/
PUBLIC int magic_type_str_get_print_style()
{
return magic_type_str_print_style;
}
/*===========================================================================*
* magic_type_get_nesting_level *
*===========================================================================*/
PRIVATE INLINE int magic_type_get_nesting_level(const struct _magic_type* type,
int level)
{
int i;
int nesting_level = -1;
for(i=0;i<level;i++) {
if(magic_nested_types[i] == type) {
nesting_level = i;
break;
}
}
return nesting_level;
}
/*===========================================================================*
* magic_type_str_print *
*===========================================================================*/
PUBLIC void magic_type_str_print(const struct _magic_type* type)
{
int num_contained_types;
int is_empty_str = !type->type_str || !strcmp(type->type_str, "");
int type_has_name = type->name && strcmp(type->name, "");
int print_multi_names = (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_MULTI_NAMES) && MAGIC_TYPE_HAS_MULTI_NAMES(type);
int print_ptr_name = (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_MULTI_NAMES) && !MAGIC_TYPE_HAS_MULTI_NAMES(type) && type_has_name;
assert(magic_level < MAGIC_MAX_RECURSIVE_TYPES);
if(magic_level == 0) {
magic_counter = 0;
}
else if(magic_counter >= MAGIC_TYPE_STR_PRINT_MAX) {
_magic_printf("%%");
return;
}
else if(magic_level >= MAGIC_TYPE_STR_PRINT_MAX_LEVEL) {
_magic_printf("%%");
return;
}
if(MAGIC_TYPE_STR_PRINT_DEBUG) {
_magic_printf("Entering level %d...\n", magic_level);
}
if(type->type_id == MAGIC_TYPE_OPAQUE) {
_magic_printf("opaque");
magic_counter += strlen("opaque");
return;
}
num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
if(num_contained_types == 0) {
assert(!is_empty_str);
if((magic_type_str_print_style & (MAGIC_TYPE_STR_PRINT_LLVM_TYPES|MAGIC_TYPE_STR_PRINT_SOURCE_TYPES)) == (MAGIC_TYPE_STR_PRINT_LLVM_TYPES|MAGIC_TYPE_STR_PRINT_SOURCE_TYPES)) {
if(print_multi_names) {
_magic_printf("%s/", type->type_str);
magic_type_names_print(type);
magic_counter += strlen(type->type_str)+1+strlen(type->name)*type->num_names;
}
else {
_magic_printf("%s/%s", type->type_str, type->name);
magic_counter += strlen(type->type_str)+1+strlen(type->name);
}
}
else if(magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_LLVM_TYPES) {
_magic_printf(type->type_str);
magic_counter += strlen(type->type_str);
}
else if(magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_SOURCE_TYPES) {
if(print_multi_names) {
magic_type_names_print(type);
magic_counter += strlen(type->name)*type->num_names;
}
else {
_magic_printf(type->name);
magic_counter += strlen(type->name);
}
}
return;
}
if(type->type_id == MAGIC_TYPE_POINTER) {
int nesting_level = magic_type_get_nesting_level(type, magic_level);
if(nesting_level >= 0) {
_magic_printf("\\%d", magic_level - nesting_level);
magic_counter += 2;
return;
}
}
magic_nested_types[magic_level] = type;
magic_level++;
if(type->type_id == MAGIC_TYPE_POINTER) {
magic_type_str_print(type->contained_types[0]);
_magic_printf("*");
magic_counter += 1;
if(print_multi_names) {
_magic_printf("|");
magic_type_names_print(type);
magic_counter += 1+strlen(type->name)*type->num_names;
}
else if(print_ptr_name) {
_magic_printf("|");
_magic_printf("%s", type->name);
magic_counter += 1+strlen(type->name);
}
}
else if(type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR) {
int num_elements = type->num_child_types;
char start_sep = type->type_id == MAGIC_TYPE_ARRAY ? '[' : '<';
char end_sep = type->type_id == MAGIC_TYPE_ARRAY ? ']' : '>';
_magic_printf("%c", start_sep);
magic_counter += 1;
if(MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE)) {
_magic_printf(" (V) ");
magic_counter += 5;
}
if(num_elements) {
_magic_printf("%d x ", num_elements);
magic_counter += 5;
}
magic_type_str_print(type->contained_types[0]);
_magic_printf("%c", end_sep);
magic_counter += 1;
}
else if(type->type_id == MAGIC_TYPE_STRUCT || type->type_id == MAGIC_TYPE_UNION) {
int i;
int skip_struct = type->type_id == MAGIC_TYPE_STRUCT && (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_SKIP_STRUCTS);
int skip_union = type->type_id == MAGIC_TYPE_UNION && (magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_SKIP_UNIONS);
_magic_printf("{ ");
magic_counter += 2;
if(type->type_id == MAGIC_TYPE_UNION) {
_magic_printf("(U) ");
magic_counter += 4;
}
if(print_multi_names) {
_magic_printf("$");
magic_type_names_print(type);
_magic_printf(" ");
magic_counter += 2 + strlen(type->name)*type->num_names;
}
else {
_magic_printf("$%s ", strcmp(type->name, "") ? type->name : "ANONYMOUS");
magic_counter += 2 + strlen(strcmp(type->name, "") ? type->name : "ANONYMOUS");
}
assert(type->member_names);
if(!skip_struct && !skip_union) {
for(i=0;i<num_contained_types;i++) {
if(i > 0) {
_magic_printf(", ");
magic_counter += 2;
}
if((magic_type_str_print_style & MAGIC_TYPE_STR_PRINT_MEMBER_NAMES)
&& (!MAGIC_TYPE_STR_PRINT_MAX || magic_counter < MAGIC_TYPE_STR_PRINT_MAX)) {
assert(type->member_names[i] && strcmp(type->member_names[i], "") && "Invalid member name!");
_magic_printf("%s ", type->member_names[i]);
magic_counter += strlen(type->member_names[i])+1;
}
magic_type_str_print(type->contained_types[i]);
}
}
_magic_printf(" }");
magic_counter += 2;
}
else if(type->type_id == MAGIC_TYPE_FUNCTION) {
int i;
assert(num_contained_types > 0);
magic_type_str_print(type->contained_types[0]);
num_contained_types--;
_magic_printf(" (");
magic_counter += 2;
for(i=0;i<num_contained_types;i++) {
if(i > 0) {
_magic_printf(", ");
magic_counter += 2;
}
magic_type_str_print(type->contained_types[i+1]);
}
_magic_printf(")");
magic_counter += 1;
}
else {
_magic_printf("???[id=%d,child_types=%d,size=%zu]", type->type_id, type->num_child_types, type->size);
magic_counter += 30;
}
magic_level--;
if(MAGIC_TYPE_STR_PRINT_DEBUG) {
_magic_printf("Exiting level %d...\n", magic_level);
}
}
/*===========================================================================*
* magic_type_values_print *
*===========================================================================*/
PUBLIC void magic_type_values_print(const struct _magic_type* type)
{
int i=0;
if(!MAGIC_TYPE_HAS_VALUE_SET(type)) {
return;
}
while(MAGIC_TYPE_HAS_VALUE(type, i)) {
int value = MAGIC_TYPE_VALUE(type, i);
_magic_printf("%s%d", (i==0 ? "" : ", "), value);
i++;
}
}
/*===========================================================================*
* magic_type_names_print *
*===========================================================================*/
PUBLIC void magic_type_names_print(const struct _magic_type* type)
{
unsigned int i;
for(i=0;i<type->num_names;i++) {
_magic_printf("%s%s", (i==0 ? "" : "|"), type->names[i]);
}
}
/*===========================================================================*
* magic_type_comp_types_print *
*===========================================================================*/
PUBLIC void magic_type_comp_types_print(const struct _magic_type* type,
int flags)
{
int num;
int i=0;
const struct _magic_type* comp_type;
if(!MAGIC_TYPE_HAS_COMP_TYPES(type)) {
return;
}
MAGIC_TYPE_NUM_COMP_TYPES(type, &num);
_magic_printf("#%d", num);
if(flags & MAGIC_SKIP_COMP_TYPES) {
return;
}
flags &= ~MAGIC_EXPAND_TYPE_STR;
MAGIC_TYPE_COMP_ITER(type, comp_type,
_magic_printf("%s%d=", (i==0 ? ": " : ", "), i+1);
MAGIC_TYPE_PRINT(comp_type, flags|MAGIC_SKIP_COMP_TYPES);
i++;
);
}
/*===========================================================================*
* magic_type_str_print_from_target *
*===========================================================================*/
PUBLIC int magic_type_str_print_from_target(void* target)
{
int printed_types=0;
int ret;
ret = magic_type_target_walk(target, NULL, NULL,
magic_type_str_print_cb, &printed_types);
if(ret < 0) {
return ret;
}
if(printed_types == 0) {
_magic_printf("BAD OFFSET");
}
return printed_types;
}
/*===========================================================================*
* magic_type_equals *
*===========================================================================*/
PUBLIC int magic_type_equals(const struct _magic_type* type, const struct _magic_type* other_type)
{
assert(magic_level < MAGIC_MAX_RECURSIVE_TYPES);
if(type == other_type) {
return TRUE;
}
if(type->type_id != other_type->type_id) {
return FALSE;
}
if((type->flags & MAGIC_TYPE_EXTERNAL) || (other_type->flags & MAGIC_TYPE_EXTERNAL)) {
int i, nesting_level;
if(type->num_child_types == other_type->num_child_types) {
int num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
if(num_contained_types == 0) {
return !strcmp(type->type_str, other_type->type_str);
}
nesting_level = magic_type_get_nesting_level(type, magic_level);
if(nesting_level >= 0) {
return (other_type == magic_nested_types2[nesting_level]);
}
magic_nested_types[magic_level] = type;
magic_nested_types2[magic_level] = other_type;
magic_level++;
for(i=0;i<num_contained_types;i++) {
if(magic_type_equals(type->contained_types[i], other_type->contained_types[i]) == FALSE) {
magic_level--;
return FALSE;
}
}
magic_level--;
return TRUE;
}
}
return FALSE;
}
/*===========================================================================*
* magic_type_compatible *
*===========================================================================*/
PUBLIC int magic_type_compatible(const struct _magic_type* type, const struct _magic_type* other_type, int flags)
{
int i, nesting_level, num_contained_types;
assert(magic_level < MAGIC_MAX_RECURSIVE_TYPES);
if(type == other_type) {
return TRUE;
}
if(type->type_id != other_type->type_id) {
return FALSE;
}
if(type->num_child_types != other_type->num_child_types) {
return FALSE;
}
if(flags & MAGIC_TYPE_COMPARE_FLAGS) {
if((type->flags & (~MAGIC_TYPE_IS_ROOT)) != (other_type->flags & (~MAGIC_TYPE_IS_ROOT))){
return FALSE;
}
}
if(flags & MAGIC_TYPE_COMPARE_VALUE_SET) {
if(MAGIC_TYPE_HAS_VALUE_SET(type) != MAGIC_TYPE_HAS_VALUE_SET(other_type)){
return FALSE;
}
if(MAGIC_TYPE_HAS_VALUE_SET(type)){
i=0;
while(MAGIC_TYPE_HAS_VALUE(type, i) && MAGIC_TYPE_HAS_VALUE(other_type, i)) {
if(MAGIC_TYPE_VALUE(type, i) != MAGIC_TYPE_VALUE(other_type, i)){
/* a value is different */
return FALSE;
}
i++;
}
if(MAGIC_TYPE_HAS_VALUE(type, i) || MAGIC_TYPE_HAS_VALUE(other_type, i)) {
return FALSE;
}
}
}
if(flags & MAGIC_TYPE_COMPARE_NAME) {
if(strcmp(type->name, other_type->name)){
return FALSE;
}
}
if(flags & MAGIC_TYPE_COMPARE_NAMES) {
if(type->num_names != other_type->num_names) {
return FALSE;
}
if(type->num_names > 1) {
for(i=0; (unsigned int)i<type->num_names; i++){
if(strcmp(type->names[i], other_type->names[i])) {
return FALSE;
}
}
}
}
num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
if(num_contained_types == 0) {
return type->size == other_type->size && !strcmp(type->type_str, other_type->type_str);
}
if(type->type_id == MAGIC_TYPE_STRUCT) {
if(flags & MAGIC_TYPE_COMPARE_MEMBER_NAMES) {
for(i=0; (unsigned int)i<type->num_child_types; i++){
if(strcmp(type->member_names[i], other_type->member_names[i])) {
return FALSE;
}
}
}
if(flags & MAGIC_TYPE_COMPARE_MEMBER_OFFSETS) {
for(i=0; (unsigned int)i<type->num_child_types; i++){
if(type->member_offsets[i] != other_type->member_offsets[i]) {
return FALSE;
}
}
}
}
nesting_level = magic_type_get_nesting_level(type, magic_level);
if(nesting_level >= 0) {
return (other_type == magic_nested_types2[nesting_level]);
}
magic_nested_types[magic_level] = type;
magic_nested_types2[magic_level] = other_type;
magic_level++;
for(i=0;i<num_contained_types;i++) {
if(!magic_type_compatible(type->contained_types[i], other_type->contained_types[i], flags)) {
magic_level--;
return FALSE;
}
}
magic_level--;
return TRUE;
}
/*===========================================================================*
* magic_type_comp_compatible *
*===========================================================================*/
PUBLIC int magic_type_comp_compatible(const struct _magic_type* type, const struct _magic_type* other_type)
{
const struct _magic_type *comp_type;
MAGIC_TYPE_COMP_ITER(type, comp_type,
if(magic_type_compatible(comp_type, other_type, 0)) {
return TRUE;
}
);
return FALSE;
}
/*===========================================================================*
* magic_type_ptr_is_text *
*===========================================================================*/
PUBLIC int magic_type_ptr_is_text(const struct _magic_type* ptr_type)
{
const struct _magic_type *comp_type;
assert(ptr_type->type_id == MAGIC_TYPE_POINTER);
if(ptr_type->contained_types[0]->type_id == MAGIC_TYPE_FUNCTION
|| MAGIC_TYPE_IS_VOID(ptr_type->contained_types[0])) {
return TRUE;
}
MAGIC_TYPE_COMP_ITER(ptr_type, comp_type,
if(comp_type->type_id == MAGIC_TYPE_FUNCTION
|| MAGIC_TYPE_IS_VOID(comp_type)) {
return TRUE;
}
);
return FALSE;
}
/*===========================================================================*
* magic_type_ptr_is_data *
*===========================================================================*/
PUBLIC int magic_type_ptr_is_data(const struct _magic_type* ptr_type)
{
const struct _magic_type *comp_type;
assert(ptr_type->type_id == MAGIC_TYPE_POINTER);
if(ptr_type->contained_types[0]->type_id != MAGIC_TYPE_FUNCTION) {
return TRUE;
}
MAGIC_TYPE_COMP_ITER(ptr_type, comp_type,
if(comp_type->type_id != MAGIC_TYPE_FUNCTION) {
return TRUE;
}
);
return FALSE;
}
/*===========================================================================*
* magic_type_alloc_needs_varsized_array *
*===========================================================================*/
PUBLIC int magic_type_alloc_needs_varsized_array(const struct _magic_type* type,
size_t alloc_size, int *num_elements)
{
/* See if this type needs a var-sized array for the given allocation size */
const struct _magic_type *array_type, *array_el_type;
size_t array_offset, array_size;
if(!MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE)) {
return FALSE;
}
assert(type->type_id == MAGIC_TYPE_STRUCT);
if(alloc_size <= type->size || type->num_child_types == 0) {
return FALSE;
}
array_type = type->contained_types[type->num_child_types-1];
if(array_type->type_id != MAGIC_TYPE_ARRAY) {
return FALSE;
}
array_el_type = array_type->contained_types[0];
array_offset = type->member_offsets[type->num_child_types-1]+array_type->num_child_types*array_el_type->size;
array_size = alloc_size - array_offset;
if(array_size == 0 || array_size % array_el_type->size != 0) {
return FALSE;
}
if(num_elements) {
*num_elements = 1+array_size/array_el_type->size;
}
return TRUE;
}
/*===========================================================================*
* magic_type_alloc_get_varsized_array_size *
*===========================================================================*/
PUBLIC size_t magic_type_alloc_get_varsized_array_size(const struct _magic_type* type,
int num_elements)
{
/* Get the allocation size from the number of elements of the varsized array. */
const struct _magic_type *array_type, *array_el_type;
size_t array_offset;
if(!MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE)) {
return 0;
}
assert(type->type_id == MAGIC_TYPE_STRUCT);
if(num_elements == 1) {
return type->size;
}
array_type = type->contained_types[type->num_child_types-1];
if(array_type->type_id != MAGIC_TYPE_ARRAY) {
return 0;
}
array_el_type = array_type->contained_types[0];
array_offset = type->member_offsets[type->num_child_types-1]+array_type->num_child_types*array_el_type->size;
return array_offset + array_el_type->size*(num_elements-1);
}
/*===========================================================================*
* magic_type_parse_varsized_array *
*===========================================================================*/
PUBLIC void magic_type_parse_varsized_array(const struct _magic_type *type,
const struct _magic_type **sub_struct_type, const struct _magic_type **sub_array_type,
size_t *sub_array_offset, size_t *sub_array_size)
{
/* Parse a var-sized array containing a variable-sized struct. */
const struct _magic_type *_sub_struct_type, *_sub_array_type, *_sub_array_el_type;
size_t _sub_array_offset, _sub_array_size;
assert(type->type_id == MAGIC_TYPE_ARRAY && MAGIC_TYPE_FLAG(type, MAGIC_TYPE_DYNAMIC));
_sub_struct_type = type->contained_types[0];
assert(magic_type_alloc_needs_varsized_array(_sub_struct_type, type->size, NULL));
_sub_array_type = _sub_struct_type->contained_types[_sub_struct_type->num_child_types-1];
_sub_array_el_type = _sub_array_type->contained_types[0];
_sub_array_offset = _sub_struct_type->member_offsets[_sub_struct_type->num_child_types-1]+_sub_array_type->num_child_types*_sub_array_el_type->size;
_sub_array_size = type->size - _sub_array_offset;
if(sub_struct_type) *sub_struct_type = _sub_struct_type;
if(sub_array_type) *sub_array_type = _sub_array_type;
if(sub_array_offset) *sub_array_offset = _sub_array_offset;
if(sub_array_size) *sub_array_size = _sub_array_size;
}
/*===========================================================================*
* magic_type_walk_flags *
*===========================================================================*/
PUBLIC int magic_type_walk_flags(const struct _magic_type* parent_type,
unsigned parent_offset, int child_num,
const struct _magic_type* type, unsigned offset,
const unsigned min_offset, const unsigned max_offset,
const magic_type_walk_cb_t cb, void* cb_args, int flags) {
static THREAD_LOCAL int magic_depth = 0;
int ret, status, action;
ret = MAGIC_TYPE_WALK_CONTINUE;
if(offset >= min_offset && offset <= max_offset) {
ret = cb(parent_type, parent_offset, child_num, type, offset, magic_depth, cb_args);
}
else if(offset > max_offset) {
ret = MAGIC_TYPE_WALK_STOP;
}
else if(offset+type->size <= min_offset) {
ret = MAGIC_TYPE_WALK_SKIP_PATH;
}
/* The status code returned to the caller is propagated directly from the
* callback only in case of ret<0 and ret == MAGIC_TYPE_WALK_STOP.
* In all the other cases, we return 0 the caller.
*/
status = ret < 0 ? ret : 0;
action = ret < 0 ? MAGIC_TYPE_WALK_STOP : ret;
switch(action) {
case MAGIC_TYPE_WALK_STOP:
status = status ? status : MAGIC_TYPE_WALK_STOP;
break;
case MAGIC_TYPE_WALK_SKIP_PATH:
status = 0;
break;
case MAGIC_TYPE_WALK_CONTINUE:
if(!MAGIC_TYPE_IS_WALKABLE(type)) {
status = 0;
}
else {
int i, num_child_types, start;
num_child_types = type->num_child_types;
start = 0;
if(type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR) {
if(!MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE) && offset < min_offset) {
/* Skip irrelevant array iterations. */
start = (min_offset-offset)/(type->contained_types[0]->size);
}
}
for(i=start;i<num_child_types;i++) {
const struct _magic_type *child_type;
unsigned child_offset;
magic_type_walk_step(type, i, &child_type, &child_offset, flags);
magic_depth++;
status = magic_type_walk_flags(type, offset, i, child_type, offset+child_offset, min_offset, max_offset, cb, cb_args, flags);
magic_depth--;
if(status < 0 || status == MAGIC_TYPE_WALK_STOP) {
break;
}
}
}
break;
default:
_magic_printf("magic_type_walk: unrecognized callback return code: %d, stopping type walk...\n", action);
status = MAGIC_TYPE_WALK_STOP;
break;
}
return status;
}
/*===========================================================================*
* magic_type_target_walk *
*===========================================================================*/
PUBLIC int magic_type_target_walk(void *target,
struct _magic_dsentry **trg_dsentry, struct _magic_dfunction **trg_dfunction,
const magic_type_walk_cb_t cb, void *cb_args)
{
int ret;
struct _magic_sentry *sentry = NULL;
struct _magic_function *function = NULL;
sentry = magic_sentry_lookup_by_range(target, magic_reentrant ? &magic_dsentry_buff : NULL);
if (sentry == NULL) {
function = magic_function_lookup_by_addr(target, magic_reentrant ? &magic_dfunction_buff : NULL);
if (function == NULL) {
/* No known entry found. */
return MAGIC_ENOENT;
}
if (MAGIC_STATE_FLAG(function, MAGIC_STATE_ADDR_NOT_TAKEN)) {
/* A function has been found, but it was not supposed to be a target. */
return MAGIC_EBADENT;
}
}
else if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_ADDR_NOT_TAKEN)) {
/* An entry has been found, but it was not supposed to be a target. */
return MAGIC_EBADENT;
}
assert(sentry || function);
if (magic_reentrant) {
if (sentry) {
if (trg_dsentry) {
if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC)) {
magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(sentry), *trg_dsentry);
}
else {
memcpy(MAGIC_DSENTRY_TO_SENTRY(*trg_dsentry), sentry, sizeof(struct _magic_sentry));
}
}
if (trg_dfunction) {
*trg_dfunction = NULL;
}
}
else {
if (trg_dfunction) {
if (MAGIC_STATE_FLAG(function, MAGIC_STATE_DYNAMIC)) {
magic_copy_dfunction(MAGIC_DFUNCTION_FROM_FUNCTION(function), *trg_dfunction);
}
else {
memcpy(MAGIC_DFUNCTION_TO_FUNCTION(*trg_dfunction), function, sizeof(struct _magic_function));
}
}
if (trg_dsentry) {
*trg_dsentry = NULL;
}
}
} else {
/*
* Just return the pointer to the target object.
* NB!: Because the target objects can be static (i.e. sentries,
* functions), the user MUST first check the flag
* of the returned target element to see if it is a sentry
* or function. Otherwise, he might end up accessing invalid
* memory.
*/
if (sentry) {
if (trg_dsentry) {
*trg_dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
}
if (trg_dfunction) {
*trg_dfunction = NULL;
}
}
else {
if (trg_dfunction) {
*trg_dfunction = MAGIC_DFUNCTION_FROM_FUNCTION(function);
}
if (trg_dsentry) {
*trg_dsentry = NULL;
}
}
}
if (sentry) {
ret = magic_type_walk_root_at_offset(sentry->type, (char *) target - (char *) sentry->address, cb, cb_args);
} else {
ret = magic_type_walk_root_at_offset(function->type, (char*) target - (char*) function->address, cb, cb_args);
}
return ret;
}
/*===========================================================================*
* magic_type_walk_as_void_array *
*===========================================================================*/
PUBLIC int magic_type_walk_as_void_array(const struct _magic_type* parent_type,
unsigned parent_offset, int child_num, const struct _magic_type* type,
unsigned offset, const unsigned min_offset, const unsigned max_offset,
const magic_type_walk_cb_t cb, void* cb_args)
{
struct _magic_type void_array_type;
MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(&void_array_type, type->size);
return magic_type_walk(parent_type, parent_offset, child_num, &void_array_type,
offset, min_offset, max_offset, cb, cb_args);
}
/*===========================================================================*
* magic_type_walk_as_ptrint_array *
*===========================================================================*/
PUBLIC int magic_type_walk_as_ptrint_array(const struct _magic_type* parent_type,
unsigned parent_offset, int child_num, const struct _magic_type* type, void* offset_addr,
unsigned offset, const unsigned min_offset, const unsigned max_offset,
const magic_type_walk_cb_t cb, void* cb_args)
{
struct _magic_type ptrint_array_type;
unsigned type_size = type->size;
unsigned addr_diff = ((unsigned)offset_addr) % sizeof(void*);
if(addr_diff > 0) {
unsigned addr_off_by = sizeof(void*) - addr_diff;
if(type_size <= addr_off_by) {
return MAGIC_EBADWALK;
}
type_size -= addr_off_by;
offset_addr = (void*)((unsigned)offset_addr + addr_off_by);
offset += addr_off_by;
}
addr_diff = (((unsigned)offset_addr)+type_size) % sizeof(void*);
if(addr_diff > 0) {
unsigned addr_off_by = addr_diff;
if(type_size <= addr_off_by) {
return MAGIC_EBADWALK;
}
type_size -= addr_off_by;
}
MAGIC_TYPE_PTRINT_ARRAY_GET_FROM_SIZE(&ptrint_array_type, type_size);
return magic_type_walk(parent_type, parent_offset, child_num, &ptrint_array_type,
offset, min_offset, max_offset, cb, cb_args);
}
/*===========================================================================*
* magic_type_str_print_cb *
*===========================================================================*/
PUBLIC int magic_type_str_print_cb(const struct _magic_type* parent_type,
const unsigned parent_offset, int child_num,
const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
{
int *printed_types = (int*) cb_args;
if(printed_types) (*printed_types)++;
magic_type_str_print(type);
_magic_printf("; ");
return MAGIC_TYPE_WALK_CONTINUE;
}
/*===========================================================================*
* magic_type_count_cb *
*===========================================================================*/
PUBLIC int magic_type_count_cb(const struct _magic_type* parent_type,
const unsigned parent_offset, int child_num,
const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
{
int *type_counter = (int*) cb_args;
if(type_counter) (*type_counter)++;
return MAGIC_TYPE_WALK_CONTINUE;
}
/*===========================================================================*
* magic_type_child_offset_cb *
*===========================================================================*/
PUBLIC int magic_type_child_offset_cb(const struct _magic_type* parent_type,
const unsigned parent_offset, int child_num,
const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
{
void **args_array = (void**) cb_args;
int *my_child_num = (int*) args_array[0];
unsigned *child_offset = (unsigned*) args_array[1];
if(!parent_type) {
return MAGIC_TYPE_WALK_CONTINUE;
}
if(child_num == *my_child_num) {
*child_offset = offset;
return MAGIC_TYPE_WALK_STOP;
}
return MAGIC_TYPE_WALK_SKIP_PATH;
}
/*===========================================================================*
* magic_type_walk_step *
*===========================================================================*/
PUBLIC void magic_type_walk_step(const struct _magic_type *type,
int child_num, const struct _magic_type **child_type, unsigned *child_offset,
int walk_flags)
{
int type_id;
struct _magic_type type_buff;
if(type->type_id == MAGIC_TYPE_UNION && (walk_flags & MAGIC_TYPE_WALK_UNIONS_AS_VOID)) {
MAGIC_TYPE_VOID_ARRAY_GET_FROM_SIZE(&type_buff, type->size);
type = &type_buff;
}
type_id = type->type_id;
if(type_id == MAGIC_TYPE_STRUCT || type_id == MAGIC_TYPE_UNION) {
*child_type = type->contained_types[child_num];
*child_offset = type->member_offsets[child_num];
}
else {
assert(type_id == MAGIC_TYPE_ARRAY || type_id == MAGIC_TYPE_VECTOR);
if(MAGIC_TYPE_FLAG(type, MAGIC_TYPE_VARSIZE) && child_num > 0) {
const struct _magic_type *sub_array_type, *sub_array_el_type;
size_t sub_array_offset;
magic_type_parse_varsized_array(type, NULL, &sub_array_type, &sub_array_offset, NULL);
sub_array_el_type = sub_array_type->contained_types[0];
*child_type = sub_array_el_type;
*child_offset = sub_array_offset + (child_num-1)*sub_array_el_type->size;
}
else {
*child_type = type->contained_types[0];
*child_offset = child_num*((*child_type)->size);
}
}
}
/*===========================================================================*
* magic_type_get_size *
*===========================================================================*/
PUBLIC size_t magic_type_get_size(struct _magic_type *type, int flags)
{
size_t size;
int i, num_contained_types;
size = sizeof(type->size) +
sizeof(type->num_child_types) + sizeof(type->contained_types) +
sizeof(type->member_offsets) + sizeof(type->type_id) + sizeof(type->flags);
num_contained_types = MAGIC_TYPE_NUM_CONTAINED_TYPES(type);
if(num_contained_types > 0) {
size += sizeof(*(type->contained_types))*num_contained_types;
}
if(type->type_id == MAGIC_TYPE_STRUCT) {
size += sizeof(*(type->member_offsets))*num_contained_types;
if(flags & MAGIC_SIZE_MEMBER_NAMES) {
size += sizeof(*(type->member_names))*num_contained_types;
for(i=0;i<num_contained_types;i++) {
size += strlen(type->member_names[i])+1;
}
}
}
if(flags & MAGIC_SIZE_VALUE_SET) {
if(MAGIC_TYPE_HAS_VALUE_SET(type)) {
int num;
MAGIC_TYPE_NUM_VALUES(type, &num);
size += sizeof(int)+(num+1);
}
}
if(flags & MAGIC_SIZE_TYPE_NAMES) {
size += sizeof(type->num_names) + sizeof(type->names) + sizeof(*(type->names))*(type->num_names);
for(i=0;(unsigned int)i<type->num_names;i++) {
size += strlen(type->names[i])+1;
}
}
if(flags & MAGIC_SIZE_COMP_TYPES) {
if(MAGIC_TYPE_HAS_COMP_TYPES(type)) {
int num;
MAGIC_TYPE_NUM_COMP_TYPES(type, &num);
size += sizeof(*(type->compatible_types))*num;
}
}
return size;
}
/*===========================================================================*
* magic_types_get_size *
*===========================================================================*/
PUBLIC size_t magic_types_get_size(int flags)
{
size_t size;
int i;
size = 0;
for(i=0;i<_magic_types_num;i++) {
size += magic_type_get_size(&_magic_types[i], flags);
}
return size;
}
/*===========================================================================*
* magic_function_get_size *
*===========================================================================*/
PUBLIC size_t magic_function_get_size(struct _magic_function *function, int flags)
{
size_t size;
size = sizeof(function->type) + sizeof(function->flags) + sizeof(function->address);
if(flags & MAGIC_SIZE_NAMES) {
size += sizeof(function->name) + strlen(function->name)+1;
}
return size;
}
/*===========================================================================*
* magic_functions_get_size *
*===========================================================================*/
PUBLIC size_t magic_functions_get_size(int flags)
{
size_t size;
int i;
size = 0;
for(i=0;i<_magic_functions_num;i++) {
size += magic_function_get_size(&_magic_functions[i], flags);
}
return size;
}
/*===========================================================================*
* magic_dfunctions_get_size *
*===========================================================================*/
PUBLIC size_t magic_dfunctions_get_size(int flags)
{
size_t size;
struct _magic_dfunction* dfunction;
struct _magic_function* function;
size = 0;
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
size += magic_function_get_size(function, flags);
);
return size;
}
/*===========================================================================*
* magic_sentry_get_size *
*===========================================================================*/
PUBLIC size_t magic_sentry_get_size(struct _magic_sentry *sentry, int flags)
{
size_t size;
size = sizeof(sentry->type) + sizeof(sentry->flags);
if(MAGIC_SENTRY_IS_DSENTRY(sentry)) {
struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
if(flags & MAGIC_SIZE_DSENTRY_NAMES) {
size += sizeof(sentry->name) + strlen(sentry->name)+1;
if(dsentry->parent_name) {
size += sizeof(dsentry->parent_name) + strlen(dsentry->parent_name)+1;
}
}
if(sentry->type == &dsentry->type) {
size += sizeof(dsentry->type.num_child_types);
}
size += sizeof(dsentry->next);
}
else {
size += sizeof(sentry->address);
if(flags & MAGIC_SIZE_NAMES) {
size += sizeof(sentry->name) + strlen(sentry->name)+1;
}
}
return size;
}
/*===========================================================================*
* magic_sentries_get_size *
*===========================================================================*/
PUBLIC size_t magic_sentries_get_size(int flags)
{
size_t size;
int i;
size = 0;
for(i=0;i<_magic_sentries_num;i++) {
size += magic_sentry_get_size(&_magic_sentries[i], flags);
}
return size;
}
/*===========================================================================*
* magic_dsentries_get_size *
*===========================================================================*/
PUBLIC size_t magic_dsentries_get_size(int flags)
{
size_t size;
struct _magic_dsentry *prev_dsentry, *dsentry;
struct _magic_sentry* sentry;
size = 0;
MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
if(!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
size += magic_sentry_get_size(sentry, flags);
}
);
return size;
}
/*===========================================================================*
* magic_dsindex_get_size *
*===========================================================================*/
PUBLIC size_t magic_dsindex_get_size(struct _magic_dsindex *dsindex, int flags)
{
size_t size;
size = sizeof(dsindex->type) + sizeof(dsindex->flags);
if(flags & MAGIC_SIZE_DSINDEX_NAMES) {
size += sizeof(dsindex->parent_name) + strlen(dsindex->parent_name)+1;
size += sizeof(dsindex->name) + strlen(dsindex->name)+1;
}
return size;
}
/*===========================================================================*
* magic_dsindexes_get_size *
*===========================================================================*/
PUBLIC size_t magic_dsindexes_get_size(int flags)
{
size_t size;
int i;
size = 0;
for(i=0;i<_magic_dsindexes_num;i++) {
size += magic_dsindex_get_size(&_magic_dsindexes[i], flags);
}
return size;
}
/*===========================================================================*
* magic_sodesc_get_size *
*===========================================================================*/
PUBLIC size_t magic_sodesc_get_size(struct _magic_sodesc *sodesc, int flags)
{
return sizeof(struct _magic_sodesc);
}
/*===========================================================================*
* magic_sodescs_get_size *
*===========================================================================*/
PUBLIC size_t magic_sodescs_get_size(int flags)
{
size_t size;
struct _magic_sodesc* sodesc;
size = 0;
MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
size += magic_sodesc_get_size(sodesc, flags);
);
return size;
}
/*===========================================================================*
* magic_dsodesc_get_size *
*===========================================================================*/
PUBLIC size_t magic_dsodesc_get_size(struct _magic_dsodesc *dsodesc, int flags)
{
return sizeof(struct _magic_dsodesc);
}
/*===========================================================================*
* magic_dsodescs_get_size *
*===========================================================================*/
PUBLIC size_t magic_dsodescs_get_size(int flags)
{
size_t size;
struct _magic_dsodesc* dsodesc;
size = 0;
MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
size += magic_dsodesc_get_size(dsodesc, flags);
);
return size;
}
/*===========================================================================*
* magic_metadata_get_size *
*===========================================================================*/
PUBLIC size_t magic_metadata_get_size(int flags)
{
size_t size = 0;
size += magic_types_get_size(flags);
size += magic_functions_get_size(flags);
size += magic_dfunctions_get_size(flags);
size += magic_sentries_get_size(flags);
size += magic_dsentries_get_size(flags);
size += magic_dsindexes_get_size(flags);
size += magic_dsodescs_get_size(flags);
return size;
}
/*===========================================================================*
* magic_sentries_data_get_size *
*===========================================================================*/
PUBLIC size_t magic_sentries_data_get_size(int flags)
{
size_t size;
int i;
size = 0;
for(i=0;i<_magic_sentries_num;i++) {
size += _magic_sentries[i].type->size;
}
return size;
}
/*===========================================================================*
* magic_dsentries_data_get_size *
*===========================================================================*/
PUBLIC size_t magic_dsentries_data_get_size(int flags)
{
size_t size;
struct _magic_dsentry *prev_dsentry, *dsentry;
struct _magic_sentry* sentry;
size = 0;
MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
if(!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
size += sentry->type->size;
if(MAGIC_STATE_FLAG(sentry, MAGIC_STATE_HEAP)) {
/* Assume a couple of words for malloc header. */
size += 2*sizeof(void*);
}
}
);
return size;
}
/*===========================================================================*
* magic_other_data_get_size *
*===========================================================================*/
PUBLIC size_t magic_other_data_get_size(int flags)
{
size_t size = 0;
MAGIC_DSENTRY_LOCK();
magic_range_is_stack(NULL);
MAGIC_DSENTRY_UNLOCK();
size += MAGIC_RANGE_SIZE(magic_stack_range);
size += MAGIC_RANGE_SIZE(magic_text_range);
return size;
}
/*===========================================================================*
* magic_data_get_size *
*===========================================================================*/
PUBLIC size_t magic_data_get_size(int flags)
{
size_t size = 0;
size += magic_sentries_data_get_size(flags);
size += magic_dsentries_data_get_size(flags);
size += magic_other_data_get_size(flags);
return size;
}
/*===========================================================================*
* magic_print_size_stats *
*===========================================================================*/
PUBLIC void magic_print_size_stats(int flags)
{
size_t sentries_data_size, sentries_metadata_size;
size_t dsentries_data_size, dsentries_metadata_size;
size_t data_size, metadata_size;
int dsentries_num;
sentries_data_size = magic_sentries_data_get_size(flags);
sentries_metadata_size = magic_sentries_get_size(flags);
dsentries_data_size = magic_dsentries_data_get_size(flags);
dsentries_metadata_size = magic_dsentries_get_size(flags);
data_size = magic_data_get_size(flags);
metadata_size = magic_metadata_get_size(flags);
MAGIC_DSENTRY_NUM(_magic_first_dsentry, &dsentries_num);
_magic_printf("--------------------------------------------------------\n");
_magic_printf("magic_print_size_stats: Printing size stats:\n");
_magic_printf(" - sentries: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num, sentries_data_size, sentries_metadata_size, sentries_data_size+sentries_metadata_size, ((double)sentries_metadata_size)/sentries_data_size);
_magic_printf(" - dsentries: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", dsentries_num, dsentries_data_size, dsentries_metadata_size, dsentries_data_size+dsentries_metadata_size, ((double)dsentries_metadata_size)/dsentries_data_size);
_magic_printf(" - other: # %6d, data %8d\n", 2, magic_other_data_get_size(flags));
_magic_printf(" - state all: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num+dsentries_num, sentries_data_size+dsentries_data_size, metadata_size, sentries_data_size+dsentries_data_size+metadata_size, ((double)metadata_size)/(sentries_data_size+dsentries_data_size));
_magic_printf(" - all: # %6d, data %8d, metadata %8d, total %8d, ratio %.3f\n", _magic_sentries_num+dsentries_num+2, data_size, metadata_size, data_size+metadata_size, ((double)metadata_size)/data_size);
_magic_printf("--------------------------------------------------------\n");
_magic_printf("magic_print_size_stats: Printing metadata size breakdown:\n");
_magic_printf(" - types: # %6d, metadata %8d\n", _magic_types_num, magic_types_get_size(flags));
_magic_printf(" - functions: # %6d, metadata %8d\n", _magic_functions_num, magic_functions_get_size(flags));
_magic_printf(" - dfunctions # %6d, metadata %8d\n", 0, magic_dfunctions_get_size(flags));
_magic_printf(" - sentries: # %6d, metadata %8d\n", _magic_sentries_num, sentries_metadata_size);
_magic_printf(" - dsentries: # %6d, metadata %8d\n", dsentries_num, dsentries_metadata_size);
_magic_printf(" - dsindexes: # %6d, metadata %8d\n", _magic_dsindexes_num, magic_dsindexes_get_size(flags));
_magic_printf(" - dsodescs: # %6d, metadata %8d\n", 0, magic_dsodescs_get_size(flags));
_magic_printf("--------------------------------------------------------\n");
}