minix/minix/llvm/static/magic/magic_range.c
David van Moolenbroek 0acd3f1ae0 Import magic library from llvm-apps
Change-Id: Icfbcfae6afc731a23e71448a7a5d0045b2c219e5
2015-09-17 13:58:32 +00:00

322 lines
11 KiB
C

#define MAGIC_RANGE_DEBUG MAGIC_DEBUG_SET(0)
#include <magic_range.h>
/*===========================================================================*
* magic_range_is_shlib *
*===========================================================================*/
PRIVATE int magic_range_is_shlib(void *addr, void **container)
{
/*
* NB!: This function requires the calling thread to already
* hold the DSODESC lock.
*/
int ret = 0;
struct _magic_sodesc *sodesc;
struct _magic_dsodesc *dsodesc;
/* First iterate through the SO descriptors. */
MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
/* First check the text range. */
MAGIC_RANGE_DEBUG_ADDR(addr, sodesc->lib.text_range);
if (MAGIC_ADDR_IS_IN_RANGE(addr, sodesc->lib.text_range)) {
ret |= MAGIC_STATE_TEXT;
goto found_so;
}
/* Next check the data range. */
MAGIC_RANGE_DEBUG_ADDR(addr, sodesc->lib.data_range);
if (MAGIC_ADDR_IS_IN_RANGE(addr, sodesc->lib.data_range)) {
ret |= MAGIC_STATE_DATA;
goto found_so;
}
);
/* Next iterate through the DSO descriptors. */
MAGIC_SODESC_ITER(_magic_first_dsodesc, dsodesc,
/* First check the text range. */
MAGIC_RANGE_DEBUG_ADDR(addr, dsodesc->lib.text_range);
if (MAGIC_ADDR_IS_IN_RANGE(addr, dsodesc->lib.text_range)) {
ret |= MAGIC_STATE_TEXT;
goto found_dso;
}
/* Next check the data range. */
MAGIC_RANGE_DEBUG_ADDR(addr, dsodesc->lib.data_range);
if (MAGIC_ADDR_IS_IN_RANGE(addr, dsodesc->lib.data_range)) {
ret |= MAGIC_STATE_DATA;
goto found_dso;
}
);
out:
return ret;
found_so:
ret |= MAGIC_STATE_LIB | MAGIC_STATE_LIB_SO;
if (container != NULL)
*container = (void *)(sodesc);
goto out;
found_dso:
ret |= MAGIC_STATE_LIB | MAGIC_STATE_LIB_DSO;
if (container != NULL) {
*container = (void *)(dsodesc);
}
goto out;
}
/*===========================================================================*
* magic_range_is_data *
*===========================================================================*/
PRIVATE INLINE int magic_range_is_data(void *addr)
{
MAGIC_RANGE_DEBUG_ADDR(addr, magic_data_range);
return MAGIC_ADDR_IS_IN_RANGE(addr, magic_data_range) ? MAGIC_STATE_DATA : 0;
}
/*===========================================================================*
* magic_range_is_text *
*===========================================================================*/
PRIVATE INLINE int magic_range_is_text(void *addr)
{
MAGIC_RANGE_DEBUG_ADDR(addr, magic_text_range);
return MAGIC_ADDR_IS_IN_RANGE(addr, magic_text_range) ? MAGIC_STATE_TEXT : 0;
}
/*===========================================================================*
* magic_range_is_heap *
*===========================================================================*/
PRIVATE INLINE int magic_range_is_heap(void *addr)
{
void* heap_range[2];
MAGIC_RANGE_SET_MIN(heap_range, magic_heap_start);
MAGIC_RANGE_SET_MAX(heap_range, (char *)magic_heap_end + MAGIC_HEAP_GAP);
MAGIC_RANGE_DEBUG_ADDR(addr, heap_range);
return MAGIC_ADDR_IS_IN_RANGE(addr, heap_range) ? MAGIC_STATE_HEAP : 0;
}
/*===========================================================================*
* magic_range_is_stack *
*===========================================================================*/
PUBLIC int magic_range_is_stack(void *addr)
{
/*
* NB!: This function requires the calling thread to already
* hold the DSENTRY lock.
*/
struct _magic_sentry *sentry;
int ret;
void *stack_range[2];
MAGIC_RANGE_INIT(stack_range);
assert(_magic_first_stack_dsentry && _magic_last_stack_dsentry);
sentry = MAGIC_DSENTRY_TO_SENTRY(_magic_first_stack_dsentry);
MAGIC_RANGE_SET_MIN(stack_range,
(char *) MAGIC_DSENTRY_TO_SENTRY(_magic_last_stack_dsentry)->address -
MAGIC_STACK_GAP);
MAGIC_RANGE_SET_MAX(stack_range,
((char *) sentry->address) + sentry->type->size - 1);
#if MAGIC_RANGE_ROUND_STACK
MAGIC_RANGE_PAGE_ROUND(stack_range);
#endif
MAGIC_RANGE_DEBUG_ADDR(addr, stack_range);
ret = MAGIC_ADDR_IS_IN_RANGE(addr, stack_range) ? MAGIC_STATE_STACK : 0;
return ret;
}
/*===========================================================================*
* magic_range_is_dsentry *
*===========================================================================*/
PUBLIC int magic_range_is_dsentry(void *addr)
{
/*
* NB!: This function requires the calling thread to already
* hold the DSENTRY lock.
*/
int ret = 0;
void *start_address, *end_address;
struct _magic_dsentry *prev_dsentry, *dsentry;
struct _magic_sentry *sentry;
int region;
if(magic_update_dsentry_ranges) {
MAGIC_RANGE_INIT(magic_heap_range);
MAGIC_RANGE_INIT(magic_map_range);
MAGIC_RANGE_INIT(magic_shm_range);
MAGIC_RANGE_INIT(magic_stack_range);
MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
start_address = sentry->address;
end_address = (void *) (((char *)sentry->address) +
sentry->type->size - 1);
region = MAGIC_STATE_REGION(sentry);
if(region & MAGIC_STATE_HEAP) {
MAGIC_RANGE_UPDATE(magic_heap_range, start_address, end_address);
}
else if(region & MAGIC_STATE_MAP) {
MAGIC_RANGE_UPDATE(magic_map_range, start_address, end_address);
}
else if(region & MAGIC_STATE_SHM) {
MAGIC_RANGE_UPDATE(magic_shm_range, start_address, end_address);
}
else if(region & MAGIC_STATE_STACK) {
MAGIC_RANGE_UPDATE(magic_stack_range, start_address, end_address);
}
);
magic_update_dsentry_ranges = 0;
}
MAGIC_RANGE_DEBUG_ADDR(addr, magic_heap_range);
if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_heap_range)) {
ret |= MAGIC_STATE_HEAP;
}
MAGIC_RANGE_DEBUG_ADDR(addr, magic_map_range);
if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_map_range)) {
ret |= MAGIC_STATE_MAP;
}
MAGIC_RANGE_DEBUG_ADDR(addr, magic_shm_range);
if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_shm_range)) {
ret |= MAGIC_STATE_SHM;
}
MAGIC_RANGE_DEBUG_ADDR(addr, magic_stack_range);
if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_stack_range)) {
ret |= MAGIC_STATE_STACK;
}
return ret;
}
/*===========================================================================*
* magic_range_is_dfunction *
*===========================================================================*/
PUBLIC int magic_range_is_dfunction(void *addr)
{
/*
* NB!: This function requires the calling thread to already
* hold the DFUNCTION lock.
*/
int ret = 0;
void *start_address;
struct _magic_dfunction* dfunction;
struct _magic_function* function;
int region;
if(magic_update_dfunction_ranges) {
MAGIC_RANGE_INIT(magic_dfunction_range);
MAGIC_DFUNCTION_FUNC_ITER(_magic_first_dfunction, dfunction, function,
start_address = function->address;
region = MAGIC_STATE_REGION(function);
assert(region & MAGIC_STATE_TEXT);
MAGIC_RANGE_UPDATE(magic_dfunction_range, start_address, start_address);
);
magic_update_dfunction_ranges = 0;
}
MAGIC_RANGE_DEBUG_ADDR(addr, magic_dfunction_range);
if(MAGIC_ADDR_IS_IN_RANGE(addr, magic_dfunction_range)) {
ret |= MAGIC_STATE_TEXT;
}
return ret;
}
/*===========================================================================*
* magic_ranges_init *
*===========================================================================*/
PUBLIC void magic_ranges_init(void)
{
int i,j;
void *start_address, *end_address;
void* linker_vars[] = { MAGIC_LINKER_VAR_NAMES };
/* Init sentry and data range. */
MAGIC_RANGE_INIT(magic_data_range);
MAGIC_RANGE_INIT(magic_sentry_range);
for (i = 0 ; i < _magic_sentries_num ; i++) {
start_address = _magic_sentries[i].address;
end_address = (void *) (((char *)_magic_sentries[i].address)+_magic_sentries[i].type->size-1);
MAGIC_RANGE_UPDATE(magic_sentry_range, start_address, end_address);
j = 0;
while (linker_vars[j] && strcmp(linker_vars[j], _magic_sentries[i].name)) j++;
if (linker_vars[j] || MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_THREAD_LOCAL)
|| MAGIC_STATE_FLAG(&_magic_sentries[i], MAGIC_STATE_EXTERNAL)) {
continue;
}
MAGIC_RANGE_UPDATE(magic_data_range, start_address, end_address);
}
#if MAGIC_RANGE_ROUND_DATA
MAGIC_RANGE_PAGE_ROUND(magic_data_range);
#endif
/* Init function range. */
MAGIC_RANGE_INIT(magic_function_range);
for (i = 0 ; i < _magic_functions_num ; i++) {
start_address = _magic_functions[i].address;
MAGIC_RANGE_UPDATE(magic_function_range, start_address, start_address);
}
/* Init text range. */
#ifdef __MINIX
MAGIC_RANGE_SET(magic_text_range, MAGIC_TEXT_START,
MAGIC_TEXT_END ? MAGIC_TEXT_END : ((char *)magic_function_range[1]));
#else
MAGIC_RANGE_SET(magic_text_range, MAGIC_TEXT_START,
MAGIC_TEXT_END ? MAGIC_TEXT_END : ((char *)magic_data_range[0] - 1));
#endif
#if MAGIC_RANGE_ROUND_TEXT
MAGIC_RANGE_PAGE_ROUND(magic_text_range);
#endif
/* Init heap start. */
magic_heap_start = MAGIC_HEAP_START ? MAGIC_HEAP_START : ((char *)magic_data_range[1] + 1);
magic_heap_end = ((char *)sbrk(0)) - 1;
/* Defaults for other ranges. */
MAGIC_RANGE_INIT(magic_heap_range);
MAGIC_RANGE_INIT(magic_map_range);
MAGIC_RANGE_INIT(magic_shm_range);
MAGIC_RANGE_INIT(magic_stack_range);
MAGIC_RANGE_INIT(magic_dfunction_range);
}
/*===========================================================================*
* magic_range_lookup_by_addr *
*===========================================================================*/
PUBLIC int magic_range_lookup_by_addr(void *addr, void **container)
{
/*
* NB!: This function requires the calling thread to already
* hold the DSENTRY, DFUNCTION and DSODESC locks.
*/
int ret;
/* Constant ranges first. */
if (magic_range_is_data(addr)) {
return MAGIC_STATE_DATA;
}
if (magic_range_is_text(addr)) {
return MAGIC_STATE_TEXT;
}
/* Non-dsentry ranges next. */
if (magic_range_is_heap(addr)) {
return MAGIC_STATE_HEAP;
}
if (magic_range_is_stack(addr)) {
return MAGIC_STATE_STACK;
}
/* Shared library ranges. */
#if 0
/* XXX: This kind of range isn't very accurate. */
if (magic_range_is_dfunction(addr)) {
return MAGIC_STATE_LIB | MAGIC_STATE_TEXT;
}
#endif
if ((ret = magic_range_is_shlib(addr, container))) {
return ret;
}
/* Dsentry ranges last. */
return magic_range_is_dsentry(addr);
}