xref: /minix/minix/lib/libmagicrt/magic_selement.c (revision e1cdaee1)
1 #include <magic_selement.h>
2 
3 /*===========================================================================*
4  *                      magic_selement_lookup_by_name                        *
5  *===========================================================================*/
6 PUBLIC int magic_selement_lookup_by_name(char *name,
7     _magic_selement_t *selement, struct _magic_dsentry *dsentry_buff)
8 {
9     char token_buff[MAGIC_MAX_NAME_LEN * 2 + 2];
10     char *token_start = name;
11     int last_num_seps = 0;
12     char *s;
13     if (!name || *name == '\0' || *name == MAGIC_SELEMENT_SEP[0]) {
14         return MAGIC_ENOENT;
15     }
16     for (s = name; *s; s++) {
17         if (*(s + 1) == '\0' || *(s + 1) == MAGIC_SELEMENT_SEP[0]) {
18             size_t len = s - token_start + 1;
19             if (len >= MAGIC_MAX_NAME_LEN * 2 + 1) {
20                 return MAGIC_ENOMEM;
21             }
22             strncpy(token_buff, token_start, len);
23             token_buff[len] = '\0';
24             if (token_start == name) {
25                 struct _magic_sentry *sentry;
26                 const char *sentry_parent_name = "", *sentry_name = NULL;
27                 char *delim = NULL;
28                 _magic_id_t dsentry_site_id = MAGIC_DSENTRY_SITE_ID_NULL;
29                 if (!(delim = strchr(token_buff, MAGIC_DSENTRY_ABS_NAME_SEP[0]))) {
30                     /* Regular sentry, no parent name or site_id. */
31                     sentry_name = token_buff;
32                 } else {
33                     /*
34                      * Dsentry. Will contain: sentry_id<DELIM>parent_name<DELIM>name<DELIM>site_id.
35                      */
36                     *delim = '\0';
37                     /* Skip sentry_id */
38                     sentry_parent_name = delim + 1;
39                     delim = strchr(delim + 1, MAGIC_DSENTRY_ABS_NAME_SEP[0]);
40                     assert(!delim && "No dsentry name found in selement name!");
41                     *delim = '\0';
42                     sentry_name = delim + 1;
43                     delim = strchr(delim + 1, MAGIC_DSENTRY_ABS_NAME_SEP[0]);
44                     assert(!delim && "No dsentry site id found in selement name!");
45                     *delim = '\0';
46                     dsentry_site_id = strtoul((const char*)delim+1, NULL, 10);
47                 }
48 
49                 sentry = magic_sentry_lookup_by_name(sentry_parent_name, sentry_name,
50                     dsentry_site_id, dsentry_buff);
51                 if (!sentry) {
52                     return MAGIC_ENOENT;
53                 }
54                 magic_selement_from_sentry(sentry, selement);
55             }
56             else {
57                 _magic_selement_t child_selement;
58                 if (!magic_selement_from_relative_name(selement, &child_selement, token_buff)) {
59                     return MAGIC_ENOENT;
60                 }
61                 *selement = child_selement;
62             }
63             s++;
64             last_num_seps = 0;
65             while (*s == MAGIC_SELEMENT_SEP[0]) {
66                 s++;
67                 last_num_seps++;
68             }
69             token_start = s;
70             s--;
71         }
72     }
73     if (last_num_seps > 0 && selement->type->type_id == MAGIC_TYPE_POINTER) {
74         int steps = magic_selement_recurse_ptr(selement, selement, last_num_seps);
75         if(steps != last_num_seps) {
76             return MAGIC_EINVAL;
77         }
78     }
79 
80     return 0;
81 }
82 
83 /*===========================================================================*
84  *                       magic_selement_name_print_cb                        *
85  *===========================================================================*/
86 PUBLIC int magic_selement_name_print_cb(const struct _magic_type* parent_type,
87     const unsigned parent_offset, int child_num,
88     const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
89 {
90     _magic_selement_t *selement = (_magic_selement_t*) cb_args;
91     struct _magic_sentry* sentry = selement->sentry;
92     void *address = (char*)sentry->address + offset;
93     void *range[2];
94     MAGIC_RANGE_SET_MIN(range, address);
95     MAGIC_RANGE_SET_MAX(range, (char*) address + type->size-1);
96     if(!MAGIC_ADDR_IS_IN_RANGE(selement->address, range)) {
97         return MAGIC_TYPE_WALK_SKIP_PATH;
98     }
99     if(address == sentry->address && type == sentry->type) {
100         magic_print_sentry_abs_name(sentry);
101     }
102     else {
103         short is_parent_array = parent_type->type_id == MAGIC_TYPE_ARRAY || parent_type->type_id == MAGIC_TYPE_VECTOR;
104         if(is_parent_array) {
105             _magic_printf("%s%d", MAGIC_SELEMENT_SEP, child_num);
106         }
107         else {
108             _magic_printf("%s%s", MAGIC_SELEMENT_SEP, parent_type->member_names[child_num]);
109         }
110     }
111     if(type->num_child_types == 0
112         || (address == selement->address && type == selement->type)) {
113         return MAGIC_TYPE_WALK_STOP;
114     }
115     return MAGIC_TYPE_WALK_CONTINUE;
116 }
117 
118 /*===========================================================================*
119  *                       magic_selement_name_get_cb                          *
120  *===========================================================================*/
121 PUBLIC int magic_selement_name_get_cb(const struct _magic_type *parent_type,
122     const unsigned parent_offset, int child_num, const struct _magic_type *type,
123     const unsigned offset, int depth, void *args_array)
124 {
125     void **cb_args = (void **) args_array;
126 
127     _magic_selement_t *selement = (_magic_selement_t*) cb_args[0];
128     char **buf = (char **) cb_args + 1;
129     int count, *buf_size = (int *) cb_args + 2;
130 
131     short is_array = type->type_id == MAGIC_TYPE_ARRAY || type->type_id == MAGIC_TYPE_VECTOR;
132 
133     struct _magic_sentry *sentry = selement->sentry;
134     void *address = (char *)sentry->address + offset;
135     void *range[2];
136     MAGIC_RANGE_SET_MIN(range, address);
137     MAGIC_RANGE_SET_MAX(range, (char *) address + type->size - 1);
138     if (!MAGIC_ADDR_IS_IN_RANGE(selement->address, range)) {
139         return MAGIC_TYPE_WALK_SKIP_PATH;
140     }
141 
142     if (address == sentry->address && type == sentry->type) {
143         if (!(sentry->flags & MAGIC_STATE_DYNAMIC)) {
144             count = snprintf(*buf, *buf_size, "%s", sentry->name);
145             if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
146             *buf += count;
147             *buf_size -= count;
148         } else {
149             struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(sentry);
150             assert(dsentry->parent_name && strcmp(dsentry->parent_name, ""));
151             assert(sentry->name && strcmp(sentry->name, ""));
152             count = snprintf(*buf, *buf_size, "%lu%s%s%s%s%s" MAGIC_ID_FORMAT,
153                 (unsigned long)MAGIC_SENTRY_ID(sentry), MAGIC_DSENTRY_ABS_NAME_SEP,
154                 dsentry->parent_name, MAGIC_DSENTRY_ABS_NAME_SEP, sentry->name,
155                 MAGIC_DSENTRY_ABS_NAME_SEP, dsentry->site_id);
156             if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
157             *buf += count;
158             *buf_size -= count;
159         }
160     } else {
161         short is_parent_array = parent_type->type_id == MAGIC_TYPE_ARRAY ||
162             parent_type->type_id == MAGIC_TYPE_VECTOR;
163         if (is_parent_array) {
164             count = snprintf(*buf, *buf_size, "%s%d",
165                 MAGIC_SELEMENT_SEP, child_num);
166             if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
167             *buf += count;
168             *buf_size -= count;
169         } else {
170             count = snprintf(*buf, *buf_size, "%s%s",
171                 MAGIC_SELEMENT_SEP, parent_type->member_names[child_num]);
172             if (count >= *buf_size) return MAGIC_TYPE_WALK_STOP;    /* Buffer too small. */
173             *buf += count;
174             *buf_size -= count;
175         }
176     }
177 
178     if (type->num_child_types == 0
179     || (address == selement->address && type == selement->type)
180     || (is_array && address == selement->address && type == selement->parent_type)) {
181         return MAGIC_TYPE_WALK_STOP;
182     }
183 
184     return MAGIC_TYPE_WALK_CONTINUE;
185 }
186 
187 /*===========================================================================*
188  *                        magic_selement_print_value                         *
189  *===========================================================================*/
190 PUBLIC void magic_selement_print_value(const _magic_selement_t *selement)
191 {
192     int type_id = selement->type->type_id;
193     unsigned size = selement->type->size;
194     double dvalue;
195     void *pvalue;
196     unsigned long uvalue;
197     long ivalue;
198     char vvalue;
199     switch(type_id) {
200         case MAGIC_TYPE_FLOAT:
201             dvalue = magic_selement_to_float(selement);
202             _magic_printf("float(%d):%g", size, dvalue);
203             _magic_printf("/%d", (long) dvalue);
204         break;
205 
206         case MAGIC_TYPE_POINTER:
207             pvalue = magic_selement_to_ptr(selement);
208             _magic_printf("ptr:%08x", pvalue);
209         break;
210 
211         case MAGIC_TYPE_INTEGER:
212         case MAGIC_TYPE_ENUM:
213             if(MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_UNSIGNED)) {
214                 uvalue = magic_selement_to_unsigned(selement);
215                 _magic_printf("unsigned %s(%d):%u", type_id == MAGIC_TYPE_INTEGER ? "int" : "enum", size, uvalue);
216             }
217             else {
218                 ivalue = magic_selement_to_int(selement);
219                 _magic_printf("%s(%d):%d", type_id == MAGIC_TYPE_INTEGER ? "int" : "enum", size, ivalue);
220             }
221         break;
222 
223         case MAGIC_TYPE_VOID:
224             vvalue = *((char*) selement->address);
225             _magic_printf("void(%d):%d", size, vvalue);
226         break;
227 
228         default:
229             _magic_printf("???");
230         break;
231     }
232 }
233 
234 /*===========================================================================*
235  *                         magic_selement_to_unsigned                        *
236  *===========================================================================*/
237 PUBLIC unsigned long magic_selement_to_unsigned(const _magic_selement_t *selement)
238 {
239     void *address = selement->address;
240     const struct _magic_type* type = selement->type;
241     unsigned long value = 0;
242     unsigned size = type->size;
243     assert(size > 0);
244     assert(type->type_id == MAGIC_TYPE_INTEGER
245         || type->type_id == MAGIC_TYPE_ENUM);
246 
247     if(address == NULL)
248 	return 0;
249 
250     if(size == sizeof(unsigned char)) {
251         value = (unsigned long) *((unsigned char*) address);
252     }
253     else if(size == sizeof(unsigned short)) {
254         value = (unsigned long) *((unsigned short*) address);
255     }
256 #ifdef MAGIC_LONG_LONG_SUPPORTED
257     else if(size == sizeof(unsigned long long)) {
258         value = (unsigned long) *((unsigned long long*) address);
259     }
260 #endif
261     else {
262         assert(size == sizeof(unsigned long));
263         value = *((unsigned long*) address);
264     }
265 
266     return value;
267 }
268 
269 /*===========================================================================*
270  *                           magic_selement_to_int                           *
271  *===========================================================================*/
272 PUBLIC long magic_selement_to_int(const _magic_selement_t *selement)
273 {
274     void *address = selement->address;
275     const struct _magic_type* type = selement->type;
276     long value = 0;
277     unsigned size = type->size;
278     assert(size > 0);
279     assert(type->type_id == MAGIC_TYPE_INTEGER
280         || type->type_id == MAGIC_TYPE_ENUM);
281 
282     if(address == NULL)
283 	return 0;
284 
285     if(size == sizeof(char)) {
286         value = (long) *((char*) address);
287     }
288     else if(size == sizeof(short)) {
289         value = (long) *((short*) address);
290     }
291 #ifdef MAGIC_LONG_LONG_SUPPORTED
292     else if(size == sizeof(long long)) {
293         value = (long) *((long long*) address);
294     }
295 #endif
296     else {
297         assert(size == sizeof(long));
298         value = *((long*) address);
299     }
300 
301     return value;
302 }
303 
304 #ifdef MAGIC_LONG_LONG_SUPPORTED
305 /*===========================================================================*
306  *                            magic_selement_to_llu                          *
307  *===========================================================================*/
308 PUBLIC unsigned long long magic_selement_to_llu(const _magic_selement_t *selement)
309 {
310     void *address = selement->address;
311     const struct _magic_type* type = selement->type;
312     unsigned long long value;
313     unsigned size = type->size;
314 
315     if(address == NULL)
316 	return 0;
317 
318     if (size == sizeof(unsigned long long))
319         value = *((unsigned long long*) address);
320     else
321         value = (unsigned long long) magic_selement_to_unsigned(selement);
322     return value;
323 }
324 
325 /*===========================================================================*
326  *                            magic_selement_to_ll                           *
327  *===========================================================================*/
328 PUBLIC long long magic_selement_to_ll(const _magic_selement_t *selement)
329 {
330     void *address = selement->address;
331     const struct _magic_type* type = selement->type;
332     long long value;
333     unsigned size = type->size;
334 
335     if(address == NULL)
336 	return 0;
337 
338     if (size == sizeof(long long))
339         value = *((long long*) address);
340     else
341         value = (long long) magic_selement_to_int(selement);
342     return value;
343 }
344 #endif
345 
346 /*===========================================================================*
347  *                          magic_selement_to_float                          *
348  *===========================================================================*/
349 PUBLIC double magic_selement_to_float(const _magic_selement_t *selement)
350 {
351     void *address = selement->address;
352     const struct _magic_type* type = selement->type;
353     double value = 0.0;
354     unsigned size = type->size;
355     assert(size > 0);
356     assert(type->type_id == MAGIC_TYPE_FLOAT);
357 
358     if(address == NULL)
359 	return 0;
360 
361     if(size == sizeof(float)) {
362         value = (double) *((float*) address);
363     }
364 #ifdef MAGIC_LONG_DOUBLE_SUPPORTED
365     else if(size == sizeof(long double)) {
366         value = (double) *((long double*) address);
367     }
368 #endif
369     else {
370         assert(size == sizeof(double));
371         value = *((double*) address);
372     }
373 
374     return value;
375 }
376 
377 /*===========================================================================*
378  *                           magic_selement_to_ptr                           *
379  *===========================================================================*/
380 PUBLIC void* magic_selement_to_ptr(const _magic_selement_t *selement)
381 {
382     void *address = selement->address;
383     const struct _magic_type* type = selement->type;
384     void* value = NULL;
385     assert(type->type_id == MAGIC_TYPE_POINTER);
386 
387     if (!address)
388         return NULL;
389     value = *((void**) address);
390     return value;
391 }
392 
393 /*===========================================================================*
394  *                         magic_selement_from_unsigned                      *
395  *===========================================================================*/
396 PUBLIC void magic_selement_from_unsigned(const _magic_selement_t *selement, unsigned long value)
397 {
398     void *address = selement->address;
399     const struct _magic_type* type = selement->type;
400     unsigned size = type->size;
401     assert(size > 0);
402     assert(type->type_id == MAGIC_TYPE_INTEGER
403         || type->type_id == MAGIC_TYPE_ENUM);
404 
405     /* Prevent a store to NULL. */
406     if(address == NULL)
407 	return;
408 
409     if(size == sizeof(unsigned char)) {
410         *((unsigned char*) address) = (unsigned char) value;
411     }
412     else if(size == sizeof(unsigned short)) {
413         *((unsigned short*) address) = (unsigned short) value;
414     }
415 #ifdef MAGIC_LONG_LONG_SUPPORTED
416     else if(size == sizeof(unsigned long long)) {
417         *((unsigned long long*) address) = (unsigned long long) value;
418     }
419 #endif
420     else {
421         assert(size == sizeof(unsigned long));
422         *((unsigned long*) address) = (unsigned long) value;
423     }
424 }
425 
426 /*===========================================================================*
427  *                           magic_selement_from_int                         *
428  *===========================================================================*/
429 PUBLIC void magic_selement_from_int(const _magic_selement_t *selement, long value)
430 {
431     void *address = selement->address;
432     const struct _magic_type* type = selement->type;
433     unsigned size = type->size;
434     assert(size > 0);
435     assert(type->type_id == MAGIC_TYPE_INTEGER
436         || type->type_id == MAGIC_TYPE_ENUM);
437 
438     /* Prevent a store to NULL. */
439     if(address == NULL)
440 	return;
441 
442     if(size == sizeof(char)) {
443         *((char*) address) = (char) value;
444     }
445     else if(size == sizeof(short)) {
446         *((short*) address) = (short) value;
447     }
448 #ifdef MAGIC_LONG_LONG_SUPPORTED
449     else if(size == sizeof(long long)) {
450         *((long long*) address) = (long long) value;
451     }
452 #endif
453     else {
454         assert(size == sizeof(long));
455         *((long*) address) = (long) value;
456     }
457 }
458 
459 /*===========================================================================*
460  *                          magic_selement_from_float                        *
461  *===========================================================================*/
462 PUBLIC void magic_selement_from_float(const _magic_selement_t *selement, double value)
463 {
464     void *address = selement->address;
465     const struct _magic_type* type = selement->type;
466     unsigned size = type->size;
467     assert(size > 0);
468     assert(type->type_id == MAGIC_TYPE_FLOAT);
469 
470     /* Prevent a store to NULL. */
471     if(address == NULL)
472 	return;
473 
474     if(size == sizeof(float)) {
475         *((float*) address) = (float) value;
476     }
477 #ifdef MAGIC_LONG_DOUBLE_SUPPORTED
478     else if(size == sizeof(long double)) {
479         *((long double*) address) = (long double) value;
480     }
481 #endif
482     else {
483         assert(size == sizeof(double));
484         *((double*) address) = (double) value;
485     }
486 }
487 
488 /*===========================================================================*
489  *                      magic_selement_ptr_value_cast                        *
490  *===========================================================================*/
491 PUBLIC int magic_selement_ptr_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
492 {
493     int src_type_id = src_selement->type->type_id;
494     int dst_type_id = dst_selement->type->type_id;
495     unsigned src_size = src_selement->type->size;
496     unsigned dst_size = dst_selement->type->size;
497     void* src_value;
498     int r = 0;
499     assert(dst_size > 0);
500 
501     if(dst_type_id != MAGIC_TYPE_POINTER) {
502         return EINVAL;
503     }
504     assert(dst_size == sizeof(void*));
505     if(src_size != sizeof(void*)) {
506         return EINVAL;
507     }
508     switch(src_type_id) {
509         case MAGIC_TYPE_POINTER:
510             return 0;
511         break;
512 
513         case MAGIC_TYPE_INTEGER:
514             if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
515                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, void*, &r, 0);
516                 assert(r == 0);
517             }
518             else {
519                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, void*, &r, 0);
520                 assert(r == 0);
521             }
522         break;
523 
524         default:
525             return EINVAL;
526         break;
527     }
528 
529     MAGIC_CHECKED_VALUE_DST_CAST(src_value, void*, value_buffer, void*, &r);
530     assert(r == 0);
531 
532     return dst_size;
533 }
534 
535 /*===========================================================================*
536  *                    magic_selement_unsigned_value_cast                     *
537  *===========================================================================*/
538 PUBLIC int magic_selement_unsigned_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
539 {
540     int src_type_id = src_selement->type->type_id;
541     int dst_type_id = dst_selement->type->type_id;
542     int r = 0;
543     unsigned src_size = src_selement->type->size;
544     unsigned dst_size = dst_selement->type->size;
545     unsigned long src_value;
546     assert(dst_size > 0);
547 
548     if(dst_type_id != MAGIC_TYPE_INTEGER && dst_type_id != MAGIC_TYPE_ENUM) {
549         return EINVAL;
550     }
551     switch(src_type_id) {
552         case MAGIC_TYPE_FLOAT:
553             MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, unsigned long, &r, 1);
554         break;
555 
556         case MAGIC_TYPE_POINTER:
557             if(dst_size != sizeof(void*)) {
558                 return EINVAL;
559             }
560             MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_ptr(src_selement), void*, src_value, unsigned long, &r, 0);
561             assert(r == 0);
562         break;
563 
564         case MAGIC_TYPE_INTEGER:
565         case MAGIC_TYPE_ENUM:
566             if(src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
567                 return 0;
568             }
569             if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
570                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, unsigned long, &r, 0);
571                 assert(r == 0);
572             }
573             else {
574                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, unsigned long, &r, 1);
575             }
576         break;
577 
578         default:
579             return EINVAL;
580         break;
581     }
582 
583     switch(dst_size) {
584         case sizeof(unsigned char):
585             MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned char, &r);
586         break;
587 
588         case sizeof(unsigned short):
589             MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned short, &r);
590         break;
591 
592         case sizeof(unsigned int):
593             MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned int, &r);
594         break;
595 
596 #ifdef MAGIC_LONG_LONG_SUPPORTED
597         case sizeof(unsigned long long):
598             MAGIC_CHECKED_VALUE_DST_CAST(src_value, unsigned long, value_buffer, unsigned long long, &r);
599         break;
600 #endif
601 
602         default:
603             return EINVAL;
604         break;
605     }
606 
607     if(r == 0) {
608         r = dst_size;
609     }
610 
611     return r;
612 }
613 
614 /*===========================================================================*
615  *                      magic_selement_int_value_cast                        *
616  *===========================================================================*/
617 PUBLIC int magic_selement_int_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
618 {
619     int src_type_id = src_selement->type->type_id;
620     int dst_type_id = dst_selement->type->type_id;
621     int r = 0;
622     unsigned src_size = src_selement->type->size;
623     unsigned dst_size = dst_selement->type->size;
624     long src_value;
625     assert(dst_size > 0);
626 
627     if(dst_type_id != MAGIC_TYPE_INTEGER && dst_type_id != MAGIC_TYPE_ENUM) {
628         return EINVAL;
629     }
630 
631     switch(src_type_id) {
632         case MAGIC_TYPE_FLOAT:
633             MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, long, &r, 1);
634         break;
635 
636         case MAGIC_TYPE_POINTER:
637             if(dst_size != sizeof(void*)) {
638                 return EINVAL;
639             }
640             MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_ptr(src_selement), void*, src_value, long, &r, 0);
641             assert(r == 0);
642         break;
643 
644         case MAGIC_TYPE_INTEGER:
645         case MAGIC_TYPE_ENUM:
646             if(src_size == dst_size && MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED) == MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
647                 return 0;
648             }
649             if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
650                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, long, &r, 1);
651             }
652             else {
653                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, long, &r, 0);
654                 assert(r == 0);
655             }
656         break;
657 
658         default:
659             return EINVAL;
660         break;
661     }
662 
663     switch(dst_size) {
664         case sizeof(char):
665             MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, char, &r);
666         break;
667 
668         case sizeof(short):
669             MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, short, &r);
670         break;
671 
672         case sizeof(int):
673             MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, int, &r);
674         break;
675 
676 #ifdef MAGIC_LONG_LONG_SUPPORTED
677         case sizeof(long long):
678             MAGIC_CHECKED_VALUE_DST_CAST(src_value, long, value_buffer, long long, &r);
679         break;
680 #endif
681 
682         default:
683             return EINVAL;
684         break;
685     }
686 
687     if(r == 0) {
688         r = dst_size;
689     }
690 
691     return r;
692 }
693 
694 /*===========================================================================*
695  *                      magic_selement_float_value_cast                      *
696  *===========================================================================*/
697 PUBLIC int magic_selement_float_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
698 {
699     int src_type_id = src_selement->type->type_id;
700     int dst_type_id = dst_selement->type->type_id;
701     int r = 0;
702     unsigned src_size = src_selement->type->size;
703     unsigned dst_size = dst_selement->type->size;
704     double src_value;
705     assert(dst_size > 0);
706 
707     if(dst_type_id != MAGIC_TYPE_FLOAT) {
708         return EINVAL;
709     }
710     switch(src_type_id) {
711         case MAGIC_TYPE_FLOAT:
712             if(src_size == dst_size) {
713                 return 0;
714             }
715             MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_float(src_selement), double, src_value, double, &r, 0);
716             assert(r == 0);
717         break;
718 
719         case MAGIC_TYPE_INTEGER:
720         case MAGIC_TYPE_ENUM:
721             if(MAGIC_TYPE_FLAG(src_selement->type, MAGIC_TYPE_UNSIGNED)) {
722                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_unsigned(src_selement), unsigned long, src_value, double, &r, 1);
723             }
724             else {
725                 MAGIC_CHECKED_VALUE_SRC_CAST(magic_selement_to_int(src_selement), long, src_value, double, &r, 1);
726             }
727         break;
728 
729         default:
730             return EINVAL;
731         break;
732     }
733 
734 
735     switch(dst_size) {
736         case sizeof(float):
737             MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, float, &r);
738         break;
739 
740         case sizeof(double):
741             MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, double, &r);
742         break;
743 
744 #ifdef MAGIC_LONG_DOUBLE_SUPPORTED
745         case sizeof(long double):
746             MAGIC_CHECKED_VALUE_DST_CAST(src_value, double, value_buffer, long double, &r);
747         break;
748 #endif
749 
750         default:
751             return EINVAL;
752         break;
753     }
754 
755     if(r == 0) {
756         r = dst_size;
757     }
758 
759     return r;
760 }
761 
762 /*===========================================================================*
763  *                         magic_selement_value_cast                         *
764  *===========================================================================*/
765 PUBLIC int magic_selement_value_cast(const _magic_selement_t *src_selement, const _magic_selement_t *dst_selement, void* value_buffer)
766 {
767     int r, src_type_id, dst_type_id;
768     size_t src_size, dst_size;
769     src_type_id = src_selement->type->type_id;
770     dst_type_id = dst_selement->type->type_id;
771     src_size = src_selement->type->size;
772     dst_size = dst_selement->type->size;
773     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)) {
774         return 0;
775     }
776 
777     /* No size change allowed in opaque value casts. */
778     if(src_type_id == MAGIC_TYPE_OPAQUE || dst_type_id == MAGIC_TYPE_OPAQUE) {
779         return src_size == dst_size ? 0 : EINVAL;
780     }
781 
782     /* No size change allowed in void value casts. */
783     if(src_type_id == MAGIC_TYPE_VOID || dst_type_id == MAGIC_TYPE_VOID) {
784         return src_size == dst_size ? 0 : EINVAL;
785     }
786 
787     switch(dst_type_id) {
788         case MAGIC_TYPE_POINTER:
789             /* Cast to pointer values. */
790             r = magic_selement_ptr_value_cast(src_selement, dst_selement, value_buffer);
791         break;
792 
793         case MAGIC_TYPE_FLOAT:
794             /* Cast to float values. */
795             r = magic_selement_float_value_cast(src_selement, dst_selement, value_buffer);
796         break;
797 
798         case MAGIC_TYPE_INTEGER:
799         case MAGIC_TYPE_ENUM:
800             if(MAGIC_TYPE_FLAG(dst_selement->type, MAGIC_TYPE_UNSIGNED)) {
801                 /* Cast to unsigned values. */
802                 r = magic_selement_unsigned_value_cast(src_selement, dst_selement, value_buffer);
803             }
804             else {
805                 /* Cast to integer values. */
806                 r = magic_selement_int_value_cast(src_selement, dst_selement, value_buffer);
807             }
808         break;
809 
810         default:
811             r = EINVAL;
812         break;
813     }
814     return r;
815 }
816 
817 /*===========================================================================*
818  *                         magic_selement_get_parent                         *
819  *===========================================================================*/
820 PUBLIC _magic_selement_t* magic_selement_get_parent(
821     const _magic_selement_t *selement, _magic_selement_t *parent_selement)
822 {
823     if(!selement->parent_type) {
824         return NULL;
825     }
826 
827     parent_selement->sentry = selement->sentry;
828     parent_selement->parent_type = NULL;
829     parent_selement->child_num = 0;
830     parent_selement->type = selement->parent_type;
831     parent_selement->address = selement->parent_address;
832     parent_selement->num = 0;
833     assert(parent_selement->address >= parent_selement->sentry->address);
834 
835     return parent_selement;
836 }
837 
838 /*===========================================================================*
839  *                    magic_selement_fill_from_parent_info                   *
840  *===========================================================================*/
841 PUBLIC void magic_selement_fill_from_parent_info(_magic_selement_t *selement,
842     int walk_flags)
843 {
844     unsigned offset;
845     magic_type_walk_step(selement->parent_type,
846         selement->child_num, &selement->type, &offset, walk_flags);
847     selement->address = (char*) selement->parent_address + offset;
848 }
849 
850 /*===========================================================================*
851  *                         magic_selement_from_sentry                        *
852  *===========================================================================*/
853 PUBLIC _magic_selement_t* magic_selement_from_sentry(struct _magic_sentry *sentry,
854     _magic_selement_t *selement)
855 {
856     selement->sentry = sentry;
857     selement->parent_type = NULL;
858     selement->child_num = 0;
859     selement->type = sentry->type;
860     selement->address = sentry->address;
861     selement->num = 1;
862 
863     return selement;
864 }
865 
866 /*===========================================================================*
867  *                      magic_selement_from_relative_name                    *
868  *===========================================================================*/
869 PUBLIC _magic_selement_t* magic_selement_from_relative_name(
870     _magic_selement_t *parent_selement, _magic_selement_t *selement, char* name)
871 {
872     _magic_selement_t new_parent_selement;
873     const struct _magic_type* parent_type = parent_selement->type;
874     int parent_type_id = parent_type->type_id;
875     int walk_flags = 0;
876     int i, child_num = -1;
877     char *end;
878 
879     if(!name || *name == '\0') {
880         return NULL;
881     }
882 
883     if(parent_type_id == MAGIC_TYPE_UNION && (*name >= '0' && *name <= '9')) {
884         parent_type_id = MAGIC_TYPE_ARRAY;
885         walk_flags = MAGIC_TYPE_WALK_UNIONS_AS_VOID;
886     }
887 
888     switch(parent_type_id) {
889         case MAGIC_TYPE_ARRAY:
890         case MAGIC_TYPE_VECTOR:
891             child_num = (int) strtol(name, &end, 10);
892             if(end == name || *end != '\0' || errno == ERANGE) {
893                 return NULL;
894             }
895         break;
896 
897         case MAGIC_TYPE_STRUCT:
898         case MAGIC_TYPE_UNION:
899             for(i=0; (unsigned int)i<parent_type->num_child_types;i++) {
900                 if(!strcmp(parent_type->member_names[i], name)) {
901                     child_num = i;
902                     break;
903                 }
904             }
905             if((unsigned int)i == parent_type->num_child_types) {
906                 return NULL;
907             }
908         break;
909 
910         case MAGIC_TYPE_POINTER:
911             i = magic_selement_recurse_ptr(parent_selement, selement, MAGIC_SELEMENT_MAX_PTR_RECURSIONS);
912             if(i <= 0 || i >= MAGIC_SELEMENT_MAX_PTR_RECURSIONS) {
913                 return NULL;
914             }
915             new_parent_selement = *selement;
916             return magic_selement_from_relative_name(&new_parent_selement, selement, name);
917         break;
918 
919         default:
920             return NULL;
921         break;
922     }
923 
924     if(child_num != -1) {
925         selement->sentry = parent_selement->sentry;
926         selement->parent_type = parent_type;
927         selement->parent_address = parent_selement->address;
928         selement->child_num = child_num;
929         selement->num = parent_selement->num+1;
930         magic_selement_fill_from_parent_info(selement, walk_flags);
931     }
932 
933     return selement;
934 }
935 
936