xref: /minix/minix/lib/libmagicrt/magic_analysis.c (revision e1cdaee1)
1 
2 #include <magic_analysis.h>
3 
4 PUBLIC char magic_ne_str[] =  "NULL_TYPE";
5 PUBLIC char magic_enf_str[] = "UNKNOWN_TYPE";
6 PUBLIC char magic_bo_str[] =  "BAD_TYPE";
7 PUBLIC char magic_be_str[] =  "BAD_ENTRY_TYPE";
8 PUBLIC char magic_bv_str[] =  "BAD_VALUE_TYPE";
9 PUBLIC char magic_vf_str[] =  "VALUE_FOUND_TYPE";
10 PUBLIC const struct _magic_type magic_NULL_ENTRY_TYPE =      MAGIC_TYPE_SPECIAL_INIT(magic_ne_str);
11 PUBLIC const struct _magic_type magic_ENTRY_NOT_FOUND_TYPE = MAGIC_TYPE_SPECIAL_INIT(magic_enf_str);
12 PUBLIC const struct _magic_type magic_BAD_OFFSET_TYPE =      MAGIC_TYPE_SPECIAL_INIT(magic_bo_str);
13 PUBLIC const struct _magic_type magic_BAD_ENTRY_TYPE =       MAGIC_TYPE_SPECIAL_INIT(magic_be_str);
14 PUBLIC const struct _magic_type magic_BAD_VALUE_TYPE =       MAGIC_TYPE_SPECIAL_INIT(magic_bv_str);
15 PUBLIC const struct _magic_type magic_VALUE_FOUND =          MAGIC_TYPE_SPECIAL_INIT(magic_vf_str);
16 
17 PRIVATE magic_cb_sentries_analyze_pre_t magic_sentries_analyze_pre_cb = NULL;
18 
19 /*===========================================================================*
20  *                      magic_setcb_sentries_analyze_pre                     *
21  *===========================================================================*/
22 PUBLIC void magic_setcb_sentries_analyze_pre(magic_cb_sentries_analyze_pre_t cb)
23 {
24     magic_sentries_analyze_pre_cb = cb;
25 }
26 
27 /*===========================================================================*
28  *                        magic_sentry_print_ptr_types                       *
29  *===========================================================================*/
30 PUBLIC int magic_sentry_print_ptr_types(struct _magic_sentry* entry)
31 {
32     int ret, ptrs_found = 0;
33     void* args_array[2];
34     args_array[0] = entry;
35     args_array[1] = &ptrs_found;
36     ret = magic_type_walk_root_all(entry->type, magic_type_examine_ptr_cb, args_array);
37     assert(ret >= 0);
38     return ptrs_found;
39 }
40 
41 /*===========================================================================*
42  *                         magic_sentry_extract_ptrs                         *
43  *===========================================================================*/
44 PUBLIC int magic_sentry_extract_ptrs(struct _magic_sentry* entry, void ****ptr_map, const struct _magic_type ***ptr_type_map, int *ptr_num)
45 {
46     int from_wrapper = MAGIC_MEM_WRAPPER_IS_ACTIVE();
47     int ret = magic_type_count_ptrs(entry->type, ptr_num);
48     assert(ret == 0);
49     if(*ptr_num == 0) {
50         *ptr_map = NULL;
51         *ptr_type_map = NULL;
52     }
53     else {
54         void* args_array[4];
55         int ptr_num2 = 0;
56         if(!from_wrapper) {
57             MAGIC_MEM_WRAPPER_BEGIN();
58         }
59         *ptr_map = (void ***) malloc((*ptr_num)*sizeof(void **));
60         *ptr_type_map = (const struct _magic_type **) malloc((*ptr_num)*sizeof(const struct _magic_type *));
61         if(!from_wrapper) {
62             MAGIC_MEM_WRAPPER_END();
63         }
64         args_array[0] = entry;
65         args_array[1] = *ptr_map;
66         args_array[2] = *ptr_type_map;
67         args_array[3] = &ptr_num2;
68         ret = magic_type_walk_root_all(entry->type, magic_type_extract_ptr_cb, args_array);
69         assert(ret >= 0);
70         assert(*ptr_num == ptr_num2);
71     }
72     return 0;
73 }
74 
75 /*===========================================================================*
76  *                           magic_sentry_analyze                            *
77  *===========================================================================*/
78 PUBLIC int magic_sentry_analyze(struct _magic_sentry* sentry, int flags,
79     const magic_sentry_analyze_cb_t cb, void* cb_args,
80     _magic_sel_stats_t *sentry_stats)
81 {
82     int ret;
83     int selement_num = 0, sel_analyzed_num = 0;
84     void* args_array[7];
85     args_array[0] = (void*) &flags;
86     args_array[1] = (void*) __UNCONST(&cb);
87     args_array[2] = (void*) cb_args;
88     args_array[3] = (void*) sentry;
89     args_array[4] = (void*) sentry_stats;
90     args_array[5] = (void*) &selement_num;
91     args_array[6] = (void*) &sel_analyzed_num;
92     ret = magic_type_walk_root_all(sentry->type, magic_type_analyzer_cb,
93         args_array);
94     if(ret < 0) {
95         return ret;
96     }
97 
98     return flags;
99 }
100 
101 /*===========================================================================*
102  *                          magic_sentries_analyze                           *
103  *===========================================================================*/
104 PUBLIC int magic_sentries_analyze(int flags, const magic_sentry_analyze_cb_t cb,
105     void *cb_args, _magic_sel_stats_t *sentries_stats)
106 {
107     int i, ret;
108     struct _magic_sentry *sentry;
109 
110     if (flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)
111         magic_reentrant_disable();
112 
113     /* See if any pre-analyze callback has been registered. */
114     if (magic_sentries_analyze_pre_cb) {
115         ret = magic_sentries_analyze_pre_cb();
116         if (ret < 0) {
117             return ret;
118         }
119     }
120 
121     /* Analyze all the sentries. */
122     for (i = 0 ; i < _magic_sentries_num ; i++) {
123         sentry = &_magic_sentries[i];
124         ret = magic_sentry_analyze(sentry, flags, cb, cb_args, sentries_stats);
125         if (ret < 0) {
126             return ret;
127         }
128         else {
129             flags |= ret;
130         }
131     }
132 
133     /* Analyze all the dsentries if asked to. */
134     if (flags & MAGIC_SEL_ANALYZE_DYNAMIC) {
135         return magic_dsentries_analyze(flags, cb, cb_args, sentries_stats);
136     }
137 
138     if (flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)
139         magic_reentrant_enable();
140 
141     return flags;
142 }
143 
144 /*===========================================================================*
145  *                       magic_sentry_print_selements                        *
146  *===========================================================================*/
147 PUBLIC int magic_sentry_print_selements(struct _magic_sentry* sentry)
148 {
149     int flags = (MAGIC_SEL_ANALYZE_POINTERS|MAGIC_SEL_ANALYZE_NONPOINTERS|MAGIC_SEL_ANALYZE_DATA|MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS);
150     return magic_sentry_analyze(sentry, flags, magic_sentry_print_el_cb, NULL, NULL);
151 }
152 
153 /*===========================================================================*
154  *                     magic_sentry_print_ptr_selements                      *
155  *===========================================================================*/
156 PUBLIC int magic_sentry_print_ptr_selements(struct _magic_sentry* sentry,
157     int skip_null_ptrs, int max_target_recusions)
158 {
159     int flags = (MAGIC_SEL_ANALYZE_POINTERS|MAGIC_SEL_ANALYZE_DATA|MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS);
160     void* args_array[2];
161     args_array[0] = &skip_null_ptrs;
162     args_array[1] = &max_target_recusions;
163     return magic_sentry_analyze(sentry, flags, magic_sentry_print_ptr_el_cb, args_array, NULL);
164 }
165 
166 /*===========================================================================*
167  *                         magic_dsentries_analyze                           *
168  *===========================================================================*/
169 PUBLIC int magic_dsentries_analyze(int flags, const magic_sentry_analyze_cb_t cb,
170     void *cb_args, _magic_sel_stats_t *dsentries_stats)
171 {
172     int ret = 0;
173     struct _magic_dsentry *prev_dsentry, *dsentry;
174     struct _magic_sentry* sentry;
175 
176     /* If dead dsentries are enabled, garbage collect them to ensure consistency. */
177     if (magic_allow_dead_dsentries)
178         magic_free_dead_dsentries();
179 
180     /* Analyze all the dsentries. */
181     /*
182      * We need to hold the DSENTRY, DFUNCTION and DSODESC locks for the
183      * magic_range_lookup_by_addr() function.
184      */
185     MAGIC_MULTIPLE_LOCK(1, 1, 1, 0);
186     MAGIC_DSENTRY_ALIVE_BLOCK_ITER(_magic_first_dsentry, prev_dsentry, dsentry,
187         sentry,
188 
189         /*
190          * Check if we should analyze out-of-band dsentries.
191          */
192         if (!(flags & MAGIC_SEL_ANALYZE_OUT_OF_BAND) &&
193             MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
194             continue;
195         }
196 
197         /*
198          * Check if we should analyze shlib state dsentries.
199          */
200         if (!(flags & MAGIC_SEL_ANALYZE_LIB_SRC) &&
201             MAGIC_STATE_FLAG(sentry, MAGIC_STATE_LIB)) {
202             continue;
203         }
204 
205         ret = magic_sentry_analyze(sentry, flags, cb, cb_args, dsentries_stats);
206         if (ret < 0) {
207             break;
208         }
209         else {
210             flags |= ret;
211         }
212     );
213     MAGIC_MULTIPLE_UNLOCK(1, 1, 1, 0);
214 
215     return ret < 0 ? ret : flags;
216 }
217 
218 /*===========================================================================*
219  *                         magic_sentry_print_el_cb                          *
220  *===========================================================================*/
221 PUBLIC int magic_sentry_print_el_cb(_magic_selement_t* selement,
222     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
223     void* cb_args)
224 {
225     if(sel_analyzed->num == 1) {
226         MAGIC_SENTRY_PRINT(selement->sentry, MAGIC_EXPAND_TYPE_STR);
227         _magic_printf("\n");
228     }
229 
230     MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR);
231     _magic_printf("\n");
232     MAGIC_SEL_ANALYZED_PRINT(sel_analyzed, MAGIC_EXPAND_TYPE_STR);
233     _magic_printf("\n");
234     MAGIC_SEL_STATS_PRINT(sel_stats);
235     _magic_printf("\n\n");
236 
237     return MAGIC_SENTRY_ANALYZE_CONTINUE;
238 }
239 
240 /*===========================================================================*
241  *                      magic_sentry_print_ptr_el_cb                         *
242  *===========================================================================*/
243 PUBLIC int magic_sentry_print_ptr_el_cb(_magic_selement_t* selement,
244     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
245     void* cb_args)
246 {
247     int r;
248     void** args_array = (void**) cb_args;
249     int skip_null_ptrs = args_array ? *((int*)args_array[0]) : 0;
250     int max_target_recursions = args_array ? *((int*)args_array[1]) : 0;
251 
252     if(sel_analyzed->type_id != MAGIC_TYPE_POINTER) {
253         return MAGIC_SENTRY_ANALYZE_CONTINUE;
254     }
255     if(skip_null_ptrs && sel_analyzed->u.ptr.value == 0) {
256         return MAGIC_SENTRY_ANALYZE_CONTINUE;
257     }
258     magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats, cb_args);
259     if(max_target_recursions>0 && !(sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS)) {
260         struct _magic_sentry *sentry = &sel_analyzed->u.ptr.trg.dsentry.sentry;
261         if(MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed) && MAGIC_SENTRY_ID(sentry)!=MAGIC_SENTRY_ID(selement->sentry)) {
262             r = magic_sentry_print_ptr_selements(sentry, skip_null_ptrs,
263                 max_target_recursions-1);
264             if(r < 0) {
265                 _magic_printf("magic_sentry_print_ptr_el_cb: recursive step reported error %d\n", r);
266                 return r;
267             }
268         }
269     }
270 
271     return MAGIC_SENTRY_ANALYZE_CONTINUE;
272 }
273 
274 /*===========================================================================*
275  *                   magic_sentry_print_el_with_trg_reg_cb                   *
276  *===========================================================================*/
277 PUBLIC int magic_sentry_print_el_with_trg_reg_cb(_magic_selement_t* selement,
278     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
279     void* cb_args)
280 {
281     if(MAGIC_SEL_ANALYZED_TRG_FLAGS(sel_analyzed)) {
282         return magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats,
283             cb_args);
284     }
285 
286     return MAGIC_SENTRY_ANALYZE_CONTINUE;
287 }
288 
289 /*===========================================================================*
290  *                     magic_sentry_print_el_with_trg_cb                     *
291  *===========================================================================*/
292 PUBLIC int magic_sentry_print_el_with_trg_cb(_magic_selement_t* selement,
293     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
294     void* cb_args)
295 {
296     if(MAGIC_SEL_ANALYZED_TRG_FLAGS(sel_analyzed)
297         && MAGIC_SELEMENT_HAS_TRG(selement)) {
298         return magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats,
299             cb_args);
300     }
301 
302     return MAGIC_SENTRY_ANALYZE_CONTINUE;
303 }
304 
305 /*===========================================================================*
306  *                          magic_type_count_ptrs                            *
307  *===========================================================================*/
308 PUBLIC int magic_type_count_ptrs(const struct _magic_type* type, int* ptr_num)
309 {
310     int ret;
311     void* args_array[4] = { NULL, NULL, NULL };
312     args_array[3] = ptr_num;
313     *ptr_num = 0;
314     ret = magic_type_walk_root_all(type, magic_type_extract_ptr_cb, args_array);
315     assert(ret >= 0);
316     return 0;
317 }
318 
319 /*===========================================================================*
320  *                         magic_type_examine_ptr_cb                         *
321  *===========================================================================*/
322 PUBLIC int magic_type_examine_ptr_cb(const struct _magic_type* parent_type,
323     const unsigned parent_offset, int child_num,
324     const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
325 {
326     int ret;
327     void** args_array = (void**) cb_args;
328     if(type->type_id == MAGIC_TYPE_POINTER) {
329         const struct _magic_sentry *root_entry = (const struct _magic_sentry *) args_array[0];
330         int *ptrs_found = (int*) args_array[1];
331         char* root_address = root_entry->address;
332         void* ptr_address = root_address ? root_address+offset : NULL;
333         void* target_address = ptr_address ? *((void**)ptr_address) : NULL;
334         (*ptrs_found)++;
335         _magic_printf("Pointer found for root entry (name=%s, address=0x%08x) at offset %d, static target type is: ", root_entry->name, (unsigned) root_address, offset);
336         magic_type_str_print(type->contained_types[0]);
337         _magic_printf(" - dynamic target types are: ");
338         if(!target_address) {
339             _magic_printf("NULL");
340         }
341         else {
342             ret = magic_type_str_print_from_target(target_address);
343             if(ret < 0) {
344                 _magic_printf("ENTRY NOT FOUND");
345             }
346         }
347         _magic_printf("\n");
348     }
349     return MAGIC_TYPE_WALK_CONTINUE;
350 }
351 
352 /*===========================================================================*
353  *                         magic_type_extract_ptr_cb                         *
354  *===========================================================================*/
355 PUBLIC int magic_type_extract_ptr_cb(const struct _magic_type* parent_type,
356     const unsigned parent_offset, int child_num,
357     const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
358 {
359     void** args_array = (void**) cb_args;
360     static void* null_ptr=NULL;
361     if(type->type_id == MAGIC_TYPE_POINTER) {
362         const struct _magic_sentry *root_entry = (const struct _magic_sentry *) args_array[0];
363         void ***ptr_map = (void ***) args_array[1];
364         const struct _magic_type **ptr_type_map = (const struct _magic_type **) args_array[2];
365         int *ptr_num = (int*) args_array[3];
366         char* root_ptr;
367         void** ptr_ptr;
368         assert(ptr_num);
369         if(root_entry && ptr_map && ptr_type_map) {
370             root_ptr = root_entry->address;
371             ptr_ptr= root_ptr ? (void**)(root_ptr+offset) : &null_ptr;
372             ptr_map[*ptr_num] = ptr_ptr;
373             ptr_type_map[*ptr_num] = type;
374         }
375         (*ptr_num)++;
376     }
377     return MAGIC_TYPE_WALK_CONTINUE;
378 }
379 
380 /*===========================================================================*
381  *                           magic_type_analyzer_cb                          *
382  *===========================================================================*/
383 PUBLIC int magic_type_analyzer_cb(const struct _magic_type* parent_type,
384     const unsigned parent_offset, int child_num, const struct _magic_type* type,
385     const unsigned offset, int depth, void* cb_args)
386 {
387     int ret;
388     void **args_array = (void **) cb_args;
389     int *flags = (int *)args_array[0];
390     magic_sentry_analyze_cb_t sentry_analyze_cb =
391         *((magic_sentry_analyze_cb_t *) args_array[1]);
392     void *sentry_analyze_cb_args = (void *) args_array[2];
393     struct _magic_sentry* sentry = (struct _magic_sentry *) args_array[3];
394     _magic_sel_stats_t *sentry_stats = (_magic_sel_stats_t *) args_array[4];
395     int *selement_num = (int *) args_array[5];
396     int *sel_analyzed_num = (int *) args_array[6];
397     static int likely_pointer_orig_type_id;
398     static int likely_pointer_orig_contained_type_id;
399     _magic_selement_t selement;
400     _magic_sel_analyzed_t sel_analyzed;
401     _magic_sel_stats_t sel_stats;
402 
403     if (type->type_id == MAGIC_TYPE_UNION &&
404         ((*flags) & MAGIC_SEL_SKIP_UNIONS)) {
405         /* Skip unions when requested. */
406         return MAGIC_TYPE_WALK_SKIP_PATH;
407     }
408 
409     if ((type->type_id == MAGIC_TYPE_INTEGER ||
410             type->type_id == MAGIC_TYPE_ENUM) &&
411             ((*flags) & MAGIC_SEL_SKIP_INTEGERS)) {
412         /* Skip integers when requested. */
413         return MAGIC_TYPE_WALK_SKIP_PATH;
414     }
415 
416     if (((*flags) & MAGIC_SEL_ANALYZE_LIKELYPOINTERS) &&
417         (MAGIC_TYPE_IS_RAW_ARRAY(type) ||
418         (MAGIC_TYPE_IS_INT_ARRAY(type) &&
419             type->contained_types[0]->size != sizeof(void *) &&
420             type->size >= sizeof(void *)) ||
421         (type->type_id == MAGIC_TYPE_INTEGER && type->size > sizeof(void *)))) {
422         /* This can be either UNION, INTEGER or ARRAY (of VOID or INTEGER). */
423         likely_pointer_orig_type_id = type->type_id;
424         if (type->type_id == MAGIC_TYPE_ARRAY)
425             likely_pointer_orig_contained_type_id =
426                 type->contained_types[0]->type_id;
427         /* Try to find likely pointers in raw arrays. */
428         ret = magic_type_walk_as_ptrint_array(parent_type, parent_offset,
429             child_num, type, (char *)sentry->address + offset, offset,
430             0, ULONG_MAX, magic_type_analyzer_cb, cb_args);
431         likely_pointer_orig_type_id = likely_pointer_orig_contained_type_id = 0;
432         if (ret != MAGIC_EBADWALK) {
433             return ret == 0 ? MAGIC_TYPE_WALK_SKIP_PATH : ret;
434         }
435     }
436 
437     selement.sentry = sentry;
438     selement.parent_type = parent_type;
439     selement.parent_address = (char *)sentry->address + parent_offset;
440     selement.child_num = child_num;
441     selement.type = type;
442     selement.address = (char *)sentry->address + offset;
443     selement.depth = depth;
444     selement.num = ++(*selement_num);
445     selement.cb_args = cb_args;
446 
447     ret = magic_selement_analyze(&selement, *flags, &sel_analyzed, &sel_stats);
448     if (ret &&
449         (((ret & MAGIC_SEL_FOUND_DATA) &&
450           ((*flags) & MAGIC_SEL_ANALYZE_DATA)) ||
451          ((ret & MAGIC_SEL_FOUND_INVARIANTS) &&
452           ((*flags) & MAGIC_SEL_ANALYZE_INVARIANTS)) ||
453          ((ret & MAGIC_SEL_FOUND_VIOLATIONS) &&
454           ((*flags) & MAGIC_SEL_ANALYZE_VIOLATIONS)) ||
455          ((ret & MAGIC_SEL_FOUND_WALKABLE) &&
456           ((*flags) & MAGIC_SEL_ANALYZE_WALKABLE))
457         )) {
458         *flags |= ret;
459         sel_analyzed.num = ++(*sel_analyzed_num);
460         if (likely_pointer_orig_type_id) {
461             sel_analyzed.type_id = likely_pointer_orig_type_id;
462             sel_analyzed.contained_type_id =
463                 likely_pointer_orig_contained_type_id;
464         }
465         ret = sentry_analyze_cb(&selement, &sel_analyzed, &sel_stats,
466             sentry_analyze_cb_args);
467         if (sel_analyzed.flags & MAGIC_SEL_FOUND_INVARIANTS) {
468             _magic_sel_stats_t* sel_stats_ptr = &sel_stats;
469             if (sentry_stats) {
470                 MAGIC_SEL_STATS_INCR(sentry_stats, sel_stats_ptr);
471             }
472         }
473         if (ret != MAGIC_SENTRY_ANALYZE_CONTINUE) {
474             switch (ret) {
475                 case MAGIC_SENTRY_ANALYZE_SKIP_PATH:
476                     ret = MAGIC_TYPE_WALK_SKIP_PATH;
477                 break;
478                 case MAGIC_SENTRY_ANALYZE_STOP:
479                     ret = MAGIC_TYPE_WALK_STOP;
480                 break;
481                 default:
482                     assert(ret < 0 && "Invalid error code!");
483                 break;
484             }
485             return ret;
486         }
487     }
488 
489     return MAGIC_TYPE_WALK_CONTINUE;
490 }
491 
492 /*===========================================================================*
493  *                          magic_selement_analyze                           *
494  *===========================================================================*/
495 PUBLIC int magic_selement_analyze(_magic_selement_t *selement, int flags,
496     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
497 {
498     const struct _magic_type *type = selement->type;
499     short is_ptr_el = type->type_id == MAGIC_TYPE_POINTER;
500     short is_nonptr_el = type->num_child_types == 0 || (type->type_id == MAGIC_TYPE_INTEGER && type->num_child_types > 0);
501     short analyze_ptr_el, analyze_nonptr_el;
502 
503     if (!is_ptr_el && !is_nonptr_el) {
504         if (MAGIC_TYPE_IS_WALKABLE(type)) {
505             sel_analyzed->type_id = MAGIC_TYPE_OPAQUE;
506             return MAGIC_SEL_FOUND_WALKABLE;
507         }
508         /* Not an element to analyze. */
509         return 0;
510     }
511     assert(is_ptr_el ^ is_nonptr_el);
512 
513     analyze_ptr_el = is_ptr_el && (flags & MAGIC_SEL_ANALYZE_POINTERS);
514     analyze_nonptr_el = 0;
515     if (is_nonptr_el && ((flags & MAGIC_SEL_ANALYZE_DATA) || MAGIC_TYPE_HAS_VALUE_SET(type))) {
516         if (flags & MAGIC_SEL_ANALYZE_NONPOINTERS) {
517             analyze_nonptr_el = 1;
518         }
519         else if (flags & MAGIC_SEL_ANALYZE_LIKELYPOINTERS) {
520             short is_intvalue_el = type->type_id == MAGIC_TYPE_ENUM
521                 || type->type_id == MAGIC_TYPE_INTEGER;
522             if (is_intvalue_el && type->size == sizeof(void *)) {
523                 long value = magic_selement_to_int(selement);
524                 analyze_nonptr_el = MAGIC_INT_IS_LIKELY_PTR(value);
525             }
526         }
527     }
528 
529     if (analyze_nonptr_el && (flags & MAGIC_SEL_ANALYZE_NONPTRS_AS_PTRS) &&
530         type->size == sizeof(void *)) {
531         struct _magic_type tmp_type;
532         int ret;
533         tmp_type = *(selement->type);
534         tmp_type.type_id = MAGIC_TYPE_POINTER;
535         selement->type = &tmp_type;
536 
537         /* Analyze non-pointer element as a pointer. */
538         ret = magic_selement_analyze_ptr(selement, flags, sel_analyzed, sel_stats);
539 
540         selement->type = type;
541         /* Keep original type in sel_analyzed. */
542         sel_analyzed->type_id = type->type_id;
543 
544         return ret;
545     }
546 
547     assert(!analyze_ptr_el || !analyze_nonptr_el);
548 
549     if (analyze_ptr_el) {
550         /* Analyze pointer element. */
551         return magic_selement_analyze_ptr(selement, flags, sel_analyzed,
552             sel_stats);
553     }
554     if (analyze_nonptr_el) {
555         /* Analyze nonpointer element. */
556         return magic_selement_analyze_nonptr(selement, flags, sel_analyzed,
557             sel_stats);
558     }
559 
560     /* Nothing to analyze. */
561     return 0;
562 }
563 
564 /*===========================================================================*
565  *                   magic_selement_analyze_ptr_value_invs                   *
566  *===========================================================================*/
567 PUBLIC int magic_selement_analyze_ptr_value_invs(_magic_selement_t *selement,
568     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
569 {
570     const struct _magic_type* ptr_type = selement->type;
571     int i, ret = 0;
572     const struct _magic_type *first_trg_type;
573     void* value = sel_analyzed->u.ptr.value;
574 
575     first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed);
576     assert(sel_analyzed->u.ptr.num_trg_types > 0 && first_trg_type);
577     if(first_trg_type == MAGIC_TYPE_NULL_ENTRY) {
578         ret |= MAGIC_SEL_FOUND_INVARIANTS;
579         sel_stats->null_type_found++;
580     }
581     else if(MAGIC_TYPE_FLAG(ptr_type, MAGIC_TYPE_INT_CAST)) {
582         if(MAGIC_TYPE_HAS_VALUE_SET(ptr_type)) {
583             i=0;
584             while(MAGIC_TYPE_HAS_VALUE(ptr_type, i)) {
585                 int trg_value = MAGIC_TYPE_VALUE(ptr_type, i);
586                 if(trg_value == (int) value) {
587                     ret |= MAGIC_SEL_FOUND_INVARIANTS;
588                     MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_VALUE_FOUND);
589                     sel_stats->value_found++;
590                     break;
591                 }
592                 i++;
593             }
594             if(!(ret & MAGIC_SEL_FOUND_INVARIANTS) && MAGIC_TYPE_FLAG(ptr_type, MAGIC_TYPE_STRICT_VALUE_SET)) {
595                 ret |= MAGIC_SEL_FOUND_INVARIANTS;
596                 MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_BAD_VALUE);
597                 sel_stats->badvalue_found++;
598             }
599         }
600         else if(MAGIC_PTR_IS_LIKELY_INT(value)) {
601             ret |= MAGIC_SEL_FOUND_INVARIANTS;
602             MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_VALUE_FOUND);
603             sel_stats->value_found++;
604         }
605     }
606 
607     return ret;
608 }
609 
610 /*===========================================================================*
611  *                    magic_selement_analyze_ptr_trg_invs                    *
612  *===========================================================================*/
613 PUBLIC int magic_selement_analyze_ptr_trg_invs(_magic_selement_t *selement,
614     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
615 {
616     int ret = 0;
617     const struct _magic_type *first_trg_type;
618 
619     first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed);
620     assert(sel_analyzed->u.ptr.num_trg_types > 0 && first_trg_type);
621     sel_stats->trg_flags |= sel_analyzed->u.ptr.trg_flags;
622     if(first_trg_type == MAGIC_TYPE_ENTRY_NOT_FOUND) {
623         ret |= MAGIC_SEL_FOUND_INVARIANTS;
624         sel_stats->unknown_found++;
625     }
626     else if(first_trg_type == MAGIC_TYPE_BAD_ENTRY) {
627         ret |= MAGIC_SEL_FOUND_INVARIANTS;
628         sel_stats->badentry_found++;
629     }
630     else if(first_trg_type == MAGIC_TYPE_BAD_OFFSET) {
631         ret |= MAGIC_SEL_FOUND_INVARIANTS;
632         sel_stats->badoffset_found++;
633     }
634 
635     return ret;
636 }
637 
638 /*===========================================================================*
639  *                      magic_selement_analyze_ptr_target                    *
640  *===========================================================================*/
641 PUBLIC _magic_trg_stats_t magic_selement_analyze_ptr_target(const struct _magic_type *ptr_type,
642     const struct _magic_type *trg_type, int trg_flags)
643 {
644     const struct _magic_type* type = ptr_type->contained_types[0];
645 
646     /* Analyze void target types first. */
647     if(MAGIC_TYPE_IS_VOID(trg_type)) {
648         int ptr_can_point_to_text = magic_type_ptr_is_text(ptr_type);
649         int ptr_can_point_to_data = magic_type_ptr_is_data(ptr_type);
650         int is_trg_data = (MAGIC_STATE_FLAGS_REGION(trg_flags) & ~MAGIC_STATE_TEXT) != 0;
651         int is_trg_text = trg_flags & MAGIC_STATE_TEXT;
652         assert(ptr_can_point_to_text || ptr_can_point_to_data);
653         assert(is_trg_text || is_trg_data);
654         if((!ptr_can_point_to_text && is_trg_text)
655             || (!ptr_can_point_to_data && is_trg_data)) {
656             return _badentry_found;
657         }
658         else {
659             return _void_type_found;
660         }
661     }
662 
663     /* Analyze void types next. */
664     if(MAGIC_TYPE_IS_VOID(type)) {
665         /* Pretend the pointer has been found, void* can point to any valid target. */
666         return _ptr_type_found;
667     }
668 
669     /* See if the target type is compatible with the static type. */
670     if(magic_type_compatible(trg_type, type, 0)) {
671         return _ptr_type_found;
672     }
673 
674     /* See if the target type is compatible with some static cast type. */
675     if(MAGIC_TYPE_HAS_COMP_TYPES(ptr_type) && magic_type_comp_compatible(ptr_type, trg_type)) {
676         return _comp_trg_types_found;
677     }
678 
679     /* No chance. The pointer is pointing to some other invalid type. */
680     return _other_types_found;
681 }
682 
683 /*===========================================================================*
684  *                    magic_selement_analyze_ptr_type_invs                   *
685  *===========================================================================*/
686 PUBLIC int magic_selement_analyze_ptr_type_invs(_magic_selement_t *selement,
687     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
688 {
689     const struct _magic_type* ptr_type = selement->type;
690     unsigned int i;
691     int ret = 0;
692     int trg_flags;
693     const struct _magic_type *trg_type;
694     _magic_trg_stats_t trg_stats;
695 
696     assert(sel_analyzed->u.ptr.num_trg_types > 0);
697     if(MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(sel_analyzed)) {
698         /* No invariants if we only have a special target type. */
699         return ret;
700     }
701     trg_flags= sel_analyzed->u.ptr.trg_flags;
702     sel_stats->trg_flags |= trg_flags;
703     ret |= MAGIC_SEL_FOUND_INVARIANTS;
704 
705     /* Analyze targets. */
706     sel_analyzed->u.ptr.first_legal_trg_type = -1;
707     sel_analyzed->u.ptr.num_legal_trg_types = 0;
708     for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
709         trg_type = sel_analyzed->u.ptr.trg_selements[i].type;
710         trg_stats = magic_selement_analyze_ptr_target(ptr_type, trg_type, trg_flags);
711         sel_analyzed->u.ptr.trg_stats[i] = trg_stats;
712         if(!MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(trg_stats)) {
713             sel_analyzed->u.ptr.num_legal_trg_types++;
714             if(sel_analyzed->u.ptr.first_legal_trg_type == -1) {
715                 sel_analyzed->u.ptr.first_legal_trg_type = i;
716             }
717         }
718     }
719 
720     /* Set global stats. */
721     for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
722         trg_stats = sel_analyzed->u.ptr.trg_stats[i];
723         if(trg_stats == _badentry_found) {
724             sel_stats->badentry_found++;
725             return ret;
726         }
727         else if(trg_stats == _void_type_found) {
728             sel_stats->void_type_found++;
729             return ret;
730         }
731     }
732     for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
733         trg_stats = sel_analyzed->u.ptr.trg_stats[i];
734         if(trg_stats == _ptr_type_found) {
735             sel_stats->ptr_type_found++;
736             return ret;
737         }
738     }
739     for(i=0;i<sel_analyzed->u.ptr.num_trg_types;i++) {
740         trg_stats = sel_analyzed->u.ptr.trg_stats[i];
741         if(trg_stats == _comp_trg_types_found) {
742             sel_stats->comp_trg_types_found++;
743             return ret;
744         }
745     }
746     sel_stats->other_types_found++;
747     return ret;
748 }
749 
750 /*===========================================================================*
751  *                          magic_selement_recurse_ptr                       *
752  *===========================================================================*/
753 PUBLIC int magic_selement_recurse_ptr(_magic_selement_t *selement,
754     _magic_selement_t *new_selement, int max_steps)
755 {
756     _magic_sel_stats_t sel_stats;
757     _magic_sel_analyzed_t sel_analyzed;
758     int steps = 0;
759 
760     if(selement->type->type_id != MAGIC_TYPE_POINTER) {
761         return MAGIC_EINVAL;
762     }
763 
764     *new_selement = *selement;
765     while(1) {
766         magic_selement_analyze_ptr(new_selement, MAGIC_SEL_ANALYZE_ALL,
767             &sel_analyzed, &sel_stats);
768         if(MAGIC_SEL_ANALYZED_PTR_HAS_SPECIAL_TRG_TYPE(&sel_analyzed)) {
769             return steps;
770         }
771         *new_selement = sel_analyzed.u.ptr.trg_selements[0];
772         steps++;
773         if(new_selement->type->type_id != MAGIC_TYPE_POINTER || (max_steps > 0 && steps >= max_steps)) {
774             break;
775         }
776     }
777 
778     return steps;
779 }
780 
781 /*===========================================================================*
782  *                         magic_sentry_analyze_ptr_trg_cb                   *
783  *===========================================================================*/
784 PRIVATE int magic_sentry_analyze_ptr_trg_cb(const struct _magic_type *trg_parent_type,
785     const unsigned parent_offset, int child_num,
786     const struct _magic_type *trg_type, const unsigned offset, int depth, void *cb_args)
787 {
788     void **args_array = (void **) cb_args;
789     _magic_sel_analyzed_t *sel_analyzed = (_magic_sel_analyzed_t *) args_array[3];
790     _magic_selement_t *sel;
791     char *trg_address;
792     int analysis_flags = (*(int *)(args_array[4]));
793 
794     if (trg_type->type_id == MAGIC_TYPE_ARRAY) {
795         /* Skip arrays. */
796         return MAGIC_TYPE_WALK_CONTINUE;
797     }
798 
799     if (!sel_analyzed->u.ptr.trg_flags) {
800         /* Set trg flags and offset only the first time. */
801         struct _magic_dsentry **trg_dsentry = (struct _magic_dsentry **) args_array[0];
802         struct _magic_dfunction **trg_dfunction = (struct _magic_dfunction **) args_array[1];
803         int flags;
804         if (*trg_dsentry) {
805             assert(!(*trg_dfunction));
806             flags = MAGIC_DSENTRY_TO_SENTRY(*trg_dsentry)->flags;
807             if (flags & MAGIC_STATE_DYNAMIC) {
808                 assert(!(flags & MAGIC_STATE_DATA) || (flags & MAGIC_STATE_LIB));
809                 assert(MAGIC_STATE_REGION(MAGIC_DSENTRY_TO_SENTRY(*trg_dsentry)));
810             }
811             else {
812                 assert((flags & MAGIC_STATE_DATA) && !(flags & MAGIC_STATE_LIB));
813             }
814         }
815         else {
816             assert(*trg_dfunction);
817             flags = MAGIC_DFUNCTION_TO_FUNCTION(*trg_dfunction)->flags;
818             assert(flags & MAGIC_STATE_TEXT);
819         }
820         sel_analyzed->u.ptr.trg_flags = flags;
821         if (analysis_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)
822             sel_analyzed->u.ptr.trg_flags |= MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS;
823         sel_analyzed->u.ptr.trg_offset = offset;
824     }
825 
826     /* Add target types. */
827     trg_address = MAGIC_SEL_ANALYZED_PTR_TRG_ADDRESS(sel_analyzed);
828     assert(trg_address);
829     sel = &sel_analyzed->u.ptr.trg_selements[sel_analyzed->u.ptr.num_trg_types];
830     if (!(analysis_flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)) {
831         sel->sentry = MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed) ? MAGIC_DSENTRY_TO_SENTRY(&sel_analyzed->u.ptr.trg.dsentry) : NULL;
832     } else {
833         sel->sentry = MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed) ? MAGIC_DSENTRY_TO_SENTRY(sel_analyzed->u.ptr.trg_p.dsentry) : NULL;
834     }
835     sel->parent_type = trg_parent_type;
836     sel->parent_address = trg_address + parent_offset;
837     sel->child_num = child_num;
838     sel->type = trg_type;
839     sel->address = trg_address + offset;
840     sel_analyzed->u.ptr.num_trg_types++;
841 
842     return MAGIC_TYPE_WALK_CONTINUE;
843 }
844 
845 /*===========================================================================*
846  *                        magic_selement_analyze_ptr                         *
847  *===========================================================================*/
848 PUBLIC int magic_selement_analyze_ptr(_magic_selement_t *selement, int flags,
849     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
850 {
851     const struct _magic_type *ptr_type = selement->type;
852     short is_ptr_el = ptr_type->type_id == MAGIC_TYPE_POINTER;
853     int r, ret = 0;
854 
855     sel_analyzed->type_id = 0;
856     if (!is_ptr_el) {
857         /* Nothing to do. */
858         return 0;
859     }
860     memset(&sel_analyzed->u.ptr, 0, sizeof(sel_analyzed->u.ptr));
861     memset(sel_stats, 0, sizeof(_magic_sel_stats_t));
862 
863     if (flags & (MAGIC_SEL_ANALYZE_DATA | MAGIC_SEL_ANALYZE_INVARIANTS | MAGIC_SEL_ANALYZE_VIOLATIONS)) {
864         /* Analyze data first. */
865         void *value = magic_selement_to_ptr(selement);
866         sel_analyzed->type_id = MAGIC_TYPE_POINTER;
867         sel_analyzed->u.ptr.value = value;
868         ret |= MAGIC_SEL_FOUND_DATA;
869         if (value == NULL) {
870             /* Null pointer. */
871             MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_NULL_ENTRY);
872         }
873         else {
874             /* Check target. */
875             struct _magic_dsentry *trg_dsentry_ptr;
876             struct _magic_dfunction *trg_dfunction_ptr;
877             void *args_array[5];
878             if (!(flags & MAGIC_SEL_ANALYZE_RETURN_TRG_PTRS)) {
879                 trg_dsentry_ptr = &sel_analyzed->u.ptr.trg.dsentry;
880                 trg_dfunction_ptr = &sel_analyzed->u.ptr.trg.dfunction;
881                 args_array[0] = &trg_dsentry_ptr;
882                 args_array[1] = &trg_dfunction_ptr;
883             } else {
884                 args_array[0] = &sel_analyzed->u.ptr.trg_p.dsentry;
885                 args_array[1] = &sel_analyzed->u.ptr.trg_p.dfunction;
886             }
887             args_array[2] = selement;
888             args_array[3] = sel_analyzed;
889             args_array[4] = &flags;
890             r = magic_type_target_walk(value, args_array[0], args_array[1],
891                 magic_sentry_analyze_ptr_trg_cb, args_array);
892             if (r == MAGIC_ENOENT) {
893                 MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_ENTRY_NOT_FOUND);
894                 sel_analyzed->u.ptr.trg_flags = magic_range_lookup_by_addr(value, NULL);
895             }
896             else if (r == MAGIC_EBADENT) {
897                 MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_BAD_ENTRY);
898                 sel_analyzed->u.ptr.trg_flags = magic_range_lookup_by_addr(value, NULL);
899             }
900             else if (sel_analyzed->u.ptr.num_trg_types == 0) {
901                 MAGIC_SEL_ANALYZED_PTR_SET_SPECIAL_TRG_TYPE(sel_analyzed, MAGIC_TYPE_BAD_OFFSET);
902                 sel_analyzed->u.ptr.trg_flags = magic_range_lookup_by_addr(value, NULL);
903             }
904         }
905 
906         if (flags & (MAGIC_SEL_ANALYZE_INVARIANTS | MAGIC_SEL_ANALYZE_VIOLATIONS)) {
907             /* Check value-based invariants. */
908             ret |= magic_selement_analyze_ptr_value_invs(selement,
909                 sel_analyzed, sel_stats);
910 
911             /* Check target-based invariants. */
912             if (!(ret & MAGIC_SEL_FOUND_INVARIANTS)) {
913                 ret |= magic_selement_analyze_ptr_trg_invs(selement,
914                     sel_analyzed, sel_stats);
915             }
916 
917             /* Check type-based invariants. */
918             if (!(ret & MAGIC_SEL_FOUND_INVARIANTS)) {
919                 ret |= magic_selement_analyze_ptr_type_invs(selement,
920                     sel_analyzed, sel_stats);
921             }
922 
923             assert(ret & MAGIC_SEL_FOUND_INVARIANTS);
924             sel_stats->ptr_found++;
925             if (MAGIC_SEL_STATS_HAS_VIOLATIONS(sel_stats)) {
926                 ret |= MAGIC_SEL_FOUND_VIOLATIONS;
927             }
928         }
929     }
930 
931     sel_analyzed->flags = ret;
932     return ret;
933 }
934 
935 /*===========================================================================*
936  *                  magic_selement_analyze_nonptr_value_invs                 *
937  *===========================================================================*/
938 PRIVATE int magic_selement_analyze_nonptr_value_invs(_magic_selement_t *selement,
939     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
940 {
941     const struct _magic_type* type = selement->type;
942     int i, ret = 0;
943     int value = sel_analyzed->u.nonptr.value;
944 
945     if(MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_EXTERNAL))
946         return 0;
947 
948     if(MAGIC_TYPE_HAS_VALUE_SET(type)) {
949         i=0;
950         ret |= MAGIC_SEL_FOUND_INVARIANTS;
951         while(MAGIC_TYPE_HAS_VALUE(type, i)) {
952             int trg_value = MAGIC_TYPE_VALUE(type, i);
953             if(trg_value == value) {
954                 sel_stats->value_found++;
955                 break;
956             }
957             i++;
958         }
959         if(!MAGIC_TYPE_HAS_VALUE(type, i)) {
960             sel_stats->badvalue_found++;
961         }
962     }
963 
964     return ret;
965 }
966 
967 /*===========================================================================*
968  *                       magic_selement_analyze_nonptr                       *
969  *===========================================================================*/
970 PUBLIC int magic_selement_analyze_nonptr(_magic_selement_t *selement, int flags,
971     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
972 {
973     int ret = 0;
974 
975     sel_analyzed->type_id = 0;
976     memset(&sel_analyzed->u.nonptr, 0, sizeof(sel_analyzed->u.nonptr));
977     memset(sel_stats, 0, sizeof(_magic_sel_stats_t));
978 
979     if(flags & (MAGIC_SEL_ANALYZE_DATA|MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS)) {
980         /* Analyze data first. */
981         switch(selement->type->type_id) {
982             case MAGIC_TYPE_VOID:
983                 sel_analyzed->type_id = MAGIC_TYPE_VOID;
984                 sel_analyzed->u.nonptr.value = (long) *((char*)selement->address);
985                 ret |= MAGIC_SEL_FOUND_DATA;
986             break;
987 
988             case MAGIC_TYPE_FLOAT:
989                 sel_analyzed->type_id = MAGIC_TYPE_FLOAT;
990                 sel_analyzed->u.nonptr.value = (long) magic_selement_to_float(selement);
991                 ret |= MAGIC_SEL_FOUND_DATA;
992             break;
993 
994             case MAGIC_TYPE_INTEGER:
995             case MAGIC_TYPE_ENUM:
996                 sel_analyzed->type_id = selement->type->type_id;
997                 sel_analyzed->u.nonptr.value = magic_selement_to_int(selement);
998                 ret |= MAGIC_SEL_FOUND_DATA;
999                 if((flags & MAGIC_SEL_ANALYZE_LIKELYPOINTERS) && selement->type->size == sizeof(void*)) {
1000                     sel_analyzed->u.nonptr.trg_flags = magic_range_lookup_by_addr((void*) sel_analyzed->u.nonptr.value, NULL);
1001                 }
1002                 if(flags & (MAGIC_SEL_ANALYZE_INVARIANTS|MAGIC_SEL_ANALYZE_VIOLATIONS)) {
1003                     /* Check value-based invariants. */
1004                     ret |= magic_selement_analyze_nonptr_value_invs(selement,
1005                         sel_analyzed, sel_stats);
1006 
1007                     if(ret & MAGIC_SEL_FOUND_INVARIANTS) {
1008                         sel_stats->nonptr_found++;
1009                         if(MAGIC_SEL_STATS_HAS_VIOLATIONS(sel_stats)) {
1010                             ret |= MAGIC_SEL_FOUND_VIOLATIONS;
1011                         }
1012                     }
1013                     else {
1014                         sel_stats->nonptr_unconstrained_found++;
1015                     }
1016                 }
1017             break;
1018         }
1019     }
1020 
1021     sel_analyzed->flags = ret;
1022     return ret;
1023 }
1024 
1025 /*===========================================================================*
1026  *                 magic_sel_analyzed_trg_selements_print                    *
1027  *===========================================================================*/
1028 PUBLIC void magic_sel_analyzed_trg_selements_print(_magic_sel_analyzed_t *sel_analyzed,
1029     int flags)
1030 {
1031     int num;
1032     int i=0;
1033     const _magic_selement_t* trg_selement;
1034     _magic_trg_stats_t trg_stats;
1035 
1036     num = sel_analyzed->u.ptr.num_trg_types;
1037     if(num == 0) {
1038         return;
1039     }
1040     _magic_printf("#%d|%d", num, sel_analyzed->u.ptr.num_legal_trg_types);
1041 
1042     for(;i<num;i++) {
1043         trg_selement = &sel_analyzed->u.ptr.trg_selements[i];
1044         trg_stats = sel_analyzed->u.ptr.trg_stats[i];
1045         _magic_printf("%s%d|%c=", (i==0 ? ": " : ", "), i+1, MAGIC_SEL_ANALYZED_TRG_STATS_C(trg_stats));
1046         MAGIC_SELEMENT_PRINT(trg_selement, flags|MAGIC_SKIP_COMP_TYPES);
1047     }
1048 }
1049 
1050 /*===========================================================================*
1051  *                        magic_selement_type_cast                           *
1052  *===========================================================================*/
1053 PUBLIC _magic_selement_t* magic_selement_type_cast(
1054     _magic_selement_t *selement, int flags, const struct _magic_type* type,
1055     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats)
1056 {
1057     _magic_sel_stats_t my_sel_stats;
1058 
1059     selement->type = type;
1060     if(sel_analyzed) {
1061         magic_selement_analyze(selement, flags,
1062             sel_analyzed, sel_stats ? sel_stats : &my_sel_stats);
1063     }
1064     return selement;
1065 }
1066 
1067