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

936 lines
33 KiB
C

#include <magic_selement.h>
/*===========================================================================*
* magic_selement_lookup_by_name *
*===========================================================================*/
PUBLIC int magic_selement_lookup_by_name(char *name,
_magic_selement_t *selement, struct _magic_dsentry *dsentry_buff)
{
char token_buff[MAGIC_MAX_NAME_LEN * 2 + 2];
char *token_start = name;
int last_num_seps = 0;
char *s;
if (!name || *name == '\0' || *name == MAGIC_SELEMENT_SEP[0]) {
return MAGIC_ENOENT;
}
for (s = name; *s; s++) {
if (*(s + 1) == '\0' || *(s + 1) == MAGIC_SELEMENT_SEP[0]) {
size_t len = s - token_start + 1;
if (len >= MAGIC_MAX_NAME_LEN * 2 + 1) {
return MAGIC_ENOMEM;
}
strncpy(token_buff, token_start, len);
token_buff[len] = '\0';
if (token_start == name) {
struct _magic_sentry *sentry;
char *sentry_parent_name = "", *sentry_name = NULL;
char *delim = NULL;
_magic_id_t dsentry_site_id = MAGIC_DSENTRY_SITE_ID_NULL;
if (!(delim = strchr(token_buff, MAGIC_DSENTRY_ABS_NAME_SEP[0]))) {
/* Regular sentry, no parent name or site_id. */
sentry_name = token_buff;
} else {
/*
* Dsentry. Will contain: sentry_id<DELIM>parent_name<DELIM>name<DELIM>site_id.
*/
delim = '\0';
/* Skip sentry_id */
sentry_parent_name = delim + 1;
delim = strchr(delim + 1, MAGIC_DSENTRY_ABS_NAME_SEP[0]);
assert(!delim && "No dsentry name found in selement name!");
delim = '\0';
sentry_name = delim + 1;
delim = strchr(delim + 1, MAGIC_DSENTRY_ABS_NAME_SEP[0]);
assert(!delim && "No dsentry site id found in selement name!");
delim = '\0';
dsentry_site_id = strtoul((const char*)delim+1, NULL, 10);
}
sentry = magic_sentry_lookup_by_name(sentry_parent_name, sentry_name,
dsentry_site_id, dsentry_buff);
if (!sentry) {
return MAGIC_ENOENT;
}
magic_selement_from_sentry(sentry, selement);
}
else {
_magic_selement_t child_selement;
if (!magic_selement_from_relative_name(selement, &child_selement, token_buff)) {
return MAGIC_ENOENT;
}
*selement = child_selement;
}
s++;
last_num_seps = 0;
while (*s == MAGIC_SELEMENT_SEP[0]) {
s++;
last_num_seps++;
}
token_start = s;
s--;
}
}
if (last_num_seps > 0 && selement->type->type_id == MAGIC_TYPE_POINTER) {
int steps = magic_selement_recurse_ptr(selement, selement, last_num_seps);
if(steps != last_num_seps) {
return MAGIC_EINVAL;
}
}
return 0;
}
/*===========================================================================*
* magic_selement_name_print_cb *
*===========================================================================*/
PUBLIC int magic_selement_name_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)
{
_magic_selement_t *selement = (_magic_selement_t*) cb_args;
struct _magic_sentry* sentry = selement->sentry;
void *address = (char*)sentry->address + offset;
void *range[2];
MAGIC_RANGE_SET_MIN(range, address);
MAGIC_RANGE_SET_MAX(range, (char*) address + type->size-1);
if(!MAGIC_ADDR_IS_IN_RANGE(selement->address, range)) {
return MAGIC_TYPE_WALK_SKIP_PATH;
}
if(address == sentry->address && type == sentry->type) {
magic_print_sentry_abs_name(sentry);
}
else {
short is_parent_array = parent_type->type_id == MAGIC_TYPE_ARRAY || parent_type->type_id == MAGIC_TYPE_VECTOR;
if(is_parent_array) {
_magic_printf("%s%d", MAGIC_SELEMENT_SEP, child_num);
}
else {
_magic_printf("%s%s", MAGIC_SELEMENT_SEP, parent_type->member_names[child_num]);
}
}
if(type->num_child_types == 0
|| (address == selement->address && type == selement->type)) {
return MAGIC_TYPE_WALK_STOP;
}
return MAGIC_TYPE_WALK_CONTINUE;
}
/*===========================================================================*
* magic_selement_name_get_cb *
*===========================================================================*/
PUBLIC int magic_selement_name_get_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 *args_array)
{
void **cb_args = (void **) args_array;
_magic_selement_t *selement = (_magic_selement_t*) cb_args[0];
char **buf = (char **) cb_args + 1;
int count, *buf_size = (int *) cb_args + 2;
short is_array = type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR;
struct _magic_sentry *sentry = selement->sentry;
void *address = (char *)sentry->address + offset;
void *range[2];
MAGIC_RANGE_SET_MIN(range, address);
MAGIC_RANGE_SET_MAX(range, (char *) address + type->size - 1);
if (!MAGIC_ADDR_IS_IN_RANGE(selement->address, range)) {
return MAGIC_TYPE_WALK_SKIP_PATH;
}
if (address == sentry->address && type == sentry->type) {
if (!(sentry->flags & MAGIC_STATE_DYNAMIC)) {
count = snprintf(*buf, *buf_size, "%s", sentry->name);
if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP; /* Buffer too small. */
*buf += count;
*buf_size -= count;
} else {
struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
assert(dsentry->parent_name && strcmp(dsentry->parent_name, ""));
assert(sentry->name && strcmp(sentry->name, ""));
count = snprintf(*buf, *buf_size, "%lu%s%s%s%s%s" MAGIC_ID_FORMAT,
(unsigned long)MAGIC_SENTRY_ID(sentry), MAGIC_DSENTRY_ABS_NAME_SEP,
dsentry->parent_name, MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name,
MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->site_id);
if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP; /* Buffer too small. */
*buf += count;
*buf_size -= count;
}
} else {
short is_parent_array = parent_type->type_id == MAGIC_TYPE_ARRAY ||
parent_type->type_id == MAGIC_TYPE_VECTOR;
if (is_parent_array) {
count = snprintf(*buf, *buf_size, "%s%d",
MAGIC_SELEMENT_SEP, child_num);
if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP; /* Buffer too small. */
*buf += count;
*buf_size -= count;
} else {
count = snprintf(*buf, *buf_size, "%s%s",
MAGIC_SELEMENT_SEP, parent_type->member_names[child_num]);
if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP; /* Buffer too small. */
*buf += count;
*buf_size -= count;
}
}
if (type->num_child_types == 0
|| (address == selement->address && type == selement->type)
|| (is_array && address == selement->address && type == selement->parent_type)) {
return MAGIC_TYPE_WALK_STOP;
}
return MAGIC_TYPE_WALK_CONTINUE;
}
/*===========================================================================*
* magic_selement_print_value *
*===========================================================================*/
PUBLIC void magic_selement_print_value(const _magic_selement_t *selement)
{
int type_id = selement->type->type_id;
unsigned size = selement->type->size;
double dvalue;
void *pvalue;
unsigned long uvalue;
long ivalue;
char vvalue;
switch(type_id) {
case MAGIC_TYPE_FLOAT:
dvalue = magic_selement_to_float(selement);
_magic_printf("float(%d):%g", size, dvalue);
_magic_printf("/%d", (long) dvalue);
break;
case MAGIC_TYPE_POINTER:
pvalue = magic_selement_to_ptr(selement);
_magic_printf("ptr:%08x", pvalue);
break;
case MAGIC_TYPE_INTEGER:
case MAGIC_TYPE_ENUM:
if(MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_UNSIGNED)) {
uvalue = magic_selement_to_unsigned(selement);
_magic_printf("unsigned %s(%d):%u", type_id == MAGIC_TYPE_INTEGER ? "int" : "enum", size, uvalue);
}
else {
ivalue = magic_selement_to_int(selement);
_magic_printf("%s(%d):%d", type_id == MAGIC_TYPE_INTEGER ? "int" : "enum", size, ivalue);
}
break;
case MAGIC_TYPE_VOID:
vvalue = *((char*) selement->address);
_magic_printf("void(%d):%d", size, vvalue);
break;
default:
_magic_printf("???");
break;
}
}
/*===========================================================================*
* magic_selement_to_unsigned *
*===========================================================================*/
PUBLIC unsigned long magic_selement_to_unsigned(const _magic_selement_t *selement)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
unsigned long value = 0;
unsigned size = type->size;
assert(size > 0);
assert(type->type_id == MAGIC_TYPE_INTEGER
|| type->type_id == MAGIC_TYPE_ENUM);
if(address == NULL)
return 0;
if(size == sizeof(unsigned char)) {
value = (unsigned long) *((unsigned char*) address);
}
else if(size == sizeof(unsigned short)) {
value = (unsigned long) *((unsigned short*) address);
}
#ifdef MAGIC_LONG_LONG_SUPPORTED
else if(size == sizeof(unsigned long long)) {
value = (unsigned long) *((unsigned long long*) address);
}
#endif
else {
assert(size == sizeof(unsigned long));
value = *((unsigned long*) address);
}
return value;
}
/*===========================================================================*
* magic_selement_to_int *
*===========================================================================*/
PUBLIC long magic_selement_to_int(const _magic_selement_t *selement)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
long value = 0;
unsigned size = type->size;
assert(size > 0);
assert(type->type_id == MAGIC_TYPE_INTEGER
|| type->type_id == MAGIC_TYPE_ENUM);
if(address == NULL)
return 0;
if(size == sizeof(char)) {
value = (long) *((char*) address);
}
else if(size == sizeof(short)) {
value = (long) *((short*) address);
}
#ifdef MAGIC_LONG_LONG_SUPPORTED
else if(size == sizeof(long long)) {
value = (long) *((long long*) address);
}
#endif
else {
assert(size == sizeof(long));
value = *((long*) address);
}
return value;
}
#ifdef MAGIC_LONG_LONG_SUPPORTED
/*===========================================================================*
* magic_selement_to_llu *
*===========================================================================*/
PUBLIC unsigned long long magic_selement_to_llu(const _magic_selement_t *selement)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
unsigned long long value;
unsigned size = type->size;
if(address == NULL)
return 0;
if (size == sizeof(unsigned long long))
value = *((unsigned long long*) address);
else
value = (unsigned long long) magic_selement_to_unsigned(selement);
return value;
}
/*===========================================================================*
* magic_selement_to_ll *
*===========================================================================*/
PUBLIC long long magic_selement_to_ll(const _magic_selement_t *selement)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
long long value;
unsigned size = type->size;
if(address == NULL)
return 0;
if (size == sizeof(long long))
value = *((long long*) address);
else
value = (long long) magic_selement_to_int(selement);
return value;
}
#endif
/*===========================================================================*
* magic_selement_to_float *
*===========================================================================*/
PUBLIC double magic_selement_to_float(const _magic_selement_t *selement)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
double value = 0.0;
unsigned size = type->size;
assert(size > 0);
assert(type->type_id == MAGIC_TYPE_FLOAT);
if(address == NULL)
return 0;
if(size == sizeof(float)) {
value = (double) *((float*) address);
}
#ifdef MAGIC_LONG_DOUBLE_SUPPORTED
else if(size == sizeof(long double)) {
value = (double) *((long double*) address);
}
#endif
else {
assert(size == sizeof(double));
value = *((double*) address);
}
return value;
}
/*===========================================================================*
* magic_selement_to_ptr *
*===========================================================================*/
PUBLIC void* magic_selement_to_ptr(const _magic_selement_t *selement)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
void* value = NULL;
assert(type->type_id == MAGIC_TYPE_POINTER);
if (!address)
return NULL;
value = *((void**) address);
return value;
}
/*===========================================================================*
* magic_selement_from_unsigned *
*===========================================================================*/
PUBLIC void magic_selement_from_unsigned(const _magic_selement_t *selement, unsigned long value)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
unsigned size = type->size;
assert(size > 0);
assert(type->type_id == MAGIC_TYPE_INTEGER
|| type->type_id == MAGIC_TYPE_ENUM);
/* Prevent a store to NULL. */
if(address == NULL)
return;
if(size == sizeof(unsigned char)) {
*((unsigned char*) address) = (unsigned char) value;
}
else if(size == sizeof(unsigned short)) {
*((unsigned short*) address) = (unsigned short) value;
}
#ifdef MAGIC_LONG_LONG_SUPPORTED
else if(size == sizeof(unsigned long long)) {
*((unsigned long long*) address) = (unsigned long long) value;
}
#endif
else {
assert(size == sizeof(unsigned long));
*((unsigned long*) address) = (unsigned long) value;
}
}
/*===========================================================================*
* magic_selement_from_int *
*===========================================================================*/
PUBLIC void magic_selement_from_int(const _magic_selement_t *selement, long value)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
unsigned size = type->size;
assert(size > 0);
assert(type->type_id == MAGIC_TYPE_INTEGER
|| type->type_id == MAGIC_TYPE_ENUM);
/* Prevent a store to NULL. */
if(address == NULL)
return;
if(size == sizeof(char)) {
*((char*) address) = (char) value;
}
else if(size == sizeof(short)) {
*((short*) address) = (short) value;
}
#ifdef MAGIC_LONG_LONG_SUPPORTED
else if(size == sizeof(long long)) {
*((long long*) address) = (long long) value;
}
#endif
else {
assert(size == sizeof(long));
*((long*) address) = (long) value;
}
}
/*===========================================================================*
* magic_selement_from_float *
*===========================================================================*/
PUBLIC void magic_selement_from_float(const _magic_selement_t *selement, double value)
{
void *address = selement->address;
const struct _magic_type* type = selement->type;
unsigned size = type->size;
assert(size > 0);
assert(type->type_id == MAGIC_TYPE_FLOAT);
/* Prevent a store to NULL. */
if(address == NULL)
return;
if(size == sizeof(float)) {
*((float*) address) = (float) value;
}
#ifdef MAGIC_LONG_DOUBLE_SUPPORTED
else if(size == sizeof(long double)) {
*((long double*) address) = (long double) value;
}
#endif
else {
assert(size == sizeof(double));
*((double*) address) = (double) value;
}
}
/*===========================================================================*
* magic_selement_ptr_value_cast *
*===========================================================================*/
PUBLIC int magic_selement_ptr_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
{
int src_type_id = src_selement->type->type_id;
int dst_type_id = dst_selement->type->type_id;
unsigned src_size = src_selement->type->size;
unsigned dst_size = dst_selement->type->size;
void* src_value;
int r = 0;
assert(dst_size > 0);
if(dst_type_id != MAGIC_TYPE_POINTER) {
return EINVAL;
}
assert(dst_size == sizeof(void*));
if(src_size != sizeof(void*)) {
return EINVAL;
}
switch(src_type_id) {
case MAGIC_TYPE_POINTER:
return 0;
break;
case MAGIC_TYPE_INTEGER:
if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, void*, &r, 0);
assert(r == 0);
}
else {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, void*, &r, 0);
assert(r == 0);
}
break;
default:
return EINVAL;
break;
}
MAGIC_CHECKED_VALUE_DST_CAST(src_value, void*, value_buffer, void*, &r);
assert(r == 0);
return dst_size;
}
/*===========================================================================*
* magic_selement_unsigned_value_cast *
*===========================================================================*/
PUBLIC int magic_selement_unsigned_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
{
int src_type_id = src_selement->type->type_id;
int dst_type_id = dst_selement->type->type_id;
int r = 0;
unsigned src_size = src_selement->type->size;
unsigned dst_size = dst_selement->type->size;
unsigned long src_value;
assert(dst_size > 0);
if(dst_type_id != MAGIC_TYPE_INTEGER && dst_type_id != MAGIC_TYPE_ENUM) {
return EINVAL;
}
switch(src_type_id) {
case MAGIC_TYPE_FLOAT:
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, unsigned long, &r, 1);
break;
case MAGIC_TYPE_POINTER:
if(dst_size != sizeof(void*)) {
return EINVAL;
}
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_ptr(src_selement), void*, src_value, unsigned long, &r, 0);
assert(r == 0);
break;
case MAGIC_TYPE_INTEGER:
case MAGIC_TYPE_ENUM:
if(src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
return 0;
}
if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, unsigned long, &r, 0);
assert(r == 0);
}
else {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, unsigned long, &r, 1);
}
break;
default:
return EINVAL;
break;
}
switch(dst_size) {
case sizeof(unsigned char):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned char, &r);
break;
case sizeof(unsigned short):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned short, &r);
break;
case sizeof(unsigned int):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned int, &r);
break;
#ifdef MAGIC_LONG_LONG_SUPPORTED
case sizeof(unsigned long long):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned long long, &r);
break;
#endif
default:
return EINVAL;
break;
}
if(r == 0) {
r = dst_size;
}
return r;
}
/*===========================================================================*
* magic_selement_int_value_cast *
*===========================================================================*/
PUBLIC int magic_selement_int_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
{
int src_type_id = src_selement->type->type_id;
int dst_type_id = dst_selement->type->type_id;
int r = 0;
unsigned src_size = src_selement->type->size;
unsigned dst_size = dst_selement->type->size;
long src_value;
assert(dst_size > 0);
if(dst_type_id != MAGIC_TYPE_INTEGER && dst_type_id != MAGIC_TYPE_ENUM) {
return EINVAL;
}
switch(src_type_id) {
case MAGIC_TYPE_FLOAT:
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, long, &r, 1);
break;
case MAGIC_TYPE_POINTER:
if(dst_size != sizeof(void*)) {
return EINVAL;
}
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_ptr(src_selement), void*, src_value, long, &r, 0);
assert(r == 0);
break;
case MAGIC_TYPE_INTEGER:
case MAGIC_TYPE_ENUM:
if(src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
return 0;
}
if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, long, &r, 1);
}
else {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, long, &r, 0);
assert(r == 0);
}
break;
default:
return EINVAL;
break;
}
switch(dst_size) {
case sizeof(char):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, char, &r);
break;
case sizeof(short):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, short, &r);
break;
case sizeof(int):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, int, &r);
break;
#ifdef MAGIC_LONG_LONG_SUPPORTED
case sizeof(long long):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, long long, &r);
break;
#endif
default:
return EINVAL;
break;
}
if(r == 0) {
r = dst_size;
}
return r;
}
/*===========================================================================*
* magic_selement_float_value_cast *
*===========================================================================*/
PUBLIC int magic_selement_float_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
{
int src_type_id = src_selement->type->type_id;
int dst_type_id = dst_selement->type->type_id;
int r = 0;
unsigned src_size = src_selement->type->size;
unsigned dst_size = dst_selement->type->size;
double src_value;
assert(dst_size > 0);
if(dst_type_id != MAGIC_TYPE_FLOAT) {
return EINVAL;
}
switch(src_type_id) {
case MAGIC_TYPE_FLOAT:
if(src_size == dst_size) {
return 0;
}
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, double, &r, 0);
assert(r == 0);
break;
case MAGIC_TYPE_INTEGER:
case MAGIC_TYPE_ENUM:
if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, double, &r, 1);
}
else {
MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, double, &r, 1);
}
break;
default:
return EINVAL;
break;
}
switch(dst_size) {
case sizeof(float):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, float, &r);
break;
case sizeof(double):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, double, &r);
break;
#ifdef MAGIC_LONG_DOUBLE_SUPPORTED
case sizeof(long double):
MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, long double, &r);
break;
#endif
default:
return EINVAL;
break;
}
if(r == 0) {
r = dst_size;
}
return r;
}
/*===========================================================================*
* magic_selement_value_cast *
*===========================================================================*/
PUBLIC int magic_selement_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
{
int r, src_type_id, dst_type_id;
size_t src_size, dst_size;
src_type_id = src_selement->type->type_id;
dst_type_id = dst_selement->type->type_id;
src_size = src_selement->type->size;
dst_size = dst_selement->type->size;
if(src_type_id == dst_type_id && src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
return 0;
}
/* No size change allowed in opaque value casts. */
if(src_type_id == MAGIC_TYPE_OPAQUE || dst_type_id == MAGIC_TYPE_OPAQUE) {
return src_size == dst_size ? 0 : EINVAL;
}
/* No size change allowed in void value casts. */
if(src_type_id == MAGIC_TYPE_VOID || dst_type_id == MAGIC_TYPE_VOID) {
return src_size == dst_size ? 0 : EINVAL;
}
switch(dst_type_id) {
case MAGIC_TYPE_POINTER:
/* Cast to pointer values. */
r = magic_selement_ptr_value_cast(src_selement, dst_selement, value_buffer);
break;
case MAGIC_TYPE_FLOAT:
/* Cast to float values. */
r = magic_selement_float_value_cast(src_selement, dst_selement, value_buffer);
break;
case MAGIC_TYPE_INTEGER:
case MAGIC_TYPE_ENUM:
if(MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
/* Cast to unsigned values. */
r = magic_selement_unsigned_value_cast(src_selement, dst_selement, value_buffer);
}
else {
/* Cast to integer values. */
r = magic_selement_int_value_cast(src_selement, dst_selement, value_buffer);
}
break;
default:
r = EINVAL;
break;
}
return r;
}
/*===========================================================================*
* magic_selement_get_parent *
*===========================================================================*/
PUBLIC _magic_selement_t* magic_selement_get_parent(
const _magic_selement_t *selement, _magic_selement_t *parent_selement)
{
if(!selement->parent_type) {
return NULL;
}
parent_selement->sentry = selement->sentry;
parent_selement->parent_type = NULL;
parent_selement->child_num = 0;
parent_selement->type = selement->parent_type;
parent_selement->address = selement->parent_address;
parent_selement->num = 0;
assert(parent_selement->address >= parent_selement->sentry->address);
return parent_selement;
}
/*===========================================================================*
* magic_selement_fill_from_parent_info *
*===========================================================================*/
PUBLIC void magic_selement_fill_from_parent_info(_magic_selement_t *selement,
int walk_flags)
{
unsigned offset;
magic_type_walk_step(selement->parent_type,
selement->child_num, &selement->type, &offset, walk_flags);
selement->address = (char*) selement->parent_address + offset;
}
/*===========================================================================*
* magic_selement_from_sentry *
*===========================================================================*/
PUBLIC _magic_selement_t* magic_selement_from_sentry(struct _magic_sentry *sentry,
_magic_selement_t *selement)
{
selement->sentry = sentry;
selement->parent_type = NULL;
selement->child_num = 0;
selement->type = sentry->type;
selement->address = sentry->address;
selement->num = 1;
return selement;
}
/*===========================================================================*
* magic_selement_from_relative_name *
*===========================================================================*/
PUBLIC _magic_selement_t* magic_selement_from_relative_name(
_magic_selement_t *parent_selement, _magic_selement_t *selement, char* name)
{
_magic_selement_t new_parent_selement;
const struct _magic_type* parent_type = parent_selement->type;
int parent_type_id = parent_type->type_id;
int walk_flags = 0;
int i, child_num = -1;
char *end;
if(!name || *name == '\0') {
return NULL;
}
if(parent_type_id == MAGIC_TYPE_UNION && (*name >= '0' && *name <= '9')) {
parent_type_id = MAGIC_TYPE_ARRAY;
walk_flags = MAGIC_TYPE_WALK_UNIONS_AS_VOID;
}
switch(parent_type_id) {
case MAGIC_TYPE_ARRAY:
case MAGIC_TYPE_VECTOR:
child_num = (int) strtol(name, &end, 10);
if(end == name || *end != '\0' || errno == ERANGE) {
return NULL;
}
break;
case MAGIC_TYPE_STRUCT:
case MAGIC_TYPE_UNION:
for(i=0;i<parent_type->num_child_types;i++) {
if(!strcmp(parent_type->member_names[i], name)) {
child_num = i;
break;
}
}
if(i == parent_type->num_child_types) {
return NULL;
}
break;
case MAGIC_TYPE_POINTER:
i = magic_selement_recurse_ptr(parent_selement, selement, MAGIC_SELEMENT_MAX_PTR_RECURSIONS);
if(i <= 0 || i >= MAGIC_SELEMENT_MAX_PTR_RECURSIONS) {
return NULL;
}
new_parent_selement = *selement;
return magic_selement_from_relative_name(&new_parent_selement, selement, name);
break;
default:
return NULL;
break;
}
if(child_num != -1) {
selement->sentry = parent_selement->sentry;
selement->parent_type = parent_type;
selement->parent_address = parent_selement->address;
selement->child_num = child_num;
selement->num = parent_selement->num+1;
magic_selement_fill_from_parent_info(selement, walk_flags);
}
return selement;
}