xref: /minix/minix/lib/libmagicrt/magic_st.c (revision e1cdaee1)
1 #include <magic.h>
2 #include <magic_mem.h>
3 #include <magic_analysis.h>
4 #include <magic_asr.h>
5 #include <stdarg.h>
6 #include <st/state_transfer.h>
7 #include <st/metadata_transfer.h>
8 #include <st/typedefs.h>
9 #include <st/private.h>
10 
11 #define printf _magic_printf
12 
13 #ifdef __MINIX
14 EXTERN endpoint_t sef_self_endpoint;
15 #else
16 #define DO_SKIP_ENVIRON_HACK 1
17 #define TODO_DSENTRY_PARENT_NAME_BUG 1
18 #define DO_SKIP_UNPAIRED_PTR_TARGETS 1
19 #endif
20 
21 #define DO_SKIP_INVARIANTS_VIOLATIONS 0
22 
23 PRIVATE st_alloc_pages *st_alloc_pages_current = NULL;
24 PRIVATE size_t st_alloc_buff_available = 0;
25 PRIVATE char *st_alloc_buff_pt = NULL;
26 PRIVATE char *st_pre_allocated_page_pt = NULL;
27 PRIVATE struct _magic_dsentry *st_dsentry_buff = NULL;
28 PRIVATE void *st_data_buff = NULL;
29 PRIVATE unsigned st_num_type_transformations = 0;
30 
31 /* Magic variables and counterparts. */
32 struct _magic_vars_t st_remote_magic_vars, st_cached_magic_vars;
33 struct _magic_vars_t *st_local_magic_vars_ptr = &_magic_vars_buff;
34 st_counterparts_t st_counterparts;
35 
36 /* Private variables. */
37 PRIVATE int st_init_done = FALSE;
38 PRIVATE int st_policies = ST_POLICIES_DEFAULT;
39 PRIVATE double st_unpaired_types_ratio = ST_UNPAIRED_TYPES_RATIO_DEFAULT;
40 PRIVATE double st_unpaired_struct_types_ratio = ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT;
41 
42 /* Forward declarations. */
43 PRIVATE INLINE int default_transfer_selement_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info);
44 
45 /* State transfer callbacks. */
46 
47 PRIVATE struct st_cbs_t st_cbs = {
48     ST_CB_PAGES_ALLOCATE_DEFAULT,
49     ST_CB_PAGES_FREE_DEFAULT,
50     ST_CB_STATE_CLEANUP_DEFAULT,
51     ST_CB_STATE_CHECKING_DEFAULT,
52     ST_CB_SELEMENT_MAP_DEFAULT,
53     ST_CB_SELEMENT_TRANSFER_EMPTY
54 };
55 
56 /* OS dependent callbacks. */
57 PRIVATE struct st_cbs_os_t st_cbs_os = {
58     ST_CB_OS_PANIC_EMPTY,
59     ST_CB_OS_OLD_STATE_TABLE_LOOKUP_EMPTY,
60     ST_CB_OS_COPY_STATE_REGION_EMPTY,
61     ST_CB_OS_ALLOC_CONTIG_EMPTY,
62     ST_CB_OS_FREE_CONTIG_EMPTY,
63     ST_CB_OS_DEBUG_HEADER_EMPTY
64 };
65 
66 /* State transfer prototypes for st_receive(). */
67 PUBLIC void do_st_before_receive(void);
68 
69 /* Callback setters */
70 
71 PUBLIC void st_setcb_pages_allocate (st_cb_pages_allocate_t cb)
72 {
73   assert(cb != NULL);
74   st_cbs.st_cb_pages_allocate = cb;
75 }
76 
77 PUBLIC void st_setcb_pages_free (st_cb_pages_free_t cb)
78 {
79   assert(cb != NULL);
80   st_cbs.st_cb_pages_free = cb;
81 }
82 
83 PUBLIC void st_setcb_state_cleanup (st_cb_state_cleanup_t cb)
84 {
85   assert(cb != NULL);
86   st_cbs.st_cb_state_cleanup = cb;
87   magic_setcb_sentries_analyze_pre(cb);
88 }
89 
90 PUBLIC void st_setcb_state_checking (st_cb_state_checking_t cb)
91 {
92   assert(cb != NULL);
93   st_cbs.st_cb_state_checking = cb;
94 }
95 
96 PUBLIC void st_setcb_selement_map(st_cb_selement_map_t cb)
97 {
98   assert(cb != NULL);
99   st_cbs.st_cb_selement_map = cb;
100 }
101 
102 PUBLIC void st_setcb_selement_transfer(st_cb_selement_transfer_t cb, int flags)
103 {
104     int i, j;
105     for (i = 0 ; i < NUM_CB_ARRAYS ; i++) {
106         if (i & flags) {
107             int is_registered = FALSE;
108             for (j = 0; j < MAX_NUM_CBS ; j++) {
109                 if (st_cbs.st_cb_selement_transfer[i][j] == NULL) {
110                     st_cbs.st_cb_selement_transfer[i][j] = cb;
111                     is_registered = TRUE;
112                     break;
113                 }
114             }
115             assert(is_registered && "Number of registered callbacks exceeds MAX_NUM_CBS");
116         }
117     }
118 }
119 
120 /* OS Callback setters. */
121 
122 PUBLIC void st_setcb_os_panic(st_cb_os_panic_t cb)
123 {
124     assert(cb != NULL && "No callback defined for panic().");
125     st_cbs_os.panic = cb;
126 }
127 
128 PUBLIC void st_setcb_os_old_state_table_lookup(st_cb_os_old_state_table_lookup_t cb)
129 {
130     assert(cb != NULL && "No callback defined for old_state_table_lookup().");
131     st_cbs_os.old_state_table_lookup = cb;
132 }
133 
134 PUBLIC void st_setcb_os_copy_state_region(st_cb_os_copy_state_region_t cb)
135 {
136     assert(cb != NULL && "No callback defined for copy_state_region().");
137     st_cbs_os.copy_state_region = cb;
138 }
139 
140 PUBLIC void st_setcb_os_alloc_contig(st_cb_os_alloc_contig_t cb)
141 {
142     assert(cb != NULL && "No callback defined for alloc_contig().");
143     st_cbs_os.alloc_contig = cb;
144 }
145 
146 PUBLIC void st_setcb_os_free_contig(st_cb_os_free_contig_t cb)
147 {
148     assert(cb != NULL && "No callback defined for free_contig().");
149     st_cbs_os.free_contig = cb;
150 }
151 
152 PUBLIC void st_setcb_os_debug_header(st_cb_os_debug_header_t cb)
153 {
154     assert(cb != NULL && "No callback defined for debug_header().");
155     st_cbs_os.debug_header = cb;
156 }
157 
158 
159 PUBLIC void st_setcb_os_all(struct st_cbs_os_t *cbs)
160 {
161     st_setcb_os_panic(cbs->panic);
162     st_setcb_os_old_state_table_lookup(cbs->old_state_table_lookup);
163     st_setcb_os_copy_state_region(cbs->copy_state_region);
164     st_setcb_os_alloc_contig(cbs->alloc_contig);
165     st_setcb_os_free_contig(cbs->free_contig);
166     st_setcb_os_debug_header(cbs->debug_header);
167 }
168 
169 /* Status variables to be transfered at state transfer time. */
170 PUBLIC int __st_before_receive_enabled = 0;
171 PRIVATE int __st_before_receive_sc_max_cycles;
172 PRIVATE int __st_before_receive_sc_max_violations;
173 
174 /* Typedef registration and lookup */
175 
176 int st_strcmp_wildcard(const char *with_wildcard, const char *without_wildcard)
177 {
178     /* Note: this implementation only supports basic regexes with a '*'
179      * at the beginning or the end of the string.
180      */
181     const char *star = strchr(with_wildcard, '*');
182     if (star) {
183         if (star == with_wildcard) {
184             size_t len = strlen(with_wildcard+1);
185             size_t len_without_wildcard = strlen(without_wildcard);
186             const char *match_without_wildcard = without_wildcard+
187                 len_without_wildcard-len;
188             if (match_without_wildcard < without_wildcard) {
189                 return -1;
190             }
191             return strncmp(with_wildcard+1, match_without_wildcard, len);
192         }
193         return strncmp(with_wildcard, without_wildcard, star - with_wildcard);
194     }
195     return strcmp(with_wildcard, without_wildcard);
196 }
197 
198 const char *st_typename_noxfers[] =   { ST_TYPENAME_NO_TRANSFER_NAMES, NULL         };
199 const char *st_typename_ixfers[] =    { ST_TYPENAME_IDENTITY_TRANSFER_NAMES, NULL   };
200 const char *st_typename_cixfers[] =   { ST_TYPENAME_CIDENTITY_TRANSFER_NAMES, NULL  };
201 const char *st_typename_pxfers[] =    { ST_TYPENAME_PTR_TRANSFER_NAMES, NULL        };
202 const char *st_typename_sxfers[] =    { ST_TYPENAME_STRUCT_TRANSFER_NAMES, NULL     };
203 const char *st_sentryname_ixfers[] =  { ST_SENTRYNAME_IDENTITY_TRANSFER_NAMES, NULL };
204 const char *st_sentryname_cixfers[] = { ST_SENTRYNAME_CIDENTITY_TRANSFER_NAMES, NULL};
205 const char *st_sentryname_pxfers[] =  { ST_SENTRYNAME_PTR_TRANSFER_NAMES, NULL      };
206 
207 /* Exclude stack references in addition to the default sentry names from state transfer. */
208 const char *st_sentryname_noxfers[] = {
209     ST_SENTRYNAME_NO_TRANSFER_NAMES,
210 #define __X(R) #R   /* Stringify the symbol names. */
211     ST_STACK_REFS_INT_LIST,
212 #if ST_STACK_REFS_CUSTOM_NUM > 0
213     ST_STACK_REFS_CUSTOM_LIST,
214 #endif
215 #undef __X
216     NULL };
217 const char *st_sentryname_noxfers_mem[] = { ST_SENTRYNAME_NO_TRANSFER_MEM_NAMES, NULL };
218 
219 /* Exclude the data segments of certain libs from state transfer. */
220 const char *st_dsentry_lib_noxfer[] = {
221 #ifdef ST_DSENTRYLIB_NO_TRANSFER_NAMES
222     ST_DSENTRYLIB_NO_TRANSFER_NAMES,
223 #endif
224     NULL };
225 
226 const char *st_typename_key_registrations[MAX_NUM_TYPENAMES];
227 
228 static int is_typename(const char *search_key, struct _magic_type *type)
229 {
230     unsigned int i;
231     /* We can't use a cached lookup result */
232     if (!st_strcmp_wildcard(search_key, type->name)) {
233         /* The name matches */
234         return TRUE;
235     }
236     for (i = 0 ; i < type->num_names ; i++) {
237         if(!st_strcmp_wildcard(search_key, type->names[i])) {
238             /* One of the typename names matches */
239             return TRUE;
240         }
241     }
242     /* No match is found */
243     return FALSE;
244 }
245 
246 PUBLIC void st_register_typename_key(const char *key)
247 {
248     int i, is_registered = FALSE;
249     for(i = 0 ; i < MAX_NUM_TYPENAMES ; i++) {
250         if (st_typename_key_registrations[i] == NULL) {
251             st_typename_key_registrations[i] = key;
252             is_registered = TRUE;
253             break;
254         }
255     }
256     assert(is_registered && "Error, number of typename registrations > MAX_NUM_TYPENAMES.\n");
257 }
258 
259 PUBLIC void st_register_typename_keys(const char **keys)
260 {
261     int i = 0;
262     while (keys[i] != NULL) {
263         st_register_typename_key(keys[i]);
264         i++;
265     }
266 }
267 
268 PRIVATE void set_typename_key(struct _magic_type *type)
269 {
270     const char **registration = st_typename_key_registrations;
271 
272     while (*registration != NULL) {
273         if (is_typename(*registration, type)) {
274             type->ext = *registration;
275             break;
276         }
277         registration++;
278     }
279 }
280 
281 PRIVATE void register_typenames(void)
282 {
283 
284     int i;
285 
286     /* Register typenames */
287     st_register_typename_keys(st_typename_noxfers);
288     st_register_typename_keys(st_typename_ixfers);
289     st_register_typename_keys(st_typename_cixfers);
290     st_register_typename_keys(st_typename_pxfers);
291     st_register_typename_keys(st_typename_sxfers);
292 
293     for(i = 0 ; i < _magic_types_num ; i++) {
294         set_typename_key(&_magic_types[i]);
295     }
296 
297 }
298 
299 PRIVATE INLINE void register_typenames_and_callbacks(void)
300 {
301 
302     static int st_is_registered = FALSE;
303     if(st_is_registered) {
304         return;
305     }
306 
307     register_typenames();
308 
309     st_setcb_selement_transfer(st_cb_transfer_sentry_default, ST_CB_TYPE_SENTRY);
310     st_setcb_selement_transfer(st_cb_transfer_typename_default, ST_CB_TYPE_TYPENAME);
311 
312     st_is_registered = TRUE;
313 
314 }
315 
316 PRIVATE int st_type_name_match_any(const char **registered_type_name_keys,
317     const char *key)
318 {
319     int i = 0;
320     while (registered_type_name_keys[i] != NULL) {
321         if (ST_TYPE_NAME_MATCH(registered_type_name_keys[i], key)) {
322             return TRUE;
323         }
324         i++;
325     }
326     return FALSE;
327 }
328 
329 PRIVATE int st_sentry_name_match_any(const char **sentry_wildcard_names,
330     const char *name)
331 {
332     int i = 0;
333     while (sentry_wildcard_names[i] != NULL) {
334         if (ST_SENTRY_NAME_MATCH(sentry_wildcard_names[i], name)) {
335             return TRUE;
336         }
337         i++;
338     }
339     return FALSE;
340 }
341 
342 PRIVATE int st_dsentry_parent_name_match_any(const char **wildcard_names,
343     const char *name)
344 {
345     int i = 0;
346     while (wildcard_names[i] != NULL) {
347         if (ST_DSENTRY_PARENT_NAME_MATCH(wildcard_names[i], name)) {
348             return TRUE;
349         }
350         i++;
351     }
352     return FALSE;
353 }
354 
355 /* Utilities. */
356 PUBLIC void st_cb_print(int level, const char *msg, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
357 {
358     if (ST_CB_PRINT_LEVEL(level)) {
359         _magic_printf("[%s] %s. Current state element:\n",
360             ST_CB_LEVEL_TO_STR(level), msg);
361         MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR);
362         _magic_printf("\n");
363         MAGIC_SEL_ANALYZED_PRINT(sel_analyzed, MAGIC_EXPAND_TYPE_STR);
364         _magic_printf("\n");
365         MAGIC_SEL_STATS_PRINT(sel_stats);
366         _magic_printf("\n\n");
367     }
368 }
369 
370 PUBLIC void st_cb_selement_type_cast(const struct _magic_type* new_selement_type, const struct _magic_type* new_local_selement_type, _magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
371 {
372     magic_selement_type_cast(selement, ST_SEL_ANALYZE_FLAGS,
373             new_selement_type, sel_analyzed, sel_stats);
374     if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
375         cb_info->local_selement->type = new_local_selement_type;
376     }
377 }
378 
379 /* Stack management. */
380 
381 PUBLIC void st_stack_refs_save_restore(char* stack_buff, int is_save)
382 {
383     struct _magic_dsentry *prev_dsentry, *dsentry;
384     struct _magic_sentry* sentry;
385     struct st_stack_refs_buff *buff_ptr;
386     int i;
387 
388 #define __X(P) P
389     extern int ST_STACK_REFS_INT_LIST;
390 #undef __X
391 #define __X(P) ((int *)&(P))
392     int* int_ptrs[] = { ST_STACK_REFS_INT_LIST, ST_STACK_REFS_CUSTOM_LIST };
393 #undef __X
394 
395     assert((ST_STACK_REFS_NUM) == sizeof(int_ptrs)/sizeof(int_ptrs[0]));
396     assert(sizeof(int) == sizeof(void*));
397     buff_ptr = (struct st_stack_refs_buff*) stack_buff;
398 
399     /* Save. */
400     if (is_save) {
401         buff_ptr->first_stack_dsentry = _magic_first_stack_dsentry;
402         buff_ptr->last_stack_dsentry = _magic_last_stack_dsentry;
403         if (_magic_first_stack_dsentry) {
404             buff_ptr->first_stack_obdsentry_buff = *MAGIC_OBDSENTRY_FROM_DSENTRY(_magic_first_stack_dsentry);
405         }
406         memcpy(buff_ptr->stack_range, magic_stack_range, 2*sizeof(void*));
407         for (i = 0 ; i < ST_STACK_REFS_NUM ; i++) {
408             memcpy(&buff_ptr->stack_int_refs[i], int_ptrs[i], sizeof(int));
409         }
410         return;
411     }
412 
413     /* Restore. */
414     if (_magic_first_dsentry == _magic_last_stack_dsentry) {
415         _magic_first_dsentry = buff_ptr->last_stack_dsentry;
416     }
417     else {
418         MAGIC_DSENTRY_ITER(_magic_first_dsentry, prev_dsentry, dsentry, sentry,
419             if (MAGIC_DSENTRY_HAS_NEXT(dsentry)
420                 && MAGIC_DSENTRY_NEXT(dsentry) == _magic_last_stack_dsentry) {
421                 MAGIC_DSENTRY_NEXT(dsentry) = buff_ptr->last_stack_dsentry;
422                 break;
423             }
424         );
425     }
426 
427     _magic_first_stack_dsentry = buff_ptr->first_stack_dsentry;
428     _magic_last_stack_dsentry = buff_ptr->last_stack_dsentry;
429     if (_magic_first_stack_dsentry) {
430         *MAGIC_OBDSENTRY_FROM_DSENTRY(_magic_first_stack_dsentry) = buff_ptr->first_stack_obdsentry_buff;
431     }
432     memcpy(magic_stack_range, buff_ptr->stack_range, 2*sizeof(void*));
433     for (i = 0 ; i < ST_STACK_REFS_NUM ; i++) {
434         memcpy(int_ptrs[i], &buff_ptr->stack_int_refs[i], sizeof(int));
435     }
436 }
437 
438 /* Metadata management. */
439 PUBLIC int st_add_special_mmapped_region(void *address, size_t size,
440     const char* name)
441 {
442     struct _magic_obdsentry* obdsentry;
443     char addr_name[24];
444 
445     if (!_magic_enabled) return OK;
446 
447     if (!name) {
448         snprintf(addr_name, sizeof(addr_name), "%%MMAP_0x%08x",
449           (unsigned int) address);
450         name = addr_name;
451     }
452     obdsentry = magic_create_obdsentry(address, MAGIC_VOID_TYPE,
453         size, MAGIC_STATE_MAP, name, NULL);
454     return obdsentry ? OK : EINVAL;
455 }
456 
457 PUBLIC int st_del_special_mmapped_region_by_addr(void *address)
458 {
459     int ret;
460 
461     if (!_magic_enabled) return OK;
462 
463     ret = magic_destroy_obdsentry_by_addr(address);
464     if (ret < 0) {
465         return EINVAL;
466     }
467     return OK;
468 }
469 
470 /* Selement transfer callbacks. */
471 
472 PRIVATE INLINE int transfer_walkable_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
473 {
474     /* Do nothing for complex type. process only its members, not the complex type itself */
475     return MAGIC_SENTRY_ANALYZE_CONTINUE;
476 }
477 
478 PRIVATE INLINE int transfer_try_raw_copy_sel_cb(_magic_selement_t *selement, struct st_cb_info *cb_info)
479 {
480     /* Only do raw copying if there are no type transformations. */
481     if ((selement->type->num_child_types == 0 && selement->type->size == cb_info->local_selement->type->size) || selement->type == cb_info->local_selement->type || ST_TYPE_IS_CACHED_COUNTERPART(selement->type, cb_info->local_selement->type)) {
482         memcpy(cb_info->local_selement->address, selement->address, cb_info->local_selement->type->size);
483         return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
484     }
485 
486     return MAGIC_SENTRY_ANALYZE_CONTINUE;
487 }
488 
489 PRIVATE INLINE int transfer_identity_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
490 {
491     if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
492         /* First try to do raw copying, assuming there are no type transformations. */
493         if (transfer_try_raw_copy_sel_cb(selement, cb_info) == MAGIC_SENTRY_ANALYZE_SKIP_PATH)
494             return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
495 
496 #if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES
497         if (cb_info->init_info->flags & ST_LU_ASR) {
498             st_cbs_os.panic("ASR should never get here!");
499         }
500 #endif
501         if (selement->type->type_id == MAGIC_TYPE_UNION) {
502             ST_CB_PRINT(ST_CB_ERR, "uncaught ixfer union with type changes", selement, sel_analyzed, sel_stats, cb_info);
503             return EFAULT;
504         }
505         cb_info->st_cb_flags |= ST_CB_FORCE_IXFER;
506         return MAGIC_SENTRY_ANALYZE_CONTINUE;
507     }
508     return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
509 }
510 
511 PRIVATE INLINE int transfer_cond_identity_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
512 {
513     int r;
514     int saved_flags = cb_info->st_cb_flags;
515     cb_info->st_cb_flags &= ~ST_CB_PRINT_ERR;
516     r = default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
517     cb_info->st_cb_flags = saved_flags;
518     if (r < 0) {
519         ST_CB_PRINT(ST_CB_DBG, "conditional ixfer resorting to ixfer", selement, sel_analyzed, sel_stats, cb_info);
520         return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
521     }
522     return r;
523 }
524 
525 PRIVATE INLINE int transfer_nonptr_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
526 {
527     if (sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS) {
528         ST_CB_PRINT(ST_CB_ERR, "uncaught non-ptr with violations", selement, sel_analyzed, sel_stats, cb_info);
529         return EFAULT;
530     }
531     return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
532 }
533 
534 PRIVATE int transfer_ptr_sel_with_trg_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
535 {
536     int trg_flags, trg_extf_flags, trg_transferred, trg_paired;
537     _magic_selement_t cached_trg_selement, local_trg_selement;
538     void **local_selement_address = cb_info->local_selement->address;
539     int r;
540 
541     r = lookup_trg_info(selement, sel_analyzed, sel_stats, cb_info, &cached_trg_selement, &local_trg_selement);
542     if (r != OK) {
543         return r;
544     }
545 
546     trg_flags = sel_analyzed->u.ptr.trg_flags;
547     trg_extf_flags = MAGIC_STATE_FLAGS_TO_EXTF(trg_flags);
548     trg_transferred = (trg_extf_flags & (ST_NEEDS_TRANSFER | ST_TRANSFER_DONE));
549     trg_paired = (local_trg_selement.type != NULL);
550 
551     if (!trg_transferred && trg_paired && (trg_extf_flags & ST_ON_PTRXFER_CASCADE)) {
552         /* Propagate transfer on the target. */
553         if (cached_trg_selement.sentry && !(trg_extf_flags & ST_NEEDS_TRANSFER)) {
554             ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in cascade transfer for the target", selement, sel_analyzed, sel_stats, cb_info);
555             st_set_status_by_sentry_id(ST_NEEDS_TRANSFER, ST_OP_ADD, MAGIC_SENTRY_ID(cached_trg_selement.sentry));
556         }
557         /* Force code below to transfer the pointer normally. */
558         trg_transferred = TRUE;
559     }
560 
561     if (trg_transferred && trg_paired) {
562         *local_selement_address = local_trg_selement.address;
563     }
564     else if (trg_extf_flags & ST_ON_PTRXFER_SET_NULL) {
565         ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in forcefully setting ptr to NULL", selement, sel_analyzed, sel_stats, cb_info);
566         *local_selement_address = NULL;
567     }
568     else if(trg_extf_flags & ST_ON_PTRXFER_SET_DEFAULT) {
569         ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in forcefully setting ptr to default value", selement, sel_analyzed, sel_stats, cb_info);
570         if (trg_flags & MAGIC_STATE_STRING) {
571             *((char**)local_selement_address) = __UNCONST("");
572         }
573         else {
574             *local_selement_address = NULL;
575         }
576     }
577     else if (trg_extf_flags & ST_ON_PTRXFER_SKIP) {
578         ST_CB_PRINT(ST_CB_DBG, "ptr lookup results in skipping ptr transfer", selement, sel_analyzed, sel_stats, cb_info);
579     }
580     else {
581         if (trg_paired) {
582             ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for non-transferred target", selement, sel_analyzed, sel_stats, cb_info);
583         }
584         else {
585             ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for unpaired target", selement, sel_analyzed, sel_stats, cb_info);
586         }
587 #if DO_SKIP_UNPAIRED_PTR_TARGETS
588         return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
589 #else
590         return ENOENT;
591 #endif
592     }
593 
594     return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
595 }
596 
597 PRIVATE INLINE int transfer_ptr_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
598 {
599     const struct _magic_type *first_trg_type;
600     if (selement->type->type_id != MAGIC_TYPE_POINTER) {
601         if (selement->type->size != sizeof(void*)) {
602             ST_CB_PRINT(ST_CB_ERR, "wrong pointer size", selement, sel_analyzed, sel_stats, cb_info);
603             return EFAULT;
604         }
605         ST_CB_PRINT(ST_CB_DBG, "casting non-ptr to ptr element", selement, sel_analyzed, sel_stats, cb_info);
606         st_cb_selement_type_cast(MAGIC_VOID_PTR_INT_CAST_TYPE, MAGIC_VOID_PTR_INT_CAST_TYPE, selement, sel_analyzed, sel_stats, cb_info);
607     }
608     first_trg_type = MAGIC_SEL_ANALYZED_PTR_FIRST_TRG_TYPE(sel_analyzed);
609     if (first_trg_type == MAGIC_TYPE_NULL_ENTRY
610         || first_trg_type == MAGIC_TYPE_VALUE_FOUND) {
611 
612         /* NULL pointer or special value. Don't adjust value */
613         return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
614 
615     } else if (!(sel_analyzed->flags & MAGIC_SEL_FOUND_VIOLATIONS)) {
616         /* Valid pointer found */
617         if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
618             return transfer_ptr_sel_with_trg_cb(selement, sel_analyzed, sel_stats, cb_info);
619         }
620 
621         return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
622 
623     } else if(MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_STACK)) {
624         struct _magic_sentry *trg_sentry = magic_sentry_lookup_by_range(sel_analyzed->u.ptr.value, NULL);
625         if (trg_sentry && !strcmp(trg_sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) {
626             /* Stack pointer to initial stack area. This is common (e.g., argv).
627              * We can safely assume the pointer will be already correctly
628              * initialized in the new version and simply skip transfer.
629              */
630             ST_CB_PRINT(ST_CB_DBG, "skipping stack ptr element pointing to initial stack area", selement, sel_analyzed, sel_stats, cb_info);
631             return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
632         }
633     }
634 #ifdef __MINIX
635 #define IS_KERNEL_PTR(p) (((intptr_t)(p) & 0xf0000000) == 0xf0000000) /* TODO: make this more dynamic */
636     else if (IS_KERNEL_PTR(sel_analyzed->u.ptr.value))
637         return MAGIC_SENTRY_ANALYZE_SKIP_PATH; /* Kernel-mapped pointer */
638 #endif
639 
640     /* Pointer with violations found */
641     ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with violations", selement, sel_analyzed, sel_stats, cb_info);
642 #if DO_SKIP_INVARIANTS_VIOLATIONS
643     return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
644 #else
645     return EFAULT;
646 #endif
647 }
648 
649 PRIVATE INLINE int transfer_struct_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
650 {
651     static int st_counter = 0;
652     unsigned parent_offset, offset;
653     int walk_flags, ret;
654 
655     if (selement->type->type_id != MAGIC_TYPE_UNION && selement->type->type_id != MAGIC_TYPE_STRUCT) {
656         ST_CB_PRINT(ST_CB_ERR, "struct transfer is only for structs and unions!", selement, sel_analyzed, sel_stats, cb_info);
657         return EFAULT;
658     }
659     if (selement->type->type_id == MAGIC_TYPE_STRUCT || st_counter > 0) {
660         return MAGIC_SENTRY_ANALYZE_CONTINUE;
661     }
662 
663     /* Walk the union as a struct. */
664     walk_flags = cb_info->walk_flags;
665     cb_info->walk_flags = (MAGIC_TYPE_WALK_DEFAULT_FLAGS & (~MAGIC_TYPE_WALK_UNIONS_AS_VOID));
666     st_counter++;
667     parent_offset = (unsigned)selement->parent_address - (unsigned)selement->sentry->address;
668     offset = (unsigned)selement->address - (unsigned)selement->sentry->address;
669     ret =  magic_type_walk_flags(selement->parent_type, parent_offset,
670         selement->child_num, selement->type, offset,
671         0, ULONG_MAX, magic_type_analyzer_cb, selement->cb_args, cb_info->walk_flags);
672     st_counter--;
673     cb_info->walk_flags = walk_flags;
674     if (ret != 0) {
675         return ret == MAGIC_TYPE_WALK_STOP ? MAGIC_SENTRY_ANALYZE_STOP : ret;
676     }
677 
678     return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
679 }
680 
681 PRIVATE INLINE int default_transfer_selement_sel_cb(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
682 {
683     /* Default handler for walkable, ptr and nonptr types. */
684 #if ST_TRANSFER_IDENTITY_FOR_NO_INNER_PTRS
685     if (MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_NO_INNER_PTRS)) {
686         /* If the type has no inner pointers, try to do raw copying. */
687         if (transfer_try_raw_copy_sel_cb(selement, cb_info) == MAGIC_SENTRY_ANALYZE_SKIP_PATH)
688             return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
689     }
690 #endif
691     if (selement->type->type_id == MAGIC_TYPE_UNION) {
692         if (!(st_policies & ST_IXFER_UNCAUGHT_UNIONS) && !MAGIC_TYPE_FLAG(selement->type, MAGIC_TYPE_NO_INNER_PTRS)) {
693             ST_CB_PRINT(ST_CB_ERR, "uncaught union", selement, sel_analyzed, sel_stats, cb_info);
694             return EFAULT;
695         }
696         else {
697             int level = (st_policies & ST_REPORT_UNCAUGHT_UNIONS) ? ST_CB_ERR : ST_CB_DBG;
698             ST_CB_PRINT(level, "uncaught union", selement, sel_analyzed, sel_stats, cb_info);
699             return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
700         }
701     } else if (MAGIC_TYPE_IS_WALKABLE(selement->type)) {
702         return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
703     } else if (selement->type->type_id == MAGIC_TYPE_POINTER) {
704         return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
705     } else {
706         return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
707     }
708 
709     /* Not reachable. */
710     ST_CB_PRINT(ST_CB_ERR, "Bug!", selement, sel_analyzed, sel_stats, cb_info);
711     return EINTR;
712 }
713 
714 PUBLIC int st_cb_transfer_sentry_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
715 {
716     const char *sentry_name = selement->sentry->name;
717 
718 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
719     if (MAGIC_STATE_FLAGS(selement->sentry, MAGIC_STATE_DYNAMIC)) {
720         if (MAGIC_STATE_FLAG(selement->sentry, MAGIC_STATE_LIB) || MAGIC_SENTRY_IS_EXT_ALLOC(selement->sentry))
721             return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
722     }
723 #endif
724 
725     if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_ixfers, sentry_name)) {
726         ST_CB_PRINT(ST_CB_DBG, "sentry name matches ixfer", selement, sel_analyzed, sel_stats, cb_info);
727         return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
728     }
729 
730     if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_cixfers, sentry_name)) {
731         ST_CB_PRINT(ST_CB_DBG, "sentry name matches cixfer", selement, sel_analyzed, sel_stats, cb_info);
732         return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
733     }
734 
735     if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_noxfers, sentry_name)) {
736         ST_CB_PRINT(ST_CB_DBG, "sentry name matches noxfer", selement, sel_analyzed, sel_stats, cb_info);
737         return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
738     }
739 
740     /* Skip memory management related sentries only when memory functions have
741      * been instrumented (which is *not* the case for the MINIX3 VM service).
742      */
743     if (_magic_no_mem_inst == 0 && ST_SENTRY_NAME_MATCH_ANY(st_sentryname_noxfers_mem, sentry_name)) {
744         ST_CB_PRINT(ST_CB_DBG, "sentry name matches noxfer", selement, sel_analyzed, sel_stats, cb_info);
745         return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
746     }
747 
748     if (ST_SENTRY_NAME_MATCH_ANY(st_sentryname_pxfers, sentry_name)) {
749         ST_CB_PRINT(ST_CB_DBG, "sentry name matches pxfer", selement, sel_analyzed, sel_stats, cb_info);
750         return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
751     }
752 
753     if (MAGIC_STATE_FLAGS(selement->sentry, MAGIC_STATE_DYNAMIC | MAGIC_STATE_MAP | MAGIC_STATE_LIB)) {
754         struct _magic_dsentry *dsentry = MAGIC_DSENTRY_FROM_SENTRY(selement->sentry);
755         if (ST_DSENTRY_PARENT_NAME_MATCH_ANY(st_dsentry_lib_noxfer, dsentry->parent_name)) {
756             ST_CB_PRINT(ST_CB_DBG, "dsentry is a lib map and parent_name matches dsentry_lib_noxfer", selement, sel_analyzed, sel_stats, cb_info);
757             return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
758         }
759     }
760 
761     return ST_CB_NOT_PROCESSED;
762 }
763 
764 PUBLIC int st_cb_transfer_typename_default(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
765 {
766     const char *typename_key = ST_TYPE_NAME_KEY(selement->type);
767     if (ST_TYPE_NAME_MATCH_ANY(st_typename_ixfers, typename_key)) {
768         return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
769     }
770 
771     if (ST_TYPE_NAME_MATCH_ANY(st_typename_cixfers, typename_key)) {
772         return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
773     }
774 
775     if (ST_TYPE_NAME_MATCH_ANY(st_typename_noxfers, typename_key)) {
776         return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
777     }
778 
779     if (ST_TYPE_NAME_MATCH_ANY(st_typename_pxfers, typename_key)) {
780         return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
781     }
782 
783     if (ST_TYPE_NAME_MATCH_ANY(st_typename_sxfers, typename_key)) {
784         return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
785     }
786 
787     return ST_CB_NOT_PROCESSED;
788 }
789 
790 PUBLIC int st_cb_transfer_walkable(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
791 {
792     return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
793 }
794 
795 PUBLIC int st_cb_transfer_ptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
796 {
797     return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
798 }
799 
800 PUBLIC int st_cb_transfer_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
801 {
802     return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
803 }
804 
805 PUBLIC int st_cb_transfer_cond_identity(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
806 {
807     return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
808 }
809 
810 PUBLIC int st_cb_transfer_nonptr(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
811 {
812     return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
813 }
814 
815 PUBLIC int st_cb_transfer_struct(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
816 {
817     return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
818 }
819 
820 PUBLIC int st_cb_transfer_selement_base(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
821 {
822     return default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
823 }
824 
825 PUBLIC int st_cb_transfer_selement_generic(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info)
826 {
827     return transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info);
828 }
829 
830 /* Selement mapping functions and callbacks. */
831 
832 PRIVATE int st_map_selement_from_sentry_cb(const struct _magic_type* parent_type,
833     const unsigned parent_offset, int child_num,
834     const struct _magic_type* type, const unsigned offset, int depth, void* cb_args)
835 {
836     void **args_array = (void**) cb_args;
837     _magic_selement_t cached_selement;
838     _magic_selement_t *local_selement = (_magic_selement_t*) args_array[1];
839     _magic_selement_t *selement = (_magic_selement_t*) args_array[0];
840     struct _magic_sentry *sentry = selement->sentry;
841     void *address = (char*)sentry->address + offset;
842     void *selement_address = selement->address;
843     int is_trg_mapping;
844     struct st_cb_info *cb_info;
845     if ((char*) selement_address >= ((char*) address + type->size)) {
846         return MAGIC_TYPE_WALK_SKIP_PATH;
847     }
848     cb_info = (struct st_cb_info*) args_array[2];
849     is_trg_mapping = (int) args_array[3];
850     cached_selement.sentry = sentry;
851     cached_selement.parent_type = parent_type;
852     cached_selement.parent_address = (char*)sentry->address + parent_offset;
853     cached_selement.child_num = child_num;
854     cached_selement.type = type;
855     cached_selement.address = address;
856     cached_selement.depth = depth;
857     st_map_selement(&cached_selement, local_selement, cb_info, is_trg_mapping);
858     if (local_selement->type == NULL) {
859         return ENOENT;
860     }
861     if (address == selement_address && type == selement->type) {
862         return MAGIC_TYPE_WALK_STOP;
863     }
864     if (type->num_child_types == 0) {
865         return EINVAL;
866     }
867     local_selement->parent_type = local_selement->type;
868     local_selement->parent_address = local_selement->address;
869     return MAGIC_TYPE_WALK_CONTINUE;
870 }
871 
872 PRIVATE INLINE void st_map_selement_from_sentry(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct _magic_sentry *local_sentry, struct st_cb_info *cb_info, int is_trg_mapping)
873 {
874     unsigned max_offset;
875     int r;
876     void *args_array[4];
877     max_offset = (unsigned) ( (char *)cached_selement->address - (char *)cached_selement->sentry->address);
878     args_array[0] = cached_selement;
879     args_array[1] = magic_selement_from_sentry(local_sentry, local_selement);
880     args_array[2] = cb_info;
881     args_array[3] = (void*) is_trg_mapping;
882     r = magic_type_walk_root(cached_selement->sentry->type, 0, max_offset, st_map_selement_from_sentry_cb, (void*) args_array);
883     if (r < 0) {
884         assert(r == ENOENT);
885         local_selement->type = NULL;
886     }
887 }
888 
889 PRIVATE INLINE void st_map_sel_analyzed_from_target(_magic_sel_analyzed_t *cached_sel_analyzed, _magic_sel_analyzed_t *local_sel_analyzed, struct _magic_sentry *local_trg_sentry, struct _magic_function *local_trg_function, struct st_cb_info *cb_info)
890 {
891     _magic_selement_t *csel, *lsel;
892     assert(local_trg_sentry || local_trg_function);
893     assert(cached_sel_analyzed->type_id == MAGIC_TYPE_POINTER);
894     assert(cached_sel_analyzed->u.ptr.first_legal_trg_type>=0);
895     local_sel_analyzed->type_id = cached_sel_analyzed->type_id;
896     local_sel_analyzed->num = cached_sel_analyzed->num;
897     local_sel_analyzed->flags = cached_sel_analyzed->flags;
898     local_sel_analyzed->u.ptr.trg_flags = local_trg_sentry ? local_trg_sentry->flags : local_trg_function->flags;
899     local_sel_analyzed->u.ptr.first_legal_trg_type = -1;
900     local_sel_analyzed->u.ptr.num_legal_trg_types = 0;
901     if (local_trg_function) {
902         assert(cached_sel_analyzed->u.ptr.num_legal_trg_types == 1);
903         lsel = &local_sel_analyzed->u.ptr.trg_selements[0];
904         memset(lsel, 0, sizeof(_magic_selement_t));
905         lsel->sentry = NULL;
906         lsel->type = local_trg_function->type;
907         lsel->address = local_trg_function->address;
908         local_sel_analyzed->u.ptr.num_trg_types = 1;
909     }
910     else {
911         unsigned int i;
912         void *address = NULL;
913         local_sel_analyzed->u.ptr.num_trg_types = 0;
914         for (i = cached_sel_analyzed->u.ptr.first_legal_trg_type ; i < cached_sel_analyzed->u.ptr.num_trg_types ; i++) {
915             _magic_trg_stats_t trg_stats = cached_sel_analyzed->u.ptr.trg_stats[i];
916             if (MAGIC_SEL_ANALYZED_TRG_STATS_HAS_VIOLATIONS(trg_stats)) {
917                 continue;
918             }
919             csel = &cached_sel_analyzed->u.ptr.trg_selements[i];
920             lsel = &local_sel_analyzed->u.ptr.trg_selements[local_sel_analyzed->u.ptr.num_trg_types++];
921             st_map_selement_from_sentry(csel, lsel, local_trg_sentry, cb_info, TRUE);
922             if (lsel->type == NULL || (address && lsel->address != address)) {
923                 /* Unpaired selement or ambiguous local address. */
924                 local_sel_analyzed->u.ptr.num_trg_types = 0;
925                 return;
926             }
927             address = lsel->address;
928         }
929         assert(local_sel_analyzed->u.ptr.num_trg_types > 0);
930     }
931 }
932 
933 PUBLIC void st_map_local_selement_from_child_num(_magic_selement_t *local_selement, struct st_cb_info *cb_info, int child_num)
934 {
935     local_selement->child_num = child_num;
936     magic_selement_fill_from_parent_info(local_selement, cb_info->walk_flags);
937 }
938 
939 PUBLIC void st_cb_map_from_parent_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
940 {
941     int cached_num_elements, local_num_elements, is_trg_at_array_end, is_trg_at_str_end;
942     /* Match arrays/vectors with arrays/vectors. */
943     assert(cached_selement->parent_type->type_id == MAGIC_TYPE_ARRAY || cached_selement->parent_type->type_id == MAGIC_TYPE_VECTOR);
944     if (local_selement->parent_type->type_id != MAGIC_TYPE_ARRAY && local_selement->parent_type->type_id != MAGIC_TYPE_VECTOR) {
945         local_selement->type = NULL;
946         return;
947     }
948     cached_num_elements = cached_selement->parent_type->num_child_types;
949     local_num_elements = local_selement->parent_type->num_child_types;
950     /* Same size or first child? We are done. */
951     if (cached_num_elements == local_num_elements || local_selement->child_num == 0) {
952          st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num);
953          return;
954     }
955     assert(local_num_elements > 0);
956     is_trg_at_str_end = FALSE;
957     is_trg_at_array_end = FALSE;
958     if (is_trg_mapping && cached_selement->child_num == cached_num_elements-1) {
959         is_trg_at_str_end = MAGIC_SENTRY_IS_STRING(cached_selement->sentry) || MAGIC_SENTRY_IS_STRING(local_selement->sentry);
960         is_trg_at_array_end = !is_trg_at_str_end;
961     }
962     if (is_trg_at_array_end && (st_policies & ST_DEFAULT_MAP_GUARD_PTRS_TO_ARRAY_END)) {
963         /* This should be interpreted as a target of a guard pointer pointing to the last element of an array and needs to be remapped as such. */
964         st_map_local_selement_from_child_num(local_selement, cb_info, local_num_elements-1);
965     }
966     else if (is_trg_at_str_end && (st_policies & ST_DEFAULT_MAP_GUARD_PTRS_TO_STR_END)) {
967         /* This should be interpreted as a target of a guard pointer pointing to the last element of a string and needs to be remapped as such. */
968         st_map_local_selement_from_child_num(local_selement, cb_info, local_num_elements-1);
969     }
970     else if (cached_selement->child_num >= local_num_elements) {
971         /* New array got truncated and this element is gone. */
972         local_selement->type = NULL;
973     }
974     else {
975         /* New array is bigger, just keep the original position in the array. */
976         st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num);
977     }
978 }
979 
980 PUBLIC void st_cb_map_child_array_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
981 {
982     size_t cached_size = cached_selement->type->num_child_types, local_size = local_selement->type->num_child_types;
983 
984     /* Match arrays/vectors with arrays/vectors. */
985     assert(cached_selement->type->type_id == MAGIC_TYPE_ARRAY || cached_selement->type->type_id == MAGIC_TYPE_VECTOR);
986     if (local_selement->type->type_id != MAGIC_TYPE_ARRAY && local_selement->type->type_id != MAGIC_TYPE_VECTOR) {
987         local_selement->type = NULL;
988         return;
989     }
990 
991     /* Varsized arrays have to be consistent across versions. */
992     if (MAGIC_TYPE_FLAG(cached_selement->type, MAGIC_TYPE_VARSIZE) != MAGIC_TYPE_FLAG(local_selement->type, MAGIC_TYPE_VARSIZE)) {
993         local_selement->type = NULL;
994         return;
995     }
996 
997     /* Check size. */
998     if (cached_size != local_size) {
999         int report;
1000         int is_string = MAGIC_SENTRY_IS_STRING(cached_selement->sentry) || MAGIC_SENTRY_IS_STRING(local_selement->sentry);
1001         if (local_size < cached_size) {
1002             report = is_string ? (st_policies & ST_REPORT_SMALLER_STRINGS) : (st_policies & ST_REPORT_SMALLER_ARRAYS);
1003         }
1004         else {
1005             report = is_string ? (st_policies & ST_REPORT_LARGER_STRINGS) : (st_policies & ST_REPORT_LARGER_ARRAYS);
1006         }
1007 
1008         if (report) {
1009             printf("st_cb_map_child_array_selement_generic: %s size found while mapping array selements:\n", local_size < cached_size ? "Smaller" : "Larger");
1010             MAGIC_SELEMENT_PRINT(cached_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
1011             MAGIC_SELEMENT_PRINT(local_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
1012         }
1013     }
1014 }
1015 
1016 PUBLIC void st_cb_map_from_parent_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1017 {
1018     /* This should only be called in case of unions transferred as structs. */
1019     st_cb_map_from_parent_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1020 }
1021 
1022 PUBLIC void st_cb_map_child_union_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1023 {
1024     /* Match unions just like structs. */
1025     st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1026 }
1027 
1028 PUBLIC void st_cb_map_from_parent_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1029 {
1030     unsigned int i;
1031     const char *cached_member_name;
1032     /* Match struct/unions with struct/unions. */
1033     assert(cached_selement->parent_type->type_id == MAGIC_TYPE_STRUCT || cached_selement->parent_type->type_id == MAGIC_TYPE_UNION);
1034     if (local_selement->parent_type->type_id != MAGIC_TYPE_STRUCT && local_selement->parent_type->type_id != MAGIC_TYPE_UNION) {
1035         local_selement->type = NULL;
1036         return;
1037     }
1038     /* Match struct/unions members by name. */
1039     cached_member_name = cached_selement->parent_type->member_names[cached_selement->child_num];
1040     for (i = 0 ; i < local_selement->parent_type->num_child_types ; i++) {
1041         if (!strcmp(local_selement->parent_type->member_names[i], cached_member_name)) {
1042             st_map_local_selement_from_child_num(local_selement, cb_info, i);
1043             return;
1044         }
1045     }
1046     local_selement->type = NULL;
1047 }
1048 
1049 PUBLIC void st_cb_map_child_struct_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1050 {
1051     unsigned int i, j;
1052     const struct _magic_type *cached_type = cached_selement->type;
1053     const struct _magic_type *local_type = local_selement->type;
1054     assert(cached_type->type_id == MAGIC_TYPE_STRUCT || cached_type->type_id == MAGIC_TYPE_UNION);
1055     if (local_type->type_id != MAGIC_TYPE_STRUCT && local_type->type_id != MAGIC_TYPE_UNION) {
1056         local_selement->type = NULL;
1057         return;
1058     }
1059     /* Match struct/unions by name(s). */
1060     if (!strcmp(cached_type->name, local_type->name)) {
1061         return;
1062     }
1063     if (cached_type->num_names > 1 || local_type->num_names > 1 ) {
1064         for (i = 0 ; i < cached_type->num_names ; i++) {
1065             for (j = 0 ; j < local_type->num_names ; j++) {
1066                 if (!strcmp(cached_type->names[i], local_type->names[j])) {
1067                     return;
1068                 }
1069             }
1070         }
1071     }
1072 
1073     local_selement->type = NULL;
1074 }
1075 
1076 PUBLIC void st_cb_map_child_nonaggr_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1077 {
1078     int r;
1079     static char magic_value_buffer[32];
1080 
1081     r = magic_selement_value_cast(cached_selement, local_selement, magic_value_buffer);
1082     if (r == 0) {
1083         return;
1084     }
1085     if (r < 0 && r != MAGIC_ERANGE && r != MAGIC_ESIGN) {
1086         local_selement->type = NULL;
1087         return;
1088     }
1089     if ((r == MAGIC_ERANGE && (st_policies & ST_REPORT_PRECISION_LOSS))
1090         || (r == MAGIC_ESIGN && (st_policies & ST_REPORT_SIGN_CHANGE))) {
1091         _magic_selement_t converted_selement = *cached_selement;
1092         converted_selement.address = magic_value_buffer;
1093         converted_selement.type = local_selement->type;
1094         printf("st_cb_map_child_nonaggr_selement_generic: %s while mapping non-aggregate selements:\n", r == MAGIC_ERANGE ? "Precision loss" : "Sign change");
1095         MAGIC_SELEMENT_PRINT(cached_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
1096         MAGIC_SELEMENT_PRINT(local_selement, MAGIC_EXPAND_TYPE_STR); printf("\n");
1097         printf(" - ORIGINAL VALUE: "); magic_selement_print_value(cached_selement); printf("\n");
1098         printf(" - MAPPED   VALUE: "); magic_selement_print_value(&converted_selement); printf("\n");
1099     }
1100     cached_selement->address = magic_value_buffer;
1101 }
1102 
1103 PUBLIC void st_cb_map_from_parent_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1104 {
1105     assert(cached_selement->parent_type && local_selement->parent_type);
1106     switch(cached_selement->parent_type->type_id) {
1107         case MAGIC_TYPE_ARRAY:
1108         case MAGIC_TYPE_VECTOR:
1109              st_cb_map_from_parent_array_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1110         break;
1111 
1112         case MAGIC_TYPE_UNION:
1113             st_cb_map_from_parent_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1114         break;
1115 
1116         case MAGIC_TYPE_STRUCT:
1117             st_cb_map_from_parent_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1118         break;
1119 
1120         default:
1121             st_cbs_os.panic("Invalid parent type!");
1122         break;
1123     }
1124 }
1125 
1126 PUBLIC void st_cb_map_child_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1127 {
1128     assert(cached_selement->type);
1129     if (local_selement->type == NULL) {
1130         return;
1131     }
1132     if (cached_selement->type->num_child_types == 0 || cached_selement->type->type_id == MAGIC_TYPE_POINTER) {
1133         st_cb_map_child_nonaggr_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1134         return;
1135     }
1136     switch (cached_selement->type->type_id) {
1137         case MAGIC_TYPE_ARRAY:
1138         case MAGIC_TYPE_VECTOR:
1139             st_cb_map_child_array_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1140         break;
1141 
1142         case MAGIC_TYPE_UNION:
1143             st_cb_map_child_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1144         break;
1145 
1146         case MAGIC_TYPE_STRUCT:
1147             st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1148         break;
1149 
1150         default:
1151             st_cbs_os.panic("Invalid parent type!");
1152         break;
1153     }
1154 }
1155 
1156 
1157 PUBLIC void st_cb_map_selement_generic(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1158 {
1159     int i;
1160     assert(cached_selement->type->type_id != MAGIC_TYPE_FUNCTION);
1161     for (i = 0 ; i < MAGIC_ST_TYPE_TRANS_ITERATIONS ; i++) {
1162         if (cached_selement->parent_type) {
1163             st_cb_map_from_parent_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1164         }
1165         st_cb_map_child_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1166     }
1167 }
1168 
1169 PRIVATE INLINE void st_map_selement(_magic_selement_t *cached_selement, _magic_selement_t *local_selement, struct st_cb_info *cb_info, int is_trg_mapping)
1170 {
1171     const struct _magic_type *cached_parent_type = cached_selement->parent_type;
1172     const struct _magic_type *local_parent_type = local_selement->parent_type;
1173     const struct _magic_type *cached_type = cached_selement->type;
1174 
1175     if (cached_parent_type) {
1176         if (cached_parent_type == local_parent_type) {
1177             /* Quickly propagate perfect type pairs from parents. */
1178             local_selement->address = (char *)local_selement->parent_address + ((char *)cached_selement->address - (char *)cached_selement->parent_address);
1179             local_selement->type = cached_type;
1180             return;
1181         }
1182         else if (ST_TYPE_IS_CACHED_COUNTERPART(cached_parent_type, local_parent_type)) {
1183             /* Quickly propagate type pairs from parents. */
1184             st_map_local_selement_from_child_num(local_selement, cb_info, cached_selement->child_num);
1185             return;
1186         }
1187         else {
1188             local_selement->type = NULL;
1189         }
1190     }
1191     else {
1192         /* In case of target mapping, we don't care about compatible types. When paired types are found, add a perfect type pair to speed up subsequent lookups. */
1193         if (ST_TYPE_IS_CACHED_COUNTERPART(cached_type, local_selement->type)) {
1194             if (is_trg_mapping) local_selement->type = cached_type;
1195             return;
1196         }
1197     }
1198 #if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES
1199     if (cb_info->init_info->flags & ST_LU_ASR) {
1200         st_cbs_os.panic("ASR should never get here!");
1201     }
1202 #endif
1203 
1204     st_num_type_transformations++;
1205     st_cbs.st_cb_selement_map(cached_selement, local_selement, cb_info, is_trg_mapping);
1206 
1207     /* Check again for paired types and add a perfect type pair to speed up subsequent lookups in case of target mapping. */
1208     if (is_trg_mapping && local_selement->type != NULL && local_selement->type != cached_selement->type) {
1209         if (ST_TYPE_IS_CACHED_COUNTERPART(cached_selement->type, local_selement->type)) {
1210             local_selement->type = cached_selement->type;
1211         }
1212     }
1213 }
1214 
1215 /* main functions */
1216 
1217 PUBLIC int st_state_transfer(st_init_info_t *info)
1218 {
1219     int r;
1220 
1221     /*
1222      * Set all OS dependent callbacks first.
1223      */
1224     st_setcb_os_all(&info->st_cbs_os);
1225 
1226 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
1227     _magic_vars->fake_malloc = 1;
1228 #endif
1229 
1230     r = st_init(info);
1231 
1232 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
1233     _magic_vars->fake_malloc = 0;
1234 #endif
1235 
1236     if (r != OK) {
1237         return r;
1238     }
1239 
1240     r = st_data_transfer(info);
1241     if (r != OK) {
1242         return r;
1243     }
1244 
1245 #if ST_DEBUG_LEVEL > 0
1246     printf("st_state_transfer: state transfer is done, num type transformations: %u.\n", st_num_type_transformations);
1247 #endif
1248 
1249     st_cleanup(info);
1250 
1251     return OK;
1252 }
1253 
1254 #if APPARENTLY_UNUSED
1255 PUBLIC void st_set_policies(int policies)
1256 {
1257     st_policies = policies;
1258 }
1259 #endif
1260 
1261 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
1262 PRIVATE void st_init_rl_index(st_init_info_t *info,
1263     struct _magic_vars_t *magic_vars)
1264 {
1265     size_t buff_size;
1266     void *buff;
1267 
1268     EXEC_WITH_MAGIC_VARS(
1269         buff_size = magic_sentry_rl_estimate_index_buff_size(0);
1270         , magic_vars
1271     );
1272     buff = st_buff_allocate(info, buff_size);
1273 
1274     EXEC_WITH_MAGIC_VARS(
1275         magic_sentry_rl_build_index(buff, buff_size);
1276         , magic_vars
1277     );
1278 }
1279 
1280 PRIVATE void st_cleanup_rl_index(st_init_info_t *info,
1281     struct _magic_vars_t *magic_vars)
1282 {
1283     EXEC_WITH_MAGIC_VARS(
1284         magic_sentry_rl_destroy_index();
1285         , magic_vars
1286     );
1287 }
1288 #endif
1289 
1290 #if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
1291 PRIVATE void st_init_sentry_hash(st_init_info_t *info,
1292     struct _magic_vars_t *magic_vars)
1293 {
1294     size_t buff_size;
1295     void *buff;
1296 
1297     EXEC_WITH_MAGIC_VARS(
1298         buff_size = magic_sentry_hash_estimate_buff_size(0);
1299         , magic_vars
1300     );
1301     buff = st_buff_allocate(info, buff_size);
1302 
1303     EXEC_WITH_MAGIC_VARS(
1304         magic_sentry_hash_build(buff, buff_size);
1305         , magic_vars
1306     );
1307 }
1308 
1309 PRIVATE void st_cleanup_sentry_hash(st_init_info_t *info,
1310     struct _magic_vars_t *magic_vars)
1311 {
1312     EXEC_WITH_MAGIC_VARS(
1313         magic_sentry_hash_destroy();
1314         , magic_vars
1315     );
1316 }
1317 #endif
1318 
1319 #if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
1320 PRIVATE void st_init_function_hash(st_init_info_t *info,
1321     struct _magic_vars_t *magic_vars)
1322 {
1323     size_t buff_size;
1324     void *buff;
1325 
1326     EXEC_WITH_MAGIC_VARS(
1327         buff_size = magic_function_hash_estimate_buff_size(0);
1328         , magic_vars
1329     );
1330     buff = st_buff_allocate(info, buff_size);
1331 
1332     EXEC_WITH_MAGIC_VARS(
1333         magic_function_hash_build(buff, buff_size);
1334         , magic_vars
1335     );
1336 }
1337 
1338 PRIVATE void st_cleanup_function_hash(st_init_info_t *info,
1339     struct _magic_vars_t *magic_vars)
1340 {
1341     EXEC_WITH_MAGIC_VARS(
1342         magic_function_hash_destroy();
1343         , magic_vars
1344     );
1345 }
1346 #endif
1347 
1348 PRIVATE void st_vars_clear_ptrs(struct _magic_vars_t *magic_vars)
1349 {
1350 #undef __X
1351 #define __X(x) offsetof(struct _magic_vars_t, x)
1352     size_t offset_list[] = { ST_MAGIC_VARS_PTR_CLEAR_LIST };
1353 #undef __X
1354     unsigned int i;
1355 
1356     for (i = 0 ; i < sizeof(offset_list) / sizeof(size_t) ; i++)
1357         *((void **)(((char *)magic_vars) + offset_list[i])) = NULL;
1358 }
1359 
1360 
1361 #ifdef __MINIX
1362 PRIVATE void st_unmap_mem(struct _magic_vars_t *magic_vars)
1363 {
1364     int i, r;
1365 
1366     for (i = 0; i < MAGIC_UNMAP_MEM_ENTRIES; i++) {
1367         if (magic_vars->unmap_mem[i].length != 0) {
1368 #if ST_DEBUG_LEVEL > 0
1369             printf("st_unmap_mem: unmapping (%p, %zu)\n",
1370                 magic_vars->unmap_mem[i].start,
1371                 magic_vars->unmap_mem[i].length);
1372 #endif
1373             r = munmap(magic_vars->unmap_mem[i].start,
1374                 magic_vars->unmap_mem[i].length);
1375             assert(r == 0);
1376         }
1377     }
1378 }
1379 #endif
1380 
1381 PUBLIC int st_init(st_init_info_t *info)
1382 {
1383     size_t max_buff_sz = 0;
1384     int r, dsentries_num;
1385     int allow_unpaired_types = TRUE;
1386     if (st_init_done) {
1387         return OK;
1388     }
1389     if (!_magic_enabled) return ENOSYS;
1390     st_init_done = TRUE;
1391 
1392     /* Ignore nested mempool dsentries for now. */
1393     magic_lookup_nested_dsentries = 0;
1394 
1395     /* Override default state transfer policies for ASR. */
1396     if ((info->flags & ST_LU_ASR) && st_policies == ST_POLICIES_DEFAULT) {
1397         st_policies = ST_POLICIES_DEFAULT_TRANSFER_ASR;
1398     }
1399 
1400     /* Fixup state transfer policies based on current configuration. */
1401 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
1402     st_policies &= (~ST_DEFAULT_ALLOC_CASCADE_XFER);
1403 #elif !defined(__MINIX)
1404     st_policies |= ST_TRANSFER_DIRTY_ONLY;
1405 #endif
1406 
1407     assert((!info->init_buff_start || (info->flags & ST_LU_NOMMAP)) && "st_init: no mmapping allowed, and no buffer is available");
1408     register_typenames_and_callbacks();
1409 
1410     /* Transfer _magic_vars, which contain addresses of the magic variables */
1411     r = st_cbs_os.old_state_table_lookup(info->info_opaque, &st_remote_magic_vars);
1412     assert( r == OK && "ERROR occurred during transfer of _magic_vars.");
1413     /*
1414      * Clear all pointers not explictly transferred, as they are not valid in
1415      * the new address space.
1416      */
1417     st_vars_clear_ptrs(&st_remote_magic_vars);
1418 
1419     /*
1420      * Some magic_vars members do not need transfer or adjustment
1421      * (e.g. the memory ranges). They are copied to st_cached_magic_vars
1422      * this way.
1423      */
1424     st_cached_magic_vars = st_remote_magic_vars;
1425 
1426     /* Transfer and adjust metadata */
1427     r = st_transfer_metadata_types(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts);
1428     assert( r == OK && "ERROR occurred during transfer of type metadata.");
1429     r = transfer_metadata_functions(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts);
1430     assert( r == OK && "ERROR occurred during transfer of function metadata.");
1431     r = transfer_metadata_dfunctions(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts);
1432     assert( r == OK && "ERROR occurred during transfer of dfunction metadata.");
1433     r = transfer_metadata_sentries(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts, &max_buff_sz);
1434     assert( r == OK && "ERROR occurred during transfer of sentry metadata.");
1435     r = st_transfer_metadata_dsentries(info, &st_cached_magic_vars, &st_remote_magic_vars, &st_counterparts, &max_buff_sz, &dsentries_num);
1436     assert( r == OK && "ERROR occurred during transfer of dsentry metadata.");
1437 
1438     /* Allocate buffer for data transfer */
1439     st_dsentry_buff = st_buff_allocate(info, max_buff_sz + sizeof(struct _magic_dsentry));
1440     if (!st_dsentry_buff) {
1441         printf("st_dsentry_buff could not be allocated.\n");
1442         return EGENERIC;
1443     }
1444     st_data_buff = &st_dsentry_buff[1];
1445 
1446     /* Allocate and initialize counterparts buffers. */
1447     st_counterparts.functions_size = st_cached_magic_vars.functions_num;
1448     st_counterparts.functions = st_buff_allocate(info, st_counterparts.functions_size * sizeof(st_ptr_mapping));
1449     assert(st_counterparts.functions && "st_counterparts.functions could not be allocated.");
1450 
1451     st_counterparts.types_size = st_cached_magic_vars.types_num;
1452     st_counterparts.types = st_buff_allocate(info, st_counterparts.types_size * sizeof(st_ptr_mapping));
1453     assert(st_counterparts.types && "st_counterparts.types could not be allocated.");
1454     st_counterparts.ptr_types = st_buff_allocate(info, st_counterparts.types_size * sizeof(st_ptr_mapping));
1455     assert(st_counterparts.ptr_types && "st_counterparts.ptr_types could not be allocated.");
1456 
1457     st_counterparts.sentries_size = st_cached_magic_vars.sentries_num + dsentries_num;
1458     st_counterparts.sentries = st_buff_allocate(info, st_counterparts.sentries_size * sizeof(st_ptr_mapping));
1459     assert(st_counterparts.sentries && "st_counterparts.sentries could not be allocated.");
1460     st_counterparts.sentries_data = st_buff_allocate(info, st_counterparts.sentries_size * sizeof(st_ptr_mapping));
1461     assert(st_counterparts.sentries_data && "st_counterparts.sentries_data could not be allocated.");
1462 
1463 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
1464     st_init_rl_index(info, &st_cached_magic_vars);
1465 #endif
1466 
1467 #if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
1468     st_init_sentry_hash(info, &st_cached_magic_vars);
1469     st_init_sentry_hash(info, _magic_vars);
1470 #endif
1471 
1472 #if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
1473     st_init_function_hash(info, &st_cached_magic_vars);
1474     st_init_function_hash(info, _magic_vars);
1475 #endif
1476 
1477 #ifdef __MINIX
1478     /* Unmap any memory ranges that are not needed in the new process. */
1479     st_unmap_mem(&st_cached_magic_vars);
1480 #endif
1481 
1482     /* Pair metadata entities */
1483     r = pair_metadata_types(info, &st_cached_magic_vars, &st_counterparts, allow_unpaired_types);
1484     assert( r == OK && "ERROR occurred during call to pair_metadata_types().");
1485     r = pair_metadata_functions(info, &st_cached_magic_vars, &st_counterparts);
1486     assert( r == OK && "ERROR occurred during call to pair_metadata_functions().");
1487     r = pair_metadata_sentries(info, &st_cached_magic_vars, &st_counterparts);
1488     assert( r == OK && "ERROR occurred during call to pair_metadata_sentries().");
1489 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
1490     r = allocate_pair_metadata_dsentries_from_raw_copy(info, &st_cached_magic_vars, &st_counterparts);
1491     assert( r == OK && "ERROR occurred during call to allocate_pair_metadata_dsentries().");
1492 #else
1493     r = allocate_pair_metadata_dsentries(info, &st_cached_magic_vars, &st_counterparts);
1494     assert( r == OK && "ERROR occurred during call to allocate_pair_metadata_dsentries().");
1495 #endif
1496 
1497     /* Set state transfer status defaults from the predefined policies. */
1498     st_set_status_defaults(info);
1499 
1500 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
1501     st_init_rl_index(info, _magic_vars);
1502 #endif
1503 
1504     return OK;
1505 }
1506 
1507 PRIVATE INLINE char* st_lookup_str_local_data(struct _magic_sentry *cached_sentry)
1508 {
1509     void *local_data_addr;
1510     assert(cached_sentry && MAGIC_SENTRY_IS_STRING(cached_sentry));
1511     ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
1512     assert(local_data_addr && "String data not in cache!");
1513     return (char*) local_data_addr;
1514 }
1515 
1516 #if ST_DEBUG_DATA_TRANSFER
1517 PRIVATE void st_print_sentities(struct _magic_vars_t *magic_vars)
1518 {
1519     struct _magic_dsentry *dsentry = magic_vars->first_dsentry;
1520     int i;
1521 
1522     for (i = 0 ; i < magic_vars->sentries_num ; i++) {
1523         struct _magic_sentry *sentry = &magic_vars->sentries[i];
1524         ST_SENTRY_PRINT(sentry, 0);
1525         printf("\n");
1526     }
1527 
1528     while (dsentry != NULL) {
1529         ST_DSENTRY_PRINT(dsentry, 0);
1530         printf("\n");
1531         dsentry = dsentry->next;
1532     }
1533 
1534     for (i = 0 ; i < magic_vars->functions_num ; i++) {
1535         struct _magic_function *function = &magic_vars->functions[i];
1536         ST_FUNCTION_PRINT(function, 0);
1537         printf("\n");
1538     }
1539 }
1540 #endif
1541 
1542 PUBLIC void st_map_str_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
1543 {
1544     struct _magic_sentry *cached_sentry = *cached_sentry_ptr;
1545     struct _magic_sentry *local_sentry = *local_sentry_ptr;
1546     struct _magic_sentry *sentry = cached_sentry ? cached_sentry : local_sentry;
1547     int string_flags, match_by_name, match_by_content;
1548     ST_CHECK_INIT();
1549     assert((cached_sentry == NULL) ^ (local_sentry == NULL));
1550 
1551     string_flags = sentry->flags & (MAGIC_STATE_STRING|MAGIC_STATE_NAMED_STRING);
1552     assert(string_flags & MAGIC_STATE_STRING);
1553     match_by_name = (string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_NAMED_STRINGS_BY_NAME);
1554     match_by_content = ((string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_NAMED_STRINGS_BY_CONTENT))
1555         || (!(string_flags & MAGIC_STATE_NAMED_STRING) && (st_policies & ST_MAP_STRINGS_BY_CONTENT));
1556     if (match_by_name) {
1557         /* Pretend it's a regular sentry and match by name */
1558         sentry->flags &= ~string_flags;
1559         st_map_sentries(cached_sentry_ptr, local_sentry_ptr);
1560         sentry->flags |= string_flags;
1561         if (*cached_sentry_ptr && *local_sentry_ptr) {
1562             /* Found by name. */
1563             return;
1564         }
1565     }
1566     if (!match_by_content) {
1567         /* No match. */
1568         return;
1569     }
1570     if (cached_sentry) {
1571         EXEC_WITH_MAGIC_VARS(
1572             local_sentry = magic_sentry_lookup_by_string(st_lookup_str_local_data(cached_sentry));
1573             , st_local_magic_vars_ptr
1574         );
1575     }
1576     else {
1577         int i;
1578         for(i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
1579             sentry = &st_cached_magic_vars.sentries[i];
1580             if (MAGIC_SENTRY_IS_STRING(sentry) && !strcmp(st_lookup_str_local_data(sentry), (char*)local_sentry->address)) {
1581                 cached_sentry = sentry;
1582                 break;
1583             }
1584         }
1585     }
1586     *cached_sentry_ptr = cached_sentry;
1587     *local_sentry_ptr = local_sentry;
1588 }
1589 
1590 PUBLIC void st_map_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
1591 {
1592     struct _magic_sentry *cached_sentry = *cached_sentry_ptr;
1593     struct _magic_sentry *local_sentry = *local_sentry_ptr;
1594     struct _magic_dsentry *cached_dsentry = cached_sentry ? (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) ? MAGIC_DSENTRY_FROM_SENTRY(cached_sentry) : NULL) : NULL;
1595     struct _magic_dsentry *local_dsentry = local_sentry ? (MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) ? MAGIC_DSENTRY_FROM_SENTRY(local_sentry) : NULL) : NULL;
1596     ST_CHECK_INIT();
1597     assert((cached_sentry == NULL) ^ (local_sentry == NULL));
1598 
1599     if ((cached_sentry && MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING))
1600         || (local_sentry && MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_STRING))) {
1601             st_map_str_sentries(cached_sentry_ptr, local_sentry_ptr);
1602             return;
1603     }
1604     else if (cached_sentry) {
1605         EXEC_WITH_MAGIC_VARS(
1606             local_sentry = magic_sentry_lookup_by_name(cached_dsentry ? cached_dsentry->parent_name : "", cached_sentry->name, cached_dsentry ? cached_dsentry->site_id : 0, NULL);
1607             , st_local_magic_vars_ptr
1608         );
1609         assert(!local_sentry || MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC));
1610     }
1611     else {
1612         EXEC_WITH_MAGIC_VARS(
1613             cached_sentry = magic_sentry_lookup_by_name(local_dsentry ? local_dsentry->parent_name : "", local_sentry->name, local_dsentry ? local_dsentry->site_id : 0, NULL);
1614             , &st_cached_magic_vars
1615         );
1616         assert(!cached_sentry || MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC));
1617     }
1618     *cached_sentry_ptr = cached_sentry;
1619     *local_sentry_ptr = local_sentry;
1620 }
1621 
1622 PRIVATE struct _magic_sentry *st_lookup_cached_sentry(struct _magic_sentry *local_sentry)
1623 {
1624     int i;
1625     struct _magic_dsentry *cached_dsentry;
1626     assert(local_sentry);
1627 
1628     for (i = 0 ; i < st_counterparts.sentries_size ; i++) {
1629         if (st_counterparts.sentries[i].counterpart == local_sentry) {
1630             break;
1631         }
1632     }
1633     if (i >= st_counterparts.sentries_size) {
1634         return NULL;
1635     }
1636     if (i < st_cached_magic_vars.sentries_num) {
1637         return &st_cached_magic_vars.sentries[i];
1638     }
1639     i -= st_cached_magic_vars.sentries_num;
1640     cached_dsentry = st_cached_magic_vars.first_dsentry;
1641     assert(i >= 0);
1642     assert(cached_dsentry);
1643     while (i > 0) {
1644         cached_dsentry = cached_dsentry->next;
1645         assert(cached_dsentry);
1646         i--;
1647     }
1648     return MAGIC_DSENTRY_TO_SENTRY(cached_dsentry);
1649 }
1650 
1651 PUBLIC void st_lookup_sentry_pair(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
1652 {
1653     struct _magic_sentry *cached_sentry = *cached_sentry_ptr;
1654     struct _magic_sentry *local_sentry = *local_sentry_ptr;
1655     ST_CHECK_INIT();
1656     assert((cached_sentry == NULL) ^ (local_sentry == NULL));
1657 
1658     if (cached_sentry) {
1659         ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
1660     }
1661     else if (MAGIC_SENTRY_IS_STRING(local_sentry)) {
1662         /* strings are special, they may have multiple local duplicates */
1663         struct _magic_sentry *csentry = NULL, *lsentry = NULL;
1664         st_map_str_sentries(&csentry, &local_sentry);
1665         if (csentry) {
1666             st_lookup_sentry_pair(&csentry, &lsentry);
1667             if (lsentry) {
1668                 cached_sentry = csentry;
1669             }
1670         }
1671     }
1672     else {
1673         cached_sentry = st_lookup_cached_sentry(local_sentry);
1674     }
1675     *cached_sentry_ptr = cached_sentry;
1676     *local_sentry_ptr = local_sentry;
1677 }
1678 
1679 PRIVATE INLINE void st_unpair_local_alloc_sentry(struct _magic_sentry *local_sentry)
1680 {
1681     if (st_policies & ST_ON_ALLOC_UNPAIR_ERROR) {
1682         st_cbs_os.panic("st_unpair_local_alloc_sentry: Error: attempting to unpair a local alloc sentry!");
1683     }
1684     else if (st_policies & ST_ON_ALLOC_UNPAIR_DEALLOCATE) {
1685         deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry));
1686     }
1687 }
1688 
1689 PUBLIC void st_add_sentry_pair(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry)
1690 {
1691     ST_CHECK_INIT();
1692     assert(cached_sentry || local_sentry);
1693 
1694     if (local_sentry) {
1695         struct _magic_sentry *csentry = NULL;
1696         st_lookup_sentry_pair(&csentry, &local_sentry);
1697         if (csentry) {
1698             ST_SET_CACHED_COUNTERPART(csentry, sentries, sentries, NULL);
1699         }
1700         if (!cached_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
1701             st_unpair_local_alloc_sentry(local_sentry);
1702         }
1703     }
1704     if (cached_sentry) {
1705         struct _magic_sentry *lsentry = NULL;
1706         st_lookup_sentry_pair(&cached_sentry, &lsentry);
1707         if (lsentry && MAGIC_SENTRY_IS_ALLOC(lsentry)) {
1708             st_unpair_local_alloc_sentry(lsentry);
1709         }
1710         ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
1711     }
1712 }
1713 
1714 PUBLIC int st_add_sentry_pair_alloc_by_dsindex(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_dsindex *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags)
1715 {
1716     int r;
1717     struct _magic_dsentry *local_dsentry;
1718     ST_CHECK_INIT();
1719     assert(cached_sentry);
1720 
1721     if (!local_dsindex) {
1722         st_add_sentry_pair(cached_sentry, NULL);
1723         return OK;
1724     }
1725 
1726     r = allocate_local_dsentry(info, local_dsindex, num_elements, MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_TYPE_SIZE_MISMATCH), p_alloc_flags, &local_dsentry, NULL, MAGIC_PTR_TO_DSENTRY(cached_sentry->address));
1727     if (r != OK) {
1728         return r;
1729     }
1730     st_add_sentry_pair(cached_sentry, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
1731     return OK;
1732 }
1733 
1734 PUBLIC void st_map_functions(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr)
1735 {
1736     struct _magic_function *cached_function = *cached_function_ptr;
1737     struct _magic_function *local_function = *local_function_ptr;
1738     ST_CHECK_INIT();
1739     assert((cached_function == NULL) ^ (local_function == NULL));
1740 
1741     if (cached_function) {
1742         EXEC_WITH_MAGIC_VARS(
1743             local_function = magic_function_lookup_by_name(NULL, cached_function->name);
1744             , st_local_magic_vars_ptr
1745         );
1746     }
1747     else {
1748         EXEC_WITH_MAGIC_VARS(
1749             cached_function = magic_function_lookup_by_name(NULL, local_function->name);
1750             , &st_cached_magic_vars
1751         );
1752     }
1753     *cached_function_ptr = cached_function;
1754     *local_function_ptr = local_function;
1755 }
1756 
1757 PUBLIC void st_lookup_function_pair(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr)
1758 {
1759     struct _magic_function *cached_function = *cached_function_ptr;
1760     struct _magic_function *local_function = *local_function_ptr;
1761     int i;
1762     ST_CHECK_INIT();
1763     assert((cached_function == NULL) ^ (local_function == NULL));
1764 
1765     if (cached_function) {
1766         if ((int)cached_function->id - 1 >= st_counterparts.functions_size) {
1767             /*
1768              * Try to check if this is a function
1769              * from an external shared object.
1770              * XXX: The number of dfunctions can be quite large,
1771              * so this needs to be done more efficiently.
1772              */
1773             struct _magic_dfunction *dfunc;
1774             struct _magic_function *func;
1775             MAGIC_DFUNCTION_FUNC_ITER(_magic_vars->first_dfunction, dfunc, func,
1776                 if (func->address == cached_function->address) {
1777                     local_function = func;
1778                     break;
1779                 }
1780             );
1781             assert(local_function != NULL && "No counterpart found for function.");
1782         } else {
1783             ST_GET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
1784         }
1785     }
1786     else {
1787         assert(st_counterparts.functions_size == st_cached_magic_vars.functions_num);
1788         for(i = 0 ; i < st_counterparts.functions_size ; i++) {
1789             if(st_counterparts.functions[i].counterpart == local_function) {
1790                 cached_function = &st_cached_magic_vars.functions[i];
1791                 break;
1792             }
1793         }
1794     }
1795     *cached_function_ptr = cached_function;
1796     *local_function_ptr = local_function;
1797 }
1798 
1799 PUBLIC void st_add_function_pair(struct _magic_function *cached_function, struct _magic_function *local_function)
1800 {
1801     ST_CHECK_INIT();
1802     assert(cached_function || local_function);
1803 
1804     if (local_function) {
1805         struct _magic_function *cfunction = NULL;
1806         st_lookup_function_pair(&cfunction, &local_function);
1807         if (cfunction) {
1808             ST_SET_CACHED_COUNTERPART(cfunction, functions, functions, NULL);
1809         }
1810     }
1811     if (cached_function) {
1812         ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
1813     }
1814 }
1815 
1816 PUBLIC int st_sentry_equals(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry)
1817 {
1818     const char *cached_parent_name = "", *local_parent_name = "";
1819     int cached_flags = MAGIC_STATE_FLAGS_TO_NONEXTF(cached_sentry->flags) & (~MAGIC_STATE_ADDR_NOT_TAKEN);
1820     int local_flags = MAGIC_STATE_FLAGS_TO_NONEXTF(local_sentry->flags) & (~MAGIC_STATE_ADDR_NOT_TAKEN);
1821     if (cached_flags != local_flags) {
1822         return FALSE;
1823     }
1824     if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING)) {
1825         return !strcmp(st_lookup_str_local_data(cached_sentry), (char*)local_sentry->address);
1826     }
1827     if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
1828         cached_parent_name = MAGIC_DSENTRY_FROM_SENTRY(cached_sentry)->parent_name;
1829         local_parent_name = MAGIC_DSENTRY_FROM_SENTRY(local_sentry)->parent_name;
1830     }
1831     if (strcmp(cached_sentry->name, local_sentry->name) || strcmp(cached_parent_name, local_parent_name)) {
1832         return FALSE;
1833     }
1834     return magic_type_compatible(cached_sentry->type, local_sentry->type, MAGIC_TYPE_COMPARE_ALL);
1835 }
1836 
1837 PUBLIC int st_function_equals(struct _magic_function *cached_function, struct _magic_function *local_function)
1838 {
1839     if (MAGIC_STATE_FLAGS_TO_NONEXTF(local_function->flags) != MAGIC_STATE_FLAGS_TO_NONEXTF(cached_function->flags)) {
1840         return FALSE;
1841     }
1842     return !strcmp(cached_function->name, local_function->name);
1843 }
1844 
1845 PUBLIC void st_print_sentry_diff(st_init_info_t *info, struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry, int raw_diff, int print_changed)
1846 {
1847     int is_paired_sentry;
1848     ST_CHECK_INIT();
1849 
1850     if (!cached_sentry || !local_sentry) {
1851         if (raw_diff) {
1852             st_map_sentries(&cached_sentry, &local_sentry);
1853         }
1854         else {
1855             st_lookup_sentry_pair(&cached_sentry, &local_sentry);
1856         }
1857     }
1858     is_paired_sentry = (cached_sentry != NULL && local_sentry != NULL);
1859     if (is_paired_sentry && st_sentry_equals(cached_sentry, local_sentry)) {
1860         return;
1861     }
1862     if (is_paired_sentry && !print_changed) {
1863         return;
1864     }
1865     if (cached_sentry) {
1866         printf("-"); ST_SENTRY_PRINT(cached_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n");
1867     }
1868     if (local_sentry) {
1869         printf("+"); ST_SENTRY_PRINT(local_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n");
1870     }
1871     printf("\n");
1872 }
1873 
1874 PUBLIC void st_print_function_diff(st_init_info_t *info, struct _magic_function *cached_function, struct _magic_function *local_function, int raw_diff, int print_changed)
1875 {
1876     int is_paired_function;
1877     ST_CHECK_INIT();
1878 
1879     if (!cached_function || !local_function) {
1880         if (raw_diff) {
1881             st_map_functions(&cached_function, &local_function);
1882         }
1883         else {
1884             st_lookup_function_pair(&cached_function, &local_function);
1885         }
1886     }
1887     is_paired_function = (cached_function != NULL && local_function != NULL);
1888     if (is_paired_function && st_function_equals(cached_function, local_function)) {
1889         return;
1890     }
1891     if (is_paired_function && !print_changed) {
1892         return;
1893     }
1894     if (cached_function) {
1895         printf("-"); ST_FUNCTION_PRINT(cached_function, MAGIC_EXPAND_TYPE_STR); printf("\n");
1896     }
1897     if (local_function) {
1898         printf("+"); ST_FUNCTION_PRINT(local_function, MAGIC_EXPAND_TYPE_STR); printf("\n");
1899     }
1900     printf("\n");
1901 }
1902 
1903 PUBLIC void st_print_sentries_diff(st_init_info_t *info, int raw_diff, int print_changed)
1904 {
1905     int i;
1906     ST_CHECK_INIT();
1907 
1908     for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
1909         struct _magic_sentry *cached_sentry = &st_cached_magic_vars.sentries[i];
1910         st_print_sentry_diff(info, cached_sentry, NULL, raw_diff, print_changed);
1911     }
1912 
1913     print_changed = FALSE;
1914     for (i = 0 ; i < st_local_magic_vars_ptr->sentries_num ; i++) {
1915         struct _magic_sentry *local_sentry = &st_local_magic_vars_ptr->sentries[i];
1916         st_print_sentry_diff(info, NULL, local_sentry, raw_diff, print_changed);
1917     }
1918 }
1919 
1920 PUBLIC void st_print_dsentries_diff(st_init_info_t *info, int raw_diff, int print_changed)
1921 {
1922     struct _magic_dsentry *dsentry;
1923     ST_CHECK_INIT();
1924 
1925     dsentry = st_cached_magic_vars.first_dsentry;
1926     while (dsentry != NULL) {
1927         struct _magic_sentry *cached_sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
1928         st_print_sentry_diff(info, cached_sentry, NULL, raw_diff, print_changed);
1929         dsentry = dsentry->next;
1930     }
1931 
1932     dsentry = st_local_magic_vars_ptr->first_dsentry;
1933     print_changed = FALSE;
1934     while (dsentry != NULL) {
1935         struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
1936         st_print_sentry_diff(info, NULL, local_sentry, raw_diff, print_changed);
1937         dsentry = dsentry->next;
1938     }
1939 }
1940 
1941 PUBLIC void st_print_functions_diff(st_init_info_t *info, int raw_diff, int print_changed)
1942 {
1943     int i;
1944     ST_CHECK_INIT();
1945 
1946     for(i = 0 ; i < st_cached_magic_vars.functions_num ; i++) {
1947         struct _magic_function *cached_function = &st_cached_magic_vars.functions[i];
1948         st_print_function_diff(info, cached_function, NULL, raw_diff, print_changed);
1949     }
1950 
1951     print_changed = FALSE;
1952     for (i = 0 ; i < st_local_magic_vars_ptr->functions_num ; i++) {
1953         struct _magic_function *local_function = &st_local_magic_vars_ptr->functions[i];
1954         st_print_function_diff(info, NULL, local_function, raw_diff, print_changed);
1955     }
1956 }
1957 
1958 PUBLIC void st_print_state_diff(st_init_info_t *info, int raw_diff, int print_changed)
1959 {
1960     ST_CHECK_INIT();
1961 
1962     printf("Index: sentries\n");
1963     printf("===================================================================\n");
1964     st_print_sentries_diff(info, raw_diff, print_changed);
1965 
1966     printf("\nIndex: dsentries\n");
1967     printf("===================================================================\n");
1968     st_print_dsentries_diff(info, raw_diff, print_changed);
1969 
1970     printf("\nIndex: functions\n");
1971     printf("===================================================================\n");
1972     st_print_functions_diff(info, raw_diff, print_changed);
1973     printf("\n");
1974 }
1975 
1976 PUBLIC int st_data_transfer(st_init_info_t *info)
1977 {
1978     struct _magic_dsentry *dsentry;
1979     int i, r;
1980     int sentry_transferred;
1981 #if ST_DEBUG_DATA_TRANSFER
1982     int counter = 1;
1983 #endif
1984     ST_CHECK_INIT();
1985 
1986     /* Check unpaired sentries. */
1987     for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
1988         struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i];
1989         int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
1990         if (!is_paired_sentry) {
1991             r = check_unpaired_sentry(info, sentry);
1992             if (r != OK) {
1993                 return r;
1994             }
1995         }
1996     }
1997 
1998     /* Check unpaired dsentries. */
1999     dsentry = st_cached_magic_vars.first_dsentry;
2000     while (dsentry != NULL) {
2001         struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
2002         int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
2003         if (!is_paired_sentry) {
2004             r = check_unpaired_sentry(info, sentry);
2005             if (r != OK) {
2006                 return r;
2007             }
2008         }
2009         dsentry = dsentry->next;
2010     }
2011 
2012     /* Data transfer. */
2013     do {
2014         sentry_transferred = 0;
2015 
2016 #if ST_DEBUG_DATA_TRANSFER
2017         printf("st_data_transfer: Round %d\n", counter++);
2018         st_print_sentities(&st_cached_magic_vars);
2019 #endif
2020 
2021         /* process sentries */
2022 #if ST_DEBUG_LEVEL > 0
2023         printf("st_data_transfer: processing sentries\n");
2024 #endif
2025         for(i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
2026             struct _magic_sentry *sentry = &st_cached_magic_vars.sentries[i];
2027             int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
2028             int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
2029             if (sentry_needs_transfer && is_paired_sentry) {
2030                 r = transfer_data_sentry(info, sentry);
2031                 if (r != OK) {
2032                     return r;
2033                 }
2034                 sentry_transferred = 1;
2035             }
2036         }
2037 
2038         /* process dsentries */
2039 #if ST_DEBUG_LEVEL > 0
2040         printf("st_data_transfer: processing dsentries\n");
2041 #endif
2042         dsentry = st_cached_magic_vars.first_dsentry;
2043         while (dsentry != NULL) {
2044             struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
2045             int is_paired_sentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
2046             int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
2047             if (sentry_needs_transfer && is_paired_sentry) {
2048                 r = transfer_data_sentry(info, sentry);
2049                 if (r != OK) {
2050                     return r;
2051                 }
2052                 sentry_transferred = 1;
2053             }
2054             dsentry = dsentry->next;
2055         }
2056 
2057     } while(sentry_transferred);
2058 
2059     return OK;
2060 }
2061 
2062 PRIVATE INLINE void st_set_transfer_status(int status_flags, int status_op,
2063     struct _magic_sentry *cached_sentry, struct _magic_function *cached_function)
2064 {
2065 #define __st_set_transfer_status(X)                         \
2066     switch(status_op) {                                     \
2067         case ST_OP_NONE:                                    \
2068             return;                                         \
2069         break;                                              \
2070         case ST_OP_ADD:                                     \
2071             MAGIC_STATE_EXTF_ADD(X, status_flags);          \
2072         break;                                              \
2073         case ST_OP_DEL:                                     \
2074             MAGIC_STATE_EXTF_DEL(X, status_flags);          \
2075         break;                                              \
2076         case ST_OP_SET:                                     \
2077             MAGIC_STATE_EXTF_SET(X, status_flags);          \
2078         break;                                              \
2079         case ST_OP_CLEAR:                                   \
2080             MAGIC_STATE_EXTF_CLEAR(X);                      \
2081         break;                                              \
2082         default:                                            \
2083             st_cbs_os.panic("Invalid operation!");          \
2084         break;                                              \
2085     }                                                       \
2086 
2087     if (cached_sentry) {
2088         __st_set_transfer_status(cached_sentry);
2089     }
2090     else {
2091         assert(cached_function);
2092         __st_set_transfer_status(cached_function);
2093     }
2094 }
2095 
2096 PUBLIC void st_set_unpaired_types_ratios(float unpaired_types_ratio,
2097     float unpaired_struct_types_ratio)
2098 {
2099     st_unpaired_types_ratio = unpaired_types_ratio;
2100     st_unpaired_struct_types_ratio = unpaired_struct_types_ratio;
2101 }
2102 
2103 PUBLIC void st_set_status_defaults(st_init_info_t *info)
2104 {
2105     int match_all = ~0, skip_none = 0;
2106     int skip_state_flags = (st_policies & ST_DEFAULT_SKIP_STACK) ? MAGIC_STATE_STACK : 0;
2107 
2108     if (!(st_policies & ST_DEFAULT_TRANSFER_NONE)) {
2109         /*
2110          * Transfer all the (d)sentries by default. Skip stack dsentries when
2111          * requested. In that case, stack dsentries won't be transferred and an
2112          * error will be raised on stack pointer transfer.
2113          */
2114         st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET,
2115             match_all, skip_state_flags);
2116         if (st_policies & ST_DEFAULT_ALLOC_CASCADE_XFER) {
2117             /*
2118              * If requested, mark non-stack dsentries for cascade transfer
2119              * instead of regular transfer.
2120              */
2121             st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET,
2122                 MAGIC_STATE_HEAP | MAGIC_STATE_MAP, skip_none);
2123         }
2124     }
2125     else {
2126         /*
2127          * Don't transfer any (d)sentries by default. Mark all the (d)sentries
2128          * for cascade transfer (except for stack dsentries when requested).
2129          */
2130         st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET,
2131             match_all, skip_state_flags);
2132     }
2133 
2134     /*
2135      * Always transfer all immutable objects.
2136      */
2137     st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET,
2138         MAGIC_STATE_IMMUTABLE, skip_none);
2139 
2140     /*
2141      * If requested, mark library state dsentries as already transferred too.
2142      */
2143     if (st_policies & ST_DEFAULT_SKIP_LIB_STATE) {
2144         st_set_status_by_state_flags(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
2145             ST_OP_ADD, MAGIC_STATE_LIB, skip_none);
2146     }
2147 
2148     /*
2149      * In addition, mark functions, out-of-band/string sentries
2150      * and shared dsentries as already transferred.
2151      */
2152     st_set_status_by_state_flags(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
2153         ST_OP_ADD, MAGIC_STATE_TEXT | MAGIC_STATE_OUT_OF_BAND |
2154         MAGIC_STATE_STRING | MAGIC_STATE_CONSTANT | MAGIC_STATE_SHM, skip_none);
2155 
2156     /*
2157      * Finally, if we only want to transfer dirty sentries, mark all the other ones
2158      * as already transferred.
2159      */
2160     if (st_policies & ST_TRANSFER_DIRTY_ONLY) {
2161         st_set_status_by_state_flags(ST_TRANSFER_DONE, ST_OP_ADD, match_all, MAGIC_STATE_DIRTY_PAGE);
2162     }
2163 
2164 #if DO_SKIP_ENVIRON_HACK
2165     st_set_status_by_name(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
2166         ST_OP_ADD, NULL, "__environ", MAGIC_DSENTRY_SITE_ID_NULL);
2167     st_set_status_by_name(ST_NEEDS_TRANSFER | ST_TRANSFER_DONE,
2168         ST_OP_ADD, NULL, "stderr", MAGIC_DSENTRY_SITE_ID_NULL);
2169 #endif
2170 }
2171 
2172 PUBLIC void st_set_status_by_state_flags(int status_flags, int status_op,
2173     int match_state_flags, int skip_state_flags)
2174 {
2175     struct _magic_dsentry *dsentry = st_cached_magic_vars.first_dsentry;
2176     int i;
2177     int candidate_sentry_flags = MAGIC_STATE_DATA | MAGIC_STATE_STRING | MAGIC_STATE_CONSTANT | MAGIC_STATE_ADDR_NOT_TAKEN;
2178     int candidate_function_flags = MAGIC_STATE_TEXT;
2179     int candidate_dsentry_flags = ~(candidate_sentry_flags | candidate_function_flags);
2180     ST_CHECK_INIT();
2181 
2182     /* process sentries */
2183     if (match_state_flags & candidate_sentry_flags) {
2184         for (i = 0 ; i < st_cached_magic_vars.sentries_num ; i++) {
2185             int state_flags = st_cached_magic_vars.sentries[i].flags;
2186             if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) {
2187                 st_set_transfer_status(status_flags, status_op, &st_cached_magic_vars.sentries[i], NULL);
2188             }
2189         }
2190     }
2191 
2192     /* process dsentries */
2193     if (match_state_flags & candidate_dsentry_flags) {
2194         while (dsentry != NULL) {
2195             int state_flags = dsentry->sentry.flags;
2196             if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) {
2197                 st_set_transfer_status(status_flags, status_op, MAGIC_DSENTRY_TO_SENTRY(dsentry), NULL);
2198             }
2199             dsentry = dsentry->next;
2200         }
2201     }
2202 
2203     /* process functions */
2204     if (match_state_flags & candidate_function_flags) {
2205         for (i = 0 ; i < st_cached_magic_vars.functions_num ; i++) {
2206             int state_flags = st_cached_magic_vars.functions[i].flags;
2207             if ((state_flags & match_state_flags) && !(state_flags & skip_state_flags)) {
2208                 st_set_transfer_status(status_flags, status_op, NULL, &st_cached_magic_vars.functions[i]);
2209             }
2210         }
2211     }
2212 }
2213 
2214 PUBLIC int st_set_status_by_function_ids(int status_flags, int status_op, _magic_id_t *ids)
2215 {
2216     int r, i = 0;
2217     while (ids[i] != 0) {
2218         r = st_set_status_by_function_id(status_flags, status_op, ids[i]);
2219         if (r != OK) {
2220             return r;
2221         }
2222         i++;
2223     }
2224     return OK;
2225 }
2226 
2227 PUBLIC int st_set_status_by_sentry_ids(int status_flags, int status_op, _magic_id_t *ids)
2228 {
2229     int r, i=0;
2230     while (ids[i] != 0) {
2231         r = st_set_status_by_sentry_id(status_flags, status_op, ids[i]);
2232         if (r != OK) {
2233             return r;
2234         }
2235         i++;
2236     }
2237     return OK;
2238 }
2239 
2240 PUBLIC int st_set_status_by_names(int status_flags, int status_op,
2241     const char **parent_names, const char **names,
2242     _magic_id_t *dsentry_site_ids)
2243 {
2244     int r, i = 0;
2245     while (names[i] != NULL) {
2246         r = st_set_status_by_name(status_flags, status_op,
2247             parent_names ? parent_names[i] : NULL, names[i],
2248             dsentry_site_ids ? dsentry_site_ids[i] :
2249                 MAGIC_DSENTRY_SITE_ID_NULL);
2250         if (r != OK) {
2251             return r;
2252         }
2253         i++;
2254     }
2255     return OK;
2256 }
2257 
2258 PUBLIC int st_set_status_by_local_addrs(int status_flags, int status_op,
2259     void **addrs)
2260 {
2261     int r, i=0;
2262     while (addrs[i] != NULL) {
2263         r = st_set_status_by_local_addr(status_flags, status_op, addrs[i]);
2264         if (r != OK) {
2265             return r;
2266         }
2267         i++;
2268     }
2269     return OK;
2270 }
2271 
2272 PUBLIC void st_set_status_by_sentry(int status_flags, int status_op,
2273     void *cached_sentry)
2274 {
2275     ST_CHECK_INIT();
2276 
2277     st_set_transfer_status(status_flags, status_op,
2278         (struct _magic_sentry*) cached_sentry, NULL);
2279 }
2280 
2281 PUBLIC void st_set_status_by_function(int status_flags, int status_op,
2282     void *cached_function)
2283 {
2284     ST_CHECK_INIT();
2285 
2286     st_set_transfer_status(status_flags, status_op,
2287         NULL, (struct _magic_function*) cached_function);
2288 }
2289 
2290 PUBLIC int st_set_status_by_name(int status_flags, int status_op,
2291     const char *parent_name, const char *name, _magic_id_t dsentry_site_id)
2292 {
2293     struct _magic_sentry *cached_sentry = NULL;
2294     struct _magic_function *cached_function = NULL;
2295     ST_CHECK_INIT();
2296 
2297     EXEC_WITH_MAGIC_VARS(
2298         cached_sentry = magic_sentry_lookup_by_name(parent_name ? parent_name : "", name, dsentry_site_id, NULL);
2299         if (!cached_sentry) {
2300             cached_function = magic_function_lookup_by_name(parent_name, name);
2301         }
2302         , &st_cached_magic_vars
2303     );
2304     if (!cached_sentry && !cached_function) {
2305         return ENOENT;
2306     }
2307     st_set_transfer_status(status_flags, status_op, cached_sentry, cached_function);
2308     if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
2309         struct _magic_dsentry *prev_dsentry, *dsentry, *next_dsentry = MAGIC_DSENTRY_NEXT(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry));
2310         struct _magic_sentry* sentry;
2311         /*
2312          * Alloc sentries may have multiple instances with the same name.
2313          * Use the site_id to distinguish between them.
2314          */
2315         assert(parent_name && name);
2316         MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(next_dsentry, prev_dsentry, dsentry, sentry,
2317             parent_name, name, dsentry_site_id,
2318             st_set_transfer_status(status_flags, status_op, sentry, NULL);
2319         );
2320     }
2321     return OK;
2322 }
2323 
2324 PUBLIC int st_set_status_by_function_id(int status_flags, int status_op,
2325     _magic_id_t id)
2326 {
2327     struct _magic_function *cached_function = NULL;
2328     ST_CHECK_INIT();
2329 
2330     EXEC_WITH_MAGIC_VARS(
2331         cached_function = magic_function_lookup_by_id(id, NULL);
2332         , &st_cached_magic_vars
2333     );
2334 
2335     if (!cached_function) {
2336         return ENOENT;
2337     }
2338 
2339     st_set_transfer_status(status_flags, status_op, NULL, cached_function);
2340     return OK;
2341 }
2342 
2343 PUBLIC int st_set_status_by_sentry_id(int status_flags, int status_op,
2344     _magic_id_t id)
2345 {
2346     struct _magic_sentry *cached_sentry = NULL;
2347     ST_CHECK_INIT();
2348 
2349     EXEC_WITH_MAGIC_VARS(
2350         cached_sentry = magic_sentry_lookup_by_id(id, NULL);
2351         , &st_cached_magic_vars
2352     );
2353 
2354     if (!cached_sentry) {
2355         return ENOENT;
2356     }
2357 
2358     st_set_transfer_status(status_flags, status_op, cached_sentry, NULL);
2359     return OK;
2360 }
2361 
2362 PUBLIC int st_set_status_by_local_addr(int status_flags, int status_op,
2363     void *addr)
2364 {
2365     const char *parent_name, *name;
2366     _magic_id_t dsentry_site_id = MAGIC_DSENTRY_SITE_ID_NULL;
2367     struct _magic_sentry *sentry = NULL;
2368     struct _magic_function *function = NULL;
2369     ST_CHECK_INIT();
2370 
2371     sentry = magic_sentry_lookup_by_addr(addr, NULL);
2372     if (!sentry) {
2373         function = magic_function_lookup_by_addr(addr, NULL);
2374     }
2375     if (sentry && !MAGIC_STATE_FLAG(sentry, MAGIC_STATE_DYNAMIC)) {
2376         name = sentry->name;
2377         parent_name = MAGIC_SENTRY_PARENT(sentry);
2378         dsentry_site_id = MAGIC_SENTRY_SITE_ID(sentry);
2379     }
2380     else if (function && !MAGIC_STATE_FLAG(function, MAGIC_STATE_DYNAMIC)) {
2381        name = function->name;
2382        parent_name = MAGIC_FUNCTION_PARENT(function);
2383     }
2384     else {
2385         return ENOENT;
2386     }
2387     st_set_status_by_name(status_flags, status_op, parent_name, name, dsentry_site_id);
2388     return OK;
2389 }
2390 
2391 PUBLIC int st_pair_by_function_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op)
2392 {
2393     int r, i=0;
2394     ST_CHECK_INIT();
2395 
2396     while (cached_ids[i] != 0) {
2397         assert(local_ids[i] != 0);
2398         r = st_pair_by_function_id(cached_ids[i], local_ids[i], status_flags, status_op);
2399         if (r != OK) {
2400             return r;
2401         }
2402         i++;
2403     }
2404     return OK;
2405 }
2406 
2407 PUBLIC int st_pair_by_sentry_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op)
2408 {
2409     int r, i=0;
2410     ST_CHECK_INIT();
2411 
2412     while (cached_ids[i] != 0) {
2413         assert(local_ids[i] != 0);
2414         r = st_pair_by_sentry_id(cached_ids[i], local_ids[i], status_flags, status_op);
2415         if (r != OK) {
2416             return r;
2417         }
2418         i++;
2419     }
2420     return OK;
2421 }
2422 
2423 PUBLIC int st_pair_by_names(char **cached_parent_names, char **cached_names,
2424     char **local_parent_names, char **local_names, _magic_id_t *dsentry_site_ids,
2425     int status_flags, int status_op)
2426 {
2427     int r, i=0;
2428     while (cached_names[i] != NULL) {
2429         assert(local_names[i]);
2430         r = st_pair_by_name(cached_parent_names ? cached_parent_names[i] : NULL, cached_names[i],
2431             local_parent_names ? local_parent_names[i] : NULL, local_names[i],
2432             dsentry_site_ids ? dsentry_site_ids[i] : MAGIC_DSENTRY_SITE_ID_NULL,
2433             status_flags, status_op);
2434         if (r != OK) {
2435             return r;
2436         }
2437         i++;
2438     }
2439     return OK;
2440 }
2441 
2442 PUBLIC void st_pair_by_sentry(void *cached_sentry, void *local_sentry, int status_flags, int status_op)
2443 {
2444     ST_CHECK_INIT();
2445 
2446     st_add_sentry_pair(cached_sentry, local_sentry);
2447     if (cached_sentry) {
2448         st_set_status_by_sentry(status_flags, status_op, cached_sentry);
2449     }
2450 }
2451 
2452 PUBLIC void st_pair_by_function(void *cached_function, void* local_function, int status_flags, int status_op)
2453 {
2454     ST_CHECK_INIT();
2455 
2456     st_add_function_pair(cached_function, local_function);
2457     if (cached_function) {
2458         st_set_status_by_function(status_flags, status_op, cached_function);
2459     }
2460 }
2461 
2462 PUBLIC int st_pair_alloc_by_dsindex(st_init_info_t *info, void *cached_sentry, void *local_dsindex, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op)
2463 {
2464     int r;
2465     ST_CHECK_INIT();
2466 
2467     r = st_add_sentry_pair_alloc_by_dsindex(info, cached_sentry, local_dsindex, num_elements, p_alloc_flags);
2468     if (r != OK) {
2469         return r;
2470     }
2471     if (cached_sentry) {
2472         st_set_status_by_sentry(status_flags, status_op, cached_sentry);
2473     }
2474     return OK;
2475 }
2476 
2477 PUBLIC int st_pair_by_function_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op)
2478 {
2479     struct _magic_function *cached_function = NULL, *local_function = NULL;
2480     ST_CHECK_INIT();
2481     assert(cached_id || local_id);
2482 
2483     if (cached_id) {
2484         EXEC_WITH_MAGIC_VARS(
2485             cached_function = magic_function_lookup_by_id(cached_id, NULL);
2486             , &st_cached_magic_vars
2487         );
2488         if (!cached_function) {
2489             return ENOENT;
2490         }
2491     }
2492     if (local_id) {
2493         EXEC_WITH_MAGIC_VARS(
2494             local_function = magic_function_lookup_by_id(local_id, NULL);
2495             , st_local_magic_vars_ptr
2496         );
2497         if (!local_function) {
2498             return ENOENT;
2499         }
2500     }
2501 
2502     st_pair_by_function(cached_function, local_function, status_flags, status_op);
2503     return OK;
2504 }
2505 
2506 PUBLIC int st_pair_by_sentry_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op)
2507 {
2508     struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
2509     ST_CHECK_INIT();
2510     assert(cached_id || local_id);
2511 
2512     if (cached_id) {
2513         EXEC_WITH_MAGIC_VARS(
2514             cached_sentry = magic_sentry_lookup_by_id(cached_id, NULL);
2515             , &st_cached_magic_vars
2516         );
2517         if (!cached_sentry) {
2518             return ENOENT;
2519         }
2520     }
2521     if (local_id) {
2522         EXEC_WITH_MAGIC_VARS(
2523             local_sentry = magic_sentry_lookup_by_id(local_id, NULL);
2524             , st_local_magic_vars_ptr
2525         );
2526         if (!local_sentry) {
2527             return ENOENT;
2528         }
2529     }
2530 
2531     st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
2532     return OK;
2533 }
2534 
2535 PUBLIC int st_pair_by_name(char *cached_parent_name, char *cached_name,
2536     char *local_parent_name, char *local_name, _magic_id_t dsentry_site_id,
2537     int status_flags, int status_op)
2538 {
2539     struct _magic_function *cached_function = NULL, *local_function = NULL;
2540     struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
2541     ST_CHECK_INIT();
2542     assert(cached_name || local_name);
2543 
2544     if (cached_name) {
2545         EXEC_WITH_MAGIC_VARS(
2546             cached_sentry = magic_sentry_lookup_by_name(cached_parent_name ? cached_parent_name : "", cached_name, dsentry_site_id, NULL);
2547             if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
2548                 return EINVAL;
2549             }
2550             if (!cached_sentry) {
2551                 cached_function = magic_function_lookup_by_name(NULL, cached_name);
2552             }
2553             , &st_cached_magic_vars
2554         );
2555         if (!cached_sentry && !cached_function) {
2556             return ENOENT;
2557         }
2558     }
2559     if (local_name) {
2560         EXEC_WITH_MAGIC_VARS(
2561             if (!cached_function) {
2562                 local_sentry = magic_sentry_lookup_by_name(local_parent_name ? local_parent_name : "", local_name, dsentry_site_id, NULL);
2563                 if (local_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
2564                     return EINVAL;
2565                 }
2566             }
2567             if (!cached_sentry && !local_sentry) {
2568                 local_function = magic_function_lookup_by_name(NULL, local_name);
2569             }
2570             , st_local_magic_vars_ptr
2571         );
2572         if (!local_sentry && !local_function) {
2573             return ENOENT;
2574         }
2575     }
2576     if (cached_function || local_function) {
2577         assert(!cached_sentry && !local_sentry);
2578         st_pair_by_function(cached_function, local_function, status_flags, status_op);
2579         return OK;
2580     }
2581     assert(cached_sentry || local_sentry);
2582     st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
2583     return OK;
2584 }
2585 
2586 PUBLIC int st_pair_by_alloc_name_policies(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int alloc_policies, int status_flags, int status_op)
2587 {
2588     int r, saved_policies = st_policies;
2589     st_policies &= ~(ST_ON_ALLOC_UNPAIR_MASK);
2590     st_policies |= (alloc_policies & ST_ON_ALLOC_UNPAIR_MASK);
2591     r = st_pair_by_alloc_name(info, cached_parent_name, cached_name, cached_dsentry_site_id, local_parent_name, local_name, local_dsentry_site_id, num_elements, p_alloc_flags, status_flags, status_op);
2592     st_policies = saved_policies;
2593     return r;
2594 }
2595 
2596 PUBLIC int st_pair_by_alloc_name(st_init_info_t *info, char *cached_parent_name, char *cached_name, _magic_id_t cached_dsentry_site_id, char *local_parent_name, char *local_name, _magic_id_t local_dsentry_site_id, int num_elements, const union __alloc_flags *p_alloc_flags, int status_flags, int status_op)
2597 {
2598     struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
2599     struct _magic_dsindex *local_dsindex = NULL;
2600     struct _magic_dsentry *prev_dsentry, *dsentry, *head_dsentry;
2601     struct _magic_sentry* sentry;
2602     int r;
2603     int is_cached_alloc = FALSE, is_local_alloc = FALSE;
2604     ST_CHECK_INIT();
2605     assert(cached_name || local_name);
2606     assert(!((cached_name == NULL) ^ (cached_parent_name == NULL)));
2607     assert(!((local_name == NULL) ^ (local_parent_name == NULL)));
2608 
2609     if (cached_name) {
2610         EXEC_WITH_MAGIC_VARS(
2611             cached_sentry = magic_sentry_lookup_by_name(cached_parent_name,
2612                 cached_name, cached_dsentry_site_id, NULL);
2613             if (cached_sentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
2614                 is_cached_alloc = TRUE;
2615             }
2616             , &st_cached_magic_vars
2617         );
2618     }
2619     if (local_name) {
2620         EXEC_WITH_MAGIC_VARS(
2621             local_sentry = magic_sentry_lookup_by_name(local_parent_name,
2622                 local_name, local_dsentry_site_id, NULL);
2623             if (local_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
2624                 is_local_alloc = TRUE;
2625             }
2626             if (!local_sentry || is_local_alloc) {
2627                 local_dsindex = magic_dsindex_lookup_by_name(local_parent_name, local_name);
2628                 if (local_dsindex && !MAGIC_DSINDEX_IS_ALLOC(local_dsindex)) {
2629                     local_dsindex = NULL;
2630                 }
2631                 if (local_sentry) assert(local_dsindex);
2632                 is_local_alloc = is_local_alloc || local_dsindex != NULL;
2633             }
2634             , st_local_magic_vars_ptr
2635         );
2636     }
2637     if (!is_cached_alloc && !is_local_alloc) {
2638         if (cached_sentry || local_sentry) {
2639             st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
2640             return OK;
2641         }
2642         return ENOENT;
2643     }
2644     if (local_sentry) {
2645         if (!is_local_alloc) {
2646             /* Alloc sentries may have multiple instances with the same name. */
2647             assert(cached_sentry && is_cached_alloc);
2648             head_dsentry = MAGIC_DSENTRY_NEXT(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry));
2649             assert(cached_parent_name && cached_name);
2650             MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, sentry, cached_parent_name, cached_name, cached_dsentry_site_id,
2651                 /* Cannot map multiple cached alloc sentries to a single local non-alloc sentry. */
2652                 return E2BIG;
2653             );
2654             /* Map a single cached alloc sentry to a single local non-alloc sentry. */
2655             st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
2656             return OK;
2657         }
2658         else {
2659             /* Unpair all the local alloc sentries. */
2660             head_dsentry = MAGIC_DSENTRY_FROM_SENTRY(local_sentry);
2661             assert(local_parent_name && local_name);
2662             MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry, sentry, local_parent_name, local_name, local_dsentry_site_id,
2663                 st_pair_by_sentry(NULL, sentry, status_flags, status_op);
2664             );
2665         }
2666     }
2667     if (!cached_sentry) {
2668         return OK;
2669     }
2670 
2671     /* Map a single cached non-alloc sentry to a local to-be-alloc sentry. */
2672     if (!is_cached_alloc) {
2673         assert(local_dsindex);
2674         return st_pair_alloc_by_dsindex(info, cached_sentry, local_dsindex, num_elements, p_alloc_flags, status_flags, status_op);
2675     }
2676 
2677     /* Map all the cached alloc sentries to the corresponding local to-be-alloc sentries (or NULL). */
2678     head_dsentry = MAGIC_DSENTRY_FROM_SENTRY(cached_sentry);
2679     assert(cached_parent_name && cached_name);
2680     MAGIC_DSENTRY_ALIVE_NAME_ID_ITER(head_dsentry, prev_dsentry, dsentry,
2681         sentry, cached_parent_name, cached_name, cached_dsentry_site_id,
2682         r = st_pair_alloc_by_dsindex(info, sentry, local_dsindex, num_elements, p_alloc_flags, status_flags, status_op);
2683         if (r != OK) {
2684             return r;
2685         }
2686     );
2687 
2688     return OK;
2689 }
2690 
2691 /* Metadata transfer and adjustment functions */
2692 
2693 PRIVATE int transfer_metadata_functions(st_init_info_t *info,
2694     struct _magic_vars_t *cached_magic_vars,
2695     struct _magic_vars_t *remote_magic_vars,
2696     st_counterparts_t *counterparts)
2697 {
2698 
2699     int i;
2700     struct _magic_function *cached_function;
2701 
2702     /* transfer magic_functions */
2703     MD_TRANSFER(info, remote_magic_vars->functions, (void **)&cached_magic_vars->functions, remote_magic_vars->functions_num * sizeof(struct _magic_function));
2704 
2705     /* adjust magic_functions */
2706     for (i = 0 ; i < cached_magic_vars->functions_num ; i++) {
2707         cached_function = &cached_magic_vars->functions[i];
2708         MD_TRANSFER_STR(info, &cached_function->name);
2709         cached_function->type = &cached_magic_vars->types[cached_function->type - remote_magic_vars->types];
2710     }
2711 
2712     return OK;
2713 }
2714 
2715 PRIVATE int transfer_metadata_dfunctions(st_init_info_t *info,
2716     struct _magic_vars_t *cached_magic_vars,
2717     struct _magic_vars_t *remote_magic_vars,
2718     st_counterparts_t *counterparts)
2719 {
2720 
2721     struct _magic_dfunction **dfunction_ptr;
2722     struct _magic_dfunction *cached_dfunction, *prev_dfunction = NULL;
2723     struct _magic_function *cached_function;
2724 
2725     /* Transfer dfunctions. */
2726     cached_magic_vars->first_dfunction = remote_magic_vars->first_dfunction;
2727     dfunction_ptr = &cached_magic_vars->first_dfunction;
2728     while (*dfunction_ptr != NULL) {
2729         MD_TRANSFER(info, *dfunction_ptr, (void **)dfunction_ptr, sizeof(struct _magic_dfunction));
2730         cached_dfunction = *dfunction_ptr;
2731 
2732         /* Adjust dfunction parent_name and next/prev links. */
2733         if (cached_dfunction->parent_name != NULL) {
2734             MD_TRANSFER_STR(info, &cached_dfunction->parent_name);
2735             if (strlen(cached_dfunction->parent_name) == 0) {
2736                 printf("ERROR. strlen(dfunction->parent_name) == 0.\n");
2737                 return EGENERIC;
2738             }
2739         } else {
2740             printf("ERROR. dfunction->parent_name == NULL.\n");
2741             return EGENERIC;
2742         }
2743 
2744         /* Adjust function name and type. */
2745         cached_function = &cached_dfunction->function;
2746         MD_TRANSFER_STR(info, &cached_function->name);
2747         cached_function->type = &cached_magic_vars->types[cached_function->type - remote_magic_vars->types];
2748 
2749         if (cached_dfunction->prev != NULL)
2750             cached_dfunction->prev = prev_dfunction;
2751 
2752         dfunction_ptr = &cached_dfunction->next;
2753         prev_dfunction = cached_dfunction;
2754     }
2755 
2756     cached_magic_vars->last_dfunction = prev_dfunction;
2757 
2758     return OK;
2759 }
2760 
2761 
2762 PUBLIC int st_transfer_metadata_types(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars
2763     , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts)
2764 {
2765 
2766     int i;
2767 
2768     /* transfer types */
2769     MD_TRANSFER(info, remote_magic_vars->types, (void **)&cached_magic_vars->types, remote_magic_vars->types_num * sizeof(struct _magic_type));
2770 
2771     /* type adjustments */
2772     for (i = 0 ; i < cached_magic_vars->types_num ; i++) {
2773         if (transfer_metadata_type_members(info, &cached_magic_vars->types[i], cached_magic_vars, remote_magic_vars)) {
2774             printf("ERROR transferring type members metadata.\n");
2775             return EGENERIC;
2776         }
2777         set_typename_key(&cached_magic_vars->types[i]);
2778     }
2779 
2780     return OK;
2781 }
2782 
2783 PRIVATE int transfer_metadata_type_value_set(st_init_info_t *info, struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, struct _magic_vars_t *remote_magic_vars)
2784 {
2785     int num_elements;
2786     /* MD_TRANSFER cannot be used, because it will allocate space for num_elements */
2787     if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) type->value_set, sizeof(int), (uint32_t) &num_elements)) {
2788         printf("ERROR transferring type value set metadata.\n");
2789         return EGENERIC;
2790     }
2791     num_elements++;
2792     MD_TRANSFER(info, type->value_set, (void **)&type->value_set, num_elements *sizeof(int));
2793     return OK;
2794 }
2795 
2796 PRIVATE int transfer_metadata_type_members(st_init_info_t *info, struct _magic_type *type, struct _magic_vars_t *cached_magic_vars, struct _magic_vars_t *remote_magic_vars)
2797 {
2798     int r;
2799     int num_child = MAGIC_TYPE_NUM_CONTAINED_TYPES(type), i;
2800 
2801     MD_TRANSFER_STR(info, &type->name);
2802     MD_TRANSFER_STR(info, &type->type_str);
2803 
2804     if (type->names != NULL && type->num_names > 0) {
2805         /* transfer array of name pointers */
2806         MD_TRANSFER(info, type->names, (void **)&type->names, type->num_names * sizeof(char *));
2807         for (i = 0 ; (unsigned int)i < type->num_names ; i++) {
2808             /* transfer individual name */
2809             MD_TRANSFER_STR(info, &type->names[i]);
2810         }
2811     }
2812 
2813 
2814 #define MD_TRANSFER_ADJUST_MEMBER_PTR(NUM_ELEMENTS,                            \
2815     ELEMENT_SIZE,PTR_ARRAY,INDEX)                                              \
2816     if((NUM_ELEMENTS) > 0 && (PTR_ARRAY) != NULL) {                            \
2817         MD_TRANSFER(info, PTR_ARRAY, (void **)&PTR_ARRAY,                      \
2818             NUM_ELEMENTS * ELEMENT_SIZE);                                      \
2819         for(INDEX = 0 ; (INDEX) < (NUM_ELEMENTS) ; INDEX++) {                  \
2820             PTR_ARRAY[INDEX] = ADJUST_POINTER(cached_magic_vars->types,        \
2821                 remote_magic_vars->types, PTR_ARRAY[INDEX]);                   \
2822         }                                                                      \
2823     }
2824 
2825     MD_TRANSFER_ADJUST_MEMBER_PTR(
2826         (type->type_id == MAGIC_TYPE_FUNCTION ? num_child + 1 : num_child),
2827         sizeof(struct _magic_type *), type->contained_types, i
2828     );
2829 
2830     if (type->compatible_types) {
2831         struct _magic_type *comp_types_element;
2832         int comp_types_size=0;
2833         /* determine size of array */
2834         do {
2835             if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) &type->compatible_types[comp_types_size]
2836                 , sizeof(struct _magic_type *), (uint32_t) &comp_types_element))
2837             {
2838                 printf("ERROR transferring compatible types array metadata.\n");
2839                 return EGENERIC;
2840             }
2841             comp_types_size++;
2842         } while(comp_types_element != NULL);
2843         /* We know the size, now transfer the whole array */
2844         MD_TRANSFER(info, type->compatible_types, (void **) &type->compatible_types, comp_types_size * sizeof(struct _magic_type *));
2845         for (i = 0; i < comp_types_size; i++) {
2846             if (type->compatible_types[i] != NULL) {
2847                 /* Adjust the pointer to point to the local counterpart */
2848                 type->compatible_types[i] = ADJUST_POINTER(cached_magic_vars->types,  remote_magic_vars->types, type->compatible_types[i]);
2849             }
2850         }
2851     }
2852 
2853     if (num_child>0 && type->member_names != NULL) {
2854         MD_TRANSFER(info, type->member_names, (void **)&type->member_names, num_child * sizeof(char *));
2855         for (i = 0 ; i < num_child ; i++) {
2856             MD_TRANSFER_STR(info, &type->member_names[i]);
2857         }
2858     }
2859 
2860     if (num_child>0 && type->member_offsets != NULL) {
2861         MD_TRANSFER(info, type->member_offsets, (void **)&type->member_offsets, num_child * sizeof(unsigned));
2862     }
2863 
2864     if (MAGIC_TYPE_HAS_VALUE_SET(type)) {
2865         r = transfer_metadata_type_value_set(info, type, cached_magic_vars, remote_magic_vars);
2866         if (r != OK) {
2867             return r;
2868         }
2869     }
2870     return OK;
2871 }
2872 
2873 PRIVATE int transfer_metadata_sentries(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars
2874     , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts
2875     , size_t *max_buff_sz)
2876 {
2877 
2878     int i;
2879     int skipped_sentries = 0;
2880     struct _magic_sentry *cached_sentry;
2881 
2882     /* transfer sentries */
2883     MD_TRANSFER(info, remote_magic_vars->sentries, (void **)&cached_magic_vars->sentries, remote_magic_vars->sentries_num * sizeof(struct _magic_sentry));
2884     /* todo: try to use only remote_magic_vars or cached magic_vars */
2885     /* todo: if transfer is complete, and argument 2 and 3 are always the same, remove 2nd argument */
2886 
2887     /* adjust sentries */
2888     for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) {
2889         cached_sentry = &cached_magic_vars->sentries[i];
2890 
2891         if ((st_policies & ST_TRANSFER_DIRTY_ONLY) &&
2892             !MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DIRTY_PAGE) &&
2893             !MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE)) {
2894             skipped_sentries++;
2895             continue;
2896         }
2897         if (skipped_sentries > 0) {
2898             cached_magic_vars->sentries[i - skipped_sentries] =
2899                 cached_magic_vars->sentries[i];
2900             cached_magic_vars->sentries[i - skipped_sentries].id -=
2901                 skipped_sentries;
2902             cached_sentry = &cached_magic_vars->sentries[i - skipped_sentries];
2903         }
2904 
2905 
2906         if (transfer_metadata_sentry_members(info, cached_sentry)) {
2907             printf("ERROR transferring sentry members metadata.\n");
2908             return EGENERIC;
2909         }
2910 
2911         /*
2912          * We have to change the type to its cached counterpart,
2913          * so that it may be compared to the local type of the local sentry counterpart.
2914          */
2915         cached_sentry->type = &cached_magic_vars->types[cached_sentry->type - remote_magic_vars->types];
2916 
2917         if (cached_sentry->type->size > *max_buff_sz) {
2918             *max_buff_sz = cached_sentry->type->size;
2919         }
2920     }
2921 
2922     if (skipped_sentries > 0)
2923         cached_magic_vars->sentries_num -= skipped_sentries;
2924 
2925     return OK;
2926 }
2927 
2928 PRIVATE int transfer_metadata_sentry_members(st_init_info_t *info, struct _magic_sentry *sentry)
2929 {
2930     if (sentry->name != NULL) {
2931         MD_TRANSFER_STR(info, &sentry->name);
2932     } else {
2933         printf("ERROR. sentry->name == NULL.\n");
2934         return EGENERIC;
2935     }
2936     return OK;
2937 }
2938 
2939 PUBLIC int st_transfer_metadata_dsentries(st_init_info_t *info, struct _magic_vars_t *cached_magic_vars
2940     , struct _magic_vars_t *remote_magic_vars, st_counterparts_t *counterparts, size_t *max_buff_sz, int *dsentries_num)
2941 {
2942 
2943     struct _magic_dsentry **dsentry_ptr;
2944 #if MAGIC_DSENTRY_ALLOW_PREV
2945     struct _magic_dsentry *prev_dsentry = NULL;
2946 #endif
2947     int r;
2948 
2949     *dsentries_num = 0;
2950 
2951     cached_magic_vars->first_dsentry = remote_magic_vars->first_dsentry;
2952     dsentry_ptr = &cached_magic_vars->first_dsentry;
2953     while (*dsentry_ptr != NULL) {
2954 
2955         struct _magic_dsentry *cached_dsentry, *remote_dsentry = *dsentry_ptr;
2956         struct _magic_sentry *sentry;
2957 
2958         /* transfer dsentry */
2959         MD_TRANSFER(info, *dsentry_ptr, (void **) dsentry_ptr, sizeof(struct _magic_dsentry));
2960         cached_dsentry = *dsentry_ptr;
2961 
2962         if ((st_policies & ST_TRANSFER_DIRTY_ONLY) &&
2963             !MAGIC_STATE_FLAG((&cached_dsentry->sentry), MAGIC_STATE_DIRTY_PAGE) &&
2964             !MAGIC_STATE_FLAG((&cached_dsentry->sentry), MAGIC_STATE_IMMUTABLE)) {
2965             *dsentry_ptr = cached_dsentry->next;
2966             continue;
2967         }
2968 
2969         if (cached_magic_vars->first_stack_dsentry == remote_dsentry) {
2970             cached_magic_vars->first_stack_dsentry = cached_dsentry;
2971         } else if(cached_magic_vars->last_stack_dsentry == remote_dsentry) {
2972             cached_magic_vars->last_stack_dsentry = cached_dsentry;
2973         }
2974 
2975         /* adjust dsentry */
2976         if (cached_dsentry->parent_name != NULL) {
2977             MD_TRANSFER_STR(info, &cached_dsentry->parent_name);
2978             if (strlen(cached_dsentry->parent_name) == 0) {
2979                 printf("ERROR. strlen(dsentry->parent_name) == 0.\n");
2980 #if TODO_DSENTRY_PARENT_NAME_BUG
2981                 if (cached_dsentry->next != NULL)
2982 #endif
2983                     return EGENERIC;
2984             }
2985         } else {
2986             printf("ERROR. dsentry->parent_name == NULL.\n");
2987             return EGENERIC;
2988         }
2989 
2990         sentry = &cached_dsentry->sentry;
2991         if (transfer_metadata_sentry_members(info, sentry)) {
2992             printf("ERROR transferring sentry members metadata.\n");
2993             return EGENERIC;
2994         }
2995 
2996         /* Override original id to simplify pairing later. */
2997         sentry->id = cached_magic_vars->sentries_num + *dsentries_num + 1;
2998 
2999         /*
3000          * Report violations for all the pointers pointing to the initial stack area.
3001          * This is to make sure no assumption is incorrectly made about this area.
3002          */
3003         if (!strcmp(sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) {
3004             sentry->flags |= MAGIC_STATE_ADDR_NOT_TAKEN;
3005         }
3006 
3007         /*
3008          * Adjust the type, so that the local and remote type can be compared
3009          * during a server version update
3010          */
3011         if (sentry->type == &remote_dsentry->type) {
3012 
3013             /*
3014              * sentry->type is contained in dsentry.type. Therefore, this is an
3015              * array type. In order to allocate a new memory region, we only
3016              * need the size of the type, and the contained type as arguments
3017              * to the magic allocation function. Therefore, other members of
3018              * the type do need to be cached or adjusted.
3019              */
3020 
3021             /* Adjust pointer to cached location */
3022             sentry->type = &cached_dsentry->type;
3023 
3024             /* Adjust contained_types to type_array located in dsentry struct. */
3025             sentry->type->contained_types = cached_dsentry->type_array;
3026 
3027             /*
3028              * Adjust only pointer in type_array. It currently has the same
3029              * value as the remote copy, but it has to point to the cached
3030              * of the contained type.
3031              */
3032             sentry->type->contained_types[0] = &cached_magic_vars->types[sentry->type->contained_types[0] - remote_magic_vars->types];
3033 
3034             /* Adjust empty strings. */
3035             sentry->type->name = "";
3036             sentry->type->type_str = "";
3037 
3038             /* Adjust value set if necessary. */
3039             if (MAGIC_TYPE_HAS_VALUE_SET(sentry->type)) {
3040                 r = transfer_metadata_type_value_set(info, sentry->type, cached_magic_vars, remote_magic_vars);
3041                 if (r != OK) {
3042                     return r;
3043                 }
3044             }
3045         } else {
3046 
3047             /*
3048              * sentry.type must be in the global type array. Adjust pointer accordingly.
3049              * The pointer is still pointing to the remote version.
3050              * We have to change it to the cached version.
3051              */
3052             sentry->type = &cached_magic_vars->types[sentry->type - remote_magic_vars->types];
3053 
3054         }
3055 
3056         /* see if the buffer needs to be bigger for the dsentry data region. */
3057         if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND) && *max_buff_sz < sentry->type->size) {
3058             *max_buff_sz = sentry->type->size;
3059         }
3060 
3061         dsentry_ptr = &cached_dsentry->next;
3062 #if MAGIC_DSENTRY_ALLOW_PREV
3063         if (cached_dsentry->prev != NULL)
3064             cached_dsentry->prev = prev_dsentry;
3065         prev_dsentry = cached_dsentry;
3066 #endif
3067         *dsentries_num = *dsentries_num + 1;
3068     }
3069 
3070     return OK;
3071 }
3072 
3073 PRIVATE int pair_metadata_types(st_init_info_t *info,
3074     struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts, int allow_unpaired_types)
3075 {
3076     int i, j, num_unpaired_struct_types = 0;
3077     int num_unpaired_types = 0;
3078     int num_total_types = 0;
3079     int num_struct_types = 0;
3080     int num_unpaired_types_left, num_unpaired_struct_types_left;
3081 
3082     if (st_unpaired_types_ratio > 0 || st_unpaired_struct_types_ratio > 0) {
3083         for (i = 0 ; i < cached_magic_vars->types_num ; i++) {
3084             struct _magic_type *type = &cached_magic_vars->types[i];
3085             if (ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) {
3086                 num_struct_types++;
3087             }
3088             if (ST_IS_UNPAIRABLE_TYPE(type)) {
3089                 num_total_types++;
3090             }
3091         }
3092         num_unpaired_types = (int) (st_unpaired_types_ratio*num_total_types);
3093         num_unpaired_struct_types = (int) (st_unpaired_struct_types_ratio*num_struct_types);
3094     }
3095     num_unpaired_types_left = num_unpaired_types;
3096     num_unpaired_struct_types_left = num_unpaired_struct_types;
3097 
3098     /* type pairing, remote->local */
3099     for(i = 0 ; i < cached_magic_vars->types_num ; i++) {
3100         struct _magic_type *type = &cached_magic_vars->types[i];
3101         counterparts->types[i].counterpart = NULL;
3102 
3103         if (num_unpaired_types_left > 0 && ST_IS_UNPAIRABLE_TYPE(type)) {
3104             num_unpaired_types_left--;
3105             continue;
3106         }
3107         else if (num_unpaired_struct_types_left > 0 && ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) {
3108             num_unpaired_struct_types_left--;
3109             continue;
3110         }
3111 
3112         for (j = 0 ; j < _magic_types_num ; j++) {
3113             /* A remote type may be paired to multiple local types.
3114              * It is safe to index only the first type since counterparts
3115              * are only used to speed up type matching.
3116              */
3117             if (magic_type_compatible(type, &_magic_types[j], MAGIC_TYPE_COMPARE_ALL)) {
3118                 counterparts->types[i].counterpart = &_magic_types[j];
3119                 break;
3120             }
3121         }
3122 
3123         if (!allow_unpaired_types && counterparts->types[i].counterpart == NULL) {
3124              printf("ERROR, remote type cannot be paired with a local type: ");
3125              MAGIC_TYPE_PRINT(type, MAGIC_EXPAND_TYPE_STR);
3126              printf("\n");
3127              return EGENERIC;
3128         }
3129     }
3130     if (st_unpaired_types_ratio > 0 || st_unpaired_struct_types_ratio > 0) {
3131         assert(num_unpaired_types_left == 0 && (st_unpaired_types_ratio > 0 || num_unpaired_struct_types == 0));
3132         _magic_printf("Unpaired types stats: unpaired types: %d, total types: %d, unpaired struct types: %d, struct types: %d\n", num_unpaired_types, num_total_types, num_unpaired_struct_types, num_struct_types);
3133     }
3134 
3135     for (i = 0 ; i < cached_magic_vars->types_num ; i++) {
3136         struct _magic_type *type = &cached_magic_vars->types[i];
3137         struct _magic_type *local_type = (struct _magic_type*) counterparts->types[i].counterpart;
3138         counterparts->ptr_types[i].counterpart = NULL;
3139         if (local_type && type->type_id == MAGIC_TYPE_POINTER) {
3140             if (MAGIC_TYPE_HAS_COMP_TYPES(type) != MAGIC_TYPE_HAS_COMP_TYPES(local_type)) {
3141                 continue;
3142             }
3143             if (MAGIC_TYPE_HAS_COMP_TYPES(type)) {
3144                 j = 0;
3145                 while (MAGIC_TYPE_HAS_COMP_TYPE(type, j) && MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) {
3146                     struct _magic_type *ctype = MAGIC_TYPE_COMP_TYPE(type, j);
3147                     struct _magic_type *local_ctype = MAGIC_TYPE_COMP_TYPE(local_type, j);
3148                     if (!ST_TYPE_IS_CACHED_COUNTERPART(ctype, local_ctype)) {
3149                         break;
3150                     }
3151                     j++;
3152                 }
3153                 if (MAGIC_TYPE_HAS_COMP_TYPE(type, j) || MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) {
3154                     continue;
3155                 }
3156             }
3157             counterparts->ptr_types[i].counterpart = local_type;
3158         }
3159     }
3160 
3161     return OK;
3162 }
3163 
3164 PRIVATE int pair_metadata_functions(st_init_info_t *info,
3165     struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
3166 {
3167     int i;
3168     struct _magic_function *cached_function, *local_function;
3169 #if ST_DEBUG_LEVEL > 0
3170     int num_relocated = 0;
3171 #endif
3172 
3173     /* map remote functions to local functions */
3174     for(i = 0 ; i < cached_magic_vars->functions_num ; i++) {
3175         cached_function = &cached_magic_vars->functions[i];
3176         local_function = NULL;
3177         st_map_functions(&cached_function, &local_function);
3178         ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
3179 
3180 #if CHECK_SENTITY_PAIRS
3181         if (local_function) {
3182             /* debug: see if the function is paired more than once */
3183             struct _magic_function *cfunction = NULL;
3184             st_map_functions(&cfunction, &local_function);
3185             if (cfunction != cached_function) {
3186                 printf("function pairing failed for (1) local function linked to multiple remote functions (2), (3)\n");
3187                 printf("(1) "); MAGIC_FUNCTION_PRINT(local_function, 0); printf("\n");
3188                 printf("(2) "); MAGIC_FUNCTION_PRINT(cached_function, 0); printf("\n");
3189                 printf("(3) "); MAGIC_FUNCTION_PRINT(cfunction, 0); printf("\n");
3190                 return EGENERIC;
3191             }
3192         }
3193 #endif
3194 
3195 #if ST_DEBUG_LEVEL > 0
3196         if (local_function && cached_function->address != local_function->address) {
3197             num_relocated++;
3198             if (ST_DEBUG_LEVEL > 1) {
3199                 printf("- relocated function: '%s'\n", cached_magic_vars->functions[i].name);
3200             }
3201         }
3202 #endif
3203     }
3204 
3205 #if ST_DEBUG_LEVEL > 0
3206     printf("total remote functions: %d. relocated: %d\n", cached_magic_vars->functions_num, num_relocated);
3207 #endif
3208 
3209     return OK;
3210 }
3211 
3212 PRIVATE int pair_metadata_sentries(st_init_info_t *info,
3213     struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
3214 {
3215     int i, r;
3216     struct _magic_sentry *cached_sentry, *local_sentry;
3217 #if ST_DEBUG_LEVEL > 0
3218     int num_relocated_str = 0, num_relocated_normal = 0;
3219 #endif
3220 
3221     /* pair sentries remote->local */
3222     for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) {
3223         void *local_data_addr = NULL;
3224         cached_sentry = &cached_magic_vars->sentries[i];
3225 
3226         /* String data is transferred directly. */
3227         if (MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3228             char *string = st_buff_allocate(info, cached_sentry->type->size);
3229             if (!string) {
3230                 printf("ERROR allocating string.\n");
3231                 return EGENERIC;
3232             }
3233             r = st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) cached_sentry->address,
3234                  cached_sentry->type->size, (uint32_t) string);
3235             if(r != OK) {
3236                 printf("ERROR transferring string.\n");
3237                 return EGENERIC;
3238             }
3239             local_data_addr = string;
3240         }
3241         ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
3242 
3243         local_sentry = NULL;
3244         st_map_sentries(&cached_sentry, &local_sentry);
3245         ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
3246 
3247 #if CHECK_SENTITY_PAIRS
3248         if (local_sentry && !MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3249             /* debug: see if the non-string sentry is paired more than once */
3250             struct _magic_sentry *csentry = NULL;
3251             st_map_sentries(&csentry, &local_sentry);
3252             if (csentry != cached_sentry) {
3253                 printf("sentry pairing failed for (1) local sentry linked to multiple remote sentries (2), (3)\n");
3254                 printf("(1) "); MAGIC_SENTRY_PRINT(local_sentry, 0); printf("\n");
3255                 printf("(2) "); MAGIC_SENTRY_PRINT(cached_sentry, 0); printf("\n");
3256                 printf("(3) "); MAGIC_SENTRY_PRINT(csentry, 0); printf("\n");
3257                 return EGENERIC;
3258             }
3259         }
3260 #endif
3261 
3262 #if ST_DEBUG_LEVEL > 0
3263         if (local_sentry && cached_sentry->address != local_sentry->address) {
3264             if (MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3265                 num_relocated_str++;
3266             }
3267             else {
3268                 num_relocated_normal++;
3269                 if (ST_DEBUG_LEVEL > 1) {
3270                     printf("- relocated non-string sentry: '%s'\n", cached_sentry->name);
3271                 }
3272             }
3273         }
3274 #endif
3275     }
3276 
3277 #if ST_DEBUG_LEVEL > 0
3278     printf("total remote sentries: %d. relocated normal: %d relocated string: %d\n", cached_magic_vars->sentries_num, num_relocated_normal, num_relocated_str);
3279 #endif
3280 
3281     return OK;
3282 }
3283 
3284 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
3285 PRIVATE int allocate_pair_metadata_dsentries_from_raw_copy(st_init_info_t *info,
3286     struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
3287 {
3288     struct _magic_dsentry *dsentry;
3289     int remote_dsentries = 0, unpaired_dsentries = 0;
3290 
3291 #if ST_DEBUG_LEVEL > 3
3292     EXEC_WITH_MAGIC_VARS(
3293         magic_print_dsentries();
3294         , &st_cached_magic_vars
3295     );
3296     magic_print_dsentries();
3297 #endif
3298 
3299     dsentry = cached_magic_vars->first_dsentry;
3300     while (dsentry != NULL) {
3301         struct _magic_sentry *local_sentry = NULL, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
3302 
3303         /* Initialize counterpart to NULL. */
3304         ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL);
3305 
3306         remote_dsentries++;
3307 
3308         if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_STACK) && !MAGIC_STATE_FLAG(sentry, MAGIC_STATE_LIB)) {
3309             local_sentry = MAGIC_DSENTRY_TO_SENTRY((struct _magic_dsentry *)MAGIC_PTR_FROM_DATA(sentry->address));
3310         } else {
3311 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
3312             EXEC_WITH_MAGIC_VARS(
3313                 local_sentry = magic_sentry_lookup_by_range(sentry->address, NULL);
3314                 , &st_cached_magic_vars
3315             );
3316 #else
3317             local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL);
3318 #endif
3319         }
3320 
3321         if (!local_sentry) {
3322              unpaired_dsentries++;
3323 #if ST_DEBUG_LEVEL > 2
3324              printf("allocate_pair_metadata_dsentries_from_raw_copy: found unpaired "); MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR); _magic_printf("\n");
3325 #endif
3326         }
3327         ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
3328         dsentry = dsentry->next;
3329     }
3330 
3331 #if ST_DEBUG_LEVEL > 0
3332     printf("total remote dsentries: %d (%d unpaired)\n", remote_dsentries, unpaired_dsentries);
3333 #endif
3334 
3335     return OK;
3336 }
3337 
3338 #else
3339 
3340 PRIVATE int allocate_pair_metadata_dsentries(st_init_info_t *info,
3341     struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
3342 {
3343     struct _magic_dsentry *dsentry = cached_magic_vars->first_dsentry, *local_dsentry;
3344     int remote_dsentries = 0;
3345 #ifndef __MINIX
3346     int *local_sentry_paired_by_id = st_buff_allocate(info, (_magic_sentries_next_id + 1) * sizeof(int));
3347 #endif
3348 
3349 #if ST_DEBUG_LEVEL > 3
3350     EXEC_WITH_MAGIC_VARS(
3351         magic_print_dsentries();
3352         , &st_cached_magic_vars
3353     );
3354     magic_print_dsentries();
3355 #endif
3356 
3357 #ifdef __MINIX
3358     /*
3359      * Since on MINIX the mmaped regions are inherited in the new process,
3360      * we must first deallocate them. This is not the case on Linux.
3361      */
3362     while (dsentry != NULL) {
3363         int res = 0;
3364         struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
3365         int size = sentry->type->size;
3366         /* For mmap first unmap the old region that is already mapped into this new instance */
3367         if (!MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)
3368                 && MAGIC_STATE_REGION(sentry) == MAGIC_STATE_MAP
3369                 && !USE_PRE_ALLOCATED_BUFFER(info)
3370            )
3371             {
3372             /*
3373              * The 'ext' field in the dsentry is used here to record
3374              * the padding for ASR.
3375              */
3376             size_t padding = (size_t) dsentry->ext;
3377             /*
3378              * call munmap(). ptr and size have to be altered,
3379              * in order to free the preceding page, containing the dsentry struct, too.
3380              */
3381             MAGIC_MEM_WRAPPER_BLOCK(
3382                 res = munmap((char *)sentry->address - magic_get_sys_pagesize(), size + magic_get_sys_pagesize() + padding);
3383             );
3384             if (res != 0) {
3385                 printf("ERROR, munmap returned NULL.\n");
3386                 return EGENERIC;
3387             }
3388         }
3389         dsentry = dsentry->next;
3390     }
3391 #endif
3392 
3393     /* Permute dsentries in case of ASR. */
3394     if (info->flags & ST_LU_ASR) {
3395         magic_asr_permute_dsentries(&cached_magic_vars->first_dsentry);
3396     }
3397 
3398     dsentry = cached_magic_vars->first_dsentry;
3399     while (dsentry != NULL) {
3400         struct _magic_sentry *local_sentry, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
3401         int is_alloc_dsentry = MAGIC_SENTRY_IS_ALLOC(sentry);
3402         int res = 0;
3403         struct _magic_dsindex *local_dsindex;
3404 
3405         remote_dsentries++;
3406 
3407 #ifdef __MINIX
3408         /* Cannot deal with dead dsentries. */
3409         assert(dsentry->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE);
3410 #else
3411         /*
3412          * If there are dead dsentries, we simply skip them.
3413          */
3414         if (dsentry->magic_state != MAGIC_DSENTRY_MSTATE_ALIVE) {
3415             dsentry = dsentry->next;
3416             continue;
3417         }
3418 #endif
3419 
3420         /* Initialize counterpart to NULL. */
3421         ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL);
3422 
3423         /* Handle non-alloc dsentries first. */
3424         if (!is_alloc_dsentry) {
3425             local_sentry = magic_sentry_lookup_by_name(dsentry->parent_name,
3426                 sentry->name, dsentry->site_id, NULL);
3427             if (local_sentry) {
3428                 assert(!MAGIC_SENTRY_IS_ALLOC(local_sentry));
3429                 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
3430             }
3431 
3432             dsentry = dsentry->next;
3433             continue;
3434         }
3435 
3436         /* Out-of-band alloc dsentries next. */
3437         if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_OUT_OF_BAND)) {
3438             struct _magic_type *type;
3439             /* We can only handle obdsentries with the magic void type, transferred as-is. */
3440             if (sentry->type != &dsentry->type) {
3441                 /* Not an array type */
3442                 type = sentry->type;
3443             } else {
3444                 /* This is an array type, use its contained type instead. */
3445                 type = sentry->type->contained_types[0];
3446             }
3447             /* We now have the cached version of the type. Compare it to magic void type */
3448             if (!magic_type_compatible(type, MAGIC_VOID_TYPE, MAGIC_TYPE_COMPARE_ALL)) {
3449                 printf("Can't handle obdsentry with non-void type\n");
3450                 return EGENERIC;
3451             }
3452 #ifdef __MINIX
3453             /* On MINIX we need to recreate all the obdsentries. */
3454             struct _magic_obdsentry *obdsentry;
3455             int size = sentry->type->size;
3456             obdsentry = magic_create_obdsentry(sentry->address,
3457                 MAGIC_VOID_TYPE, size, MAGIC_STATE_REGION(sentry), sentry->name, dsentry->parent_name);
3458             if (obdsentry == NULL) {
3459                 printf("ERROR, magic_create_obdsentry returned NULL.\n");
3460                 return EGENERIC;
3461             }
3462             local_dsentry = MAGIC_OBDSENTRY_TO_DSENTRY(obdsentry);
3463 #else
3464             /* On Linux we only need to pair them. */
3465             local_sentry = magic_sentry_lookup_by_name(
3466                 MAGIC_SENTRY_PARENT(sentry), sentry->name,
3467                 MAGIC_SENTRY_SITE_ID(sentry), NULL);
3468             if (local_sentry == NULL) {
3469                 printf("Unable to pair obdsentry.\n");
3470                 return EGENERIC;
3471             }
3472             local_dsentry = MAGIC_DSENTRY_FROM_SENTRY(local_sentry);
3473 #endif
3474             ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
3475             dsentry = dsentry->next;
3476             continue;
3477         }
3478 
3479         /* Handle regular alloc dsentries last. */
3480 #ifndef __MINIX
3481         /*
3482          * For Linux, first pair INIT time remote
3483          * dsentries with local dsentries.
3484          */
3485 
3486         if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_INIT)) {
3487             local_sentry = NULL;
3488 
3489             if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_IMMUTABLE)) {
3490                 /*
3491                  * Immutable init time dsentries should have already been
3492                  * preallocated, so just pair them by address.
3493                  */
3494                 local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL);
3495             } else {
3496 #if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
3497                 struct _magic_sentry_list *local_sentry_list;
3498                 local_sentry_list = magic_sentry_list_lookup_by_name_hash(
3499                     dsentry->parent_name, sentry->name, dsentry->site_id, NULL);
3500 
3501                 while (local_sentry_list) {
3502                     if (!local_sentry_paired_by_id[local_sentry_list->sentry->id]) {
3503                         local_sentry = local_sentry_list->sentry;
3504                         break;
3505                     }
3506                     local_sentry_list = local_sentry_list->next;
3507                 }
3508 
3509 #else
3510                 do {
3511                     struct _magic_dsentry *prev_dsentry, *tmp_dsentry;
3512                     struct _magic_sentry *tmp_sentry;
3513                     MAGIC_DSENTRY_LOCK();
3514                     MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
3515                         tmp_dsentry, tmp_sentry,
3516                         if (!strcmp(tmp_sentry->name, sentry->name)) {
3517                             if (!dsentry->parent_name ||
3518                                     !strcmp(MAGIC_SENTRY_PARENT(tmp_sentry), dsentry->parent_name)) {
3519                                 if (dsentry->site_id == MAGIC_DSENTRY_SITE_ID_NULL ||
3520                                         tmp_dsentry->site_id == dsentry->site_id) {
3521                                     if (!local_sentry_paired_by_id[tmp_sentry->id]) {
3522                                         local_sentry = tmp_sentry;
3523                                         break;
3524                                     }
3525                                 }
3526                             }
3527                         }
3528                     );
3529                     MAGIC_DSENTRY_UNLOCK();
3530                 } while (0);
3531 #endif
3532             }
3533             if (local_sentry) {
3534                 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
3535                 local_sentry_paired_by_id[local_sentry->id] = 1;
3536                 dsentry = dsentry->next;
3537                 continue;
3538             }
3539         }
3540 #endif
3541 
3542         /*
3543          * Just recreate all the other dsentries. Immutable objects will
3544          * have already been inherited and allocate_local_dsentry() will
3545          * not reallocate them, but instead it will just create a new
3546          * local dsentry in the right place.
3547          */
3548         local_dsindex = magic_dsindex_lookup_by_name(dsentry->parent_name, sentry->name);
3549         if (local_dsindex || MAGIC_SENTRY_IS_LIB_ALLOC(sentry)) {
3550 
3551             /* Allocate a new local dsentry and pair it with the remote. */
3552             res = allocate_local_dsentry(info, local_dsindex, 0, 0, NULL, &local_dsentry, dsentry, NULL);
3553             if (res != ENOSYS) {
3554                 if (res != OK) {
3555                     return res;
3556                 }
3557                 assert(local_dsentry);
3558                 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
3559             }
3560         }
3561         dsentry = dsentry->next;
3562     }
3563 
3564 #if ST_DEBUG_LEVEL > 0
3565     printf("total remote dsentries: %d\n", remote_dsentries);
3566 #endif
3567 
3568     return OK;
3569 }
3570 
3571 PRIVATE int deallocate_nonxferred_dsentries(struct _magic_dsentry *first_dsentry, st_counterparts_t *counterparts)
3572 {
3573     struct _magic_dsentry *dsentry = first_dsentry;
3574     struct _magic_sentry *local_sentry;
3575 
3576     while (dsentry != NULL) {
3577         struct _magic_sentry *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
3578         int is_paired_dsentry = ST_HAS_CACHED_COUNTERPART(sentry, sentries);
3579         int is_alloc_dsentry = MAGIC_SENTRY_IS_ALLOC(sentry);
3580         ST_GET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
3581 
3582         if (MAGIC_STATE_EXTF_GET(sentry, ST_TRANSFER_DONE) || !is_alloc_dsentry) {
3583             dsentry = dsentry->next;
3584             continue;
3585         }
3586 
3587         /* Report non-transferred alloc dsentries when requested. */
3588         if (is_paired_dsentry && (st_policies & ST_REPORT_NONXFERRED_ALLOCS)) {
3589             printf("deallocate_nonxferred_dsentries: Non-transferred dsentry found: ");
3590             MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
3591             printf("\n");
3592         }
3593         if (!is_paired_dsentry && (st_policies & ST_REPORT_NONXFERRED_UNPAIRED_ALLOCS)) {
3594             printf("deallocate_nonxferred_dsentries: Non-transferred unpaired dsentry found: ");
3595             MAGIC_DSENTRY_PRINT(dsentry, MAGIC_EXPAND_TYPE_STR);
3596             printf("\n");
3597         }
3598 
3599         if (!is_paired_dsentry) {
3600             dsentry = dsentry->next;
3601             continue;
3602         }
3603         assert(local_sentry);
3604         if (MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
3605             deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry));
3606         }
3607         dsentry = dsentry->next;
3608     }
3609 
3610     return OK;
3611 }
3612 #endif
3613 
3614 PRIVATE void deallocate_local_dsentry(struct _magic_dsentry *local_dsentry)
3615 {
3616     int r, dsentry_type;
3617     struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(local_dsentry);
3618 
3619     assert(MAGIC_SENTRY_IS_ALLOC(local_sentry));
3620     dsentry_type = MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_OUT_OF_BAND) ? MAGIC_STATE_OUT_OF_BAND : MAGIC_STATE_REGION(local_sentry);
3621     /* A MAP_SHARED region will have both MAGIC_STATE_MAP and MAGIC_STATE_SHM. */
3622     if (dsentry_type == (MAGIC_STATE_MAP | MAGIC_STATE_SHM))
3623         dsentry_type = MAGIC_STATE_MAP;
3624 
3625     MAGIC_MEM_WRAPPER_BEGIN();
3626     switch (dsentry_type) {
3627         case MAGIC_STATE_HEAP:
3628             /* free */
3629             magic_free(local_sentry->address);
3630             break;
3631 
3632         case MAGIC_STATE_MAP:
3633             /* munmap */
3634             r = magic_munmap(local_sentry->address, local_sentry->type->size);
3635             if (r != 0) {
3636                 printf("Warning: magic_munmap failed for ");
3637                 MAGIC_DSENTRY_PRINT(local_dsentry, 0);
3638                 printf("\n");
3639             }
3640             break;
3641 
3642 #ifndef __MINIX
3643         case MAGIC_STATE_SHM:
3644             /* shmdt */
3645             r = magic_shmdt(local_sentry->address);
3646             if (r != 0) {
3647                 printf("Warning: magic_shmdt failed for ");
3648                 MAGIC_DSENTRY_PRINT(local_dsentry, 0);
3649                 printf("\n");
3650             }
3651             break;
3652 #endif
3653 
3654         case MAGIC_STATE_OUT_OF_BAND:
3655             /* out-of-band dsentry. */
3656             r = magic_destroy_obdsentry_by_addr(local_sentry->address);
3657             if (r != 0) {
3658                 printf("Warning: magic_destroy_obdsentry_by_addr failed for ");
3659                 MAGIC_DSENTRY_PRINT(local_dsentry, 0);
3660                 printf("\n");
3661             }
3662             break;
3663 
3664         default:
3665             st_cbs_os.panic("ERROR. UNSUPPORTED DSENTRY TYPE: %d\n", dsentry_type);
3666     }
3667     MAGIC_MEM_WRAPPER_END();
3668 }
3669 
3670 PRIVATE int allocate_local_dsentry(st_init_info_t *info, struct _magic_dsindex *local_dsindex, int num_elements, int is_type_mismatch, const union __alloc_flags *p_alloc_flags, struct _magic_dsentry** local_dsentry_ptr, struct _magic_dsentry *cached_dsentry, void *ptr)
3671 {
3672     struct _magic_dsentry *local_dsentry = NULL;
3673     struct _magic_sentry *cached_sentry = NULL;
3674     const char *name, *parent_name;
3675     struct _magic_type *type;
3676     int region;
3677     size_t size;
3678     union __alloc_flags alloc_flags;
3679 
3680     /* Either a dsindex or a dsentry needs to be set. */
3681     assert(local_dsindex || cached_dsentry);
3682 
3683     if (cached_dsentry)
3684         cached_sentry = MAGIC_DSENTRY_TO_SENTRY(cached_dsentry);
3685 
3686     /* name, parent_name: local_dsindex || cached_dsentry. */
3687     if (local_dsindex) {
3688         assert(MAGIC_DSINDEX_IS_ALLOC(local_dsindex));
3689         name = local_dsindex->name;
3690         parent_name = local_dsindex->parent_name;
3691     } else {
3692         assert(MAGIC_SENTRY_IS_ALLOC(cached_sentry));
3693         /*
3694          * The external allocation parent_name needs to be readjusted.
3695          * The external allocation name is adjusted after the new dsentry
3696          * is created.
3697          */
3698         name = cached_sentry->name;
3699         if (!strcmp(cached_dsentry->parent_name, MAGIC_ALLOC_EXT_PARENT_NAME)) {
3700             parent_name = MAGIC_ALLOC_EXT_PARENT_NAME;
3701         } else {
3702             int found_parent_name = 0;
3703             struct _magic_sodesc *sodesc;
3704             struct _magic_dsodesc *dsodesc;
3705             MAGIC_DSODESC_LOCK();
3706             MAGIC_SODESC_ITER(_magic_first_sodesc, sodesc,
3707                 if (!strcmp(cached_dsentry->parent_name, sodesc->lib.name)) {
3708                     parent_name = (const char *)sodesc->lib.name;
3709                     found_parent_name = 1;
3710                     break;
3711                 }
3712             );
3713             if (!found_parent_name) {
3714                 MAGIC_DSODESC_ITER(_magic_first_dsodesc, dsodesc,
3715                     if (!strcmp(cached_dsentry->parent_name, dsodesc->lib.name)) {
3716                         parent_name = (const char *)dsodesc->lib.name;
3717                         found_parent_name = 1;
3718                         break;
3719                     }
3720                 );
3721             }
3722             MAGIC_DSODESC_UNLOCK();
3723             assert(found_parent_name && "Invalid parent name for cached dsentry!");
3724         }
3725     }
3726 
3727     /* num_elements: args || cached_sentry. */
3728     if (num_elements <= 0 && cached_sentry) {
3729         num_elements = cached_sentry->type->type_id == MAGIC_TYPE_ARRAY ?
3730             cached_sentry->type->num_child_types : 1;
3731     }
3732     assert(num_elements > 0);
3733 
3734     /* alloc_flags: args || cached_dsentry. */
3735     if (!p_alloc_flags) {
3736         if (cached_dsentry && MAGIC_SENTRY_IS_ALLOC(cached_sentry)) {
3737             alloc_flags = cached_dsentry->alloc_flags;
3738         }
3739     } else {
3740         alloc_flags = *p_alloc_flags;
3741     }
3742 
3743     /* is_type_mismatch: args || cached_dsentry. */
3744     if (!is_type_mismatch && cached_dsentry)
3745         is_type_mismatch = MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_TYPE_SIZE_MISMATCH);
3746 
3747     /*
3748      * Use old address for immutable objects.
3749      */
3750     /* ptr: args || cached_sentry. */
3751     if (!ptr && cached_sentry &&
3752             MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE))
3753         ptr = cached_sentry->address;
3754 
3755     /* region: local_dsindex || cached_sentry. */
3756     if (local_dsindex)
3757         region = MAGIC_STATE_REGION(local_dsindex);
3758     else
3759         region = MAGIC_STATE_REGION(cached_sentry);
3760 
3761     /* Check if the region is ambigous. This shouldn't happen. */
3762     assert(!((region & (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) ==
3763         (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) &&
3764         "MAGIC_STATE_HEAP | MAGIC_STATE_MAP detected!");
3765 #if 0
3766     if ((region & (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) ==
3767         (MAGIC_STATE_HEAP | MAGIC_STATE_MAP)) {
3768         /* Check call flags to determine what to do in the ambiguous cases. */
3769         region = (alloc_flags.mmap_flags && alloc_flags.mmap_prot) ?
3770             MAGIC_STATE_MAP : MAGIC_STATE_HEAP;
3771     }
3772 #endif
3773 
3774     /* type: local_dsindex || cached_sentry. */
3775     if (local_dsindex) {
3776         type = local_dsindex->type;
3777 
3778         if (num_elements > 1 && MAGIC_TYPE_FLAG(local_dsindex->type, MAGIC_TYPE_VARSIZE)) {
3779             size = magic_type_alloc_get_varsized_array_size(local_dsindex->type, num_elements);
3780             assert(size > 0);
3781         } else {
3782             if (is_type_mismatch) {
3783                 type = MAGIC_VOID_TYPE;
3784                 printf("WARNING: Type size mismatch dsentry detected! Ignoring dsindex type and reverting to MAGIC_TYPE_VOID.\n");
3785                 printf("name=%s, parent_name=%s\n", local_dsindex->name, local_dsindex->parent_name);
3786             }
3787             size = num_elements * type->size;
3788         }
3789     } else {
3790         /*
3791          * The type will need adjusting later.
3792          */
3793         type = cached_sentry->type;
3794         size = type->size;
3795     }
3796 
3797     *local_dsentry_ptr = NULL;
3798 
3799     if (region & MAGIC_STATE_HEAP) {
3800         /* malloc */
3801         ptr = magic_malloc_positioned(type, name, parent_name, size, (ptr == NULL ? NULL : MAGIC_PTR_FROM_DATA(ptr)));
3802         if (ptr == NULL) {
3803             printf("ERROR, magic_malloc_positioned returned NULL.\n");
3804             return ENOMEM;
3805         }
3806         memset(ptr, 0, size);
3807         local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
3808     }
3809     else if (region & MAGIC_STATE_MAP) {
3810         /* mmap */
3811         if (!alloc_flags.mmap_flags || !alloc_flags.mmap_prot) {
3812             /* We need call_flags to perform mmap. */
3813             return ENOSYS;
3814         }
3815         ptr = persistent_mmap(type, name, parent_name, info, NULL, size,
3816             alloc_flags.mmap_prot, alloc_flags.mmap_flags, -1, 0, ptr);
3817         if (ptr == NULL) {
3818             printf("ERROR, persistent_mmap returned NULL.\n");
3819             return ENOMEM;
3820         }
3821         if (!(alloc_flags.mmap_flags & MAP_SHARED))
3822             memset(ptr, 0, size);
3823         local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
3824     }
3825 #ifndef __MINIX
3826     else if (region & MAGIC_STATE_SHM) {
3827         /* shmat */
3828         if (!alloc_flags.shmat_flags || !alloc_flags.shmat_shmid) {
3829             /* We need call_flags to perform shmat. */
3830             return ENOSYS;
3831         }
3832         ptr = magic_shmat(type, name, parent_name, alloc_flags.shmat_shmid,
3833             ptr, alloc_flags.shmat_flags);
3834         if (ptr == NULL) {
3835             printf("ERROR, magic_shmat returned NULL.\n");
3836             return ENOMEM;
3837         }
3838         local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
3839     }
3840 #endif
3841     else {
3842         if (local_dsindex) {
3843             printf("ERROR. UNSUPPORTED DSINDEX TYPE: ");
3844             MAGIC_DSINDEX_PRINT(local_dsindex, MAGIC_EXPAND_TYPE_STR);
3845         } else {
3846             printf("ERROR. UNSUPPORTED DSENTRY: ");
3847             MAGIC_DSENTRY_PRINT(cached_dsentry, MAGIC_EXPAND_TYPE_STR);
3848         }
3849         printf("\n");
3850         return EINVAL;
3851     }
3852 
3853     if (!local_dsindex) {
3854         /*
3855          * This was an externally allocated type and, as such, needs adjusting.
3856          */
3857         assert(cached_sentry->type == &cached_dsentry->type);
3858         local_dsentry->type = cached_dsentry->type;
3859         if (cached_dsentry->type_array[0]->type_id == MAGIC_TYPE_POINTER) {
3860             ST_GET_CACHED_COUNTERPART(cached_dsentry->type_array[0], types, ptr_types, local_dsentry->type_array[0]);
3861         } else {
3862             ST_GET_CACHED_COUNTERPART(cached_dsentry->type_array[0], types, types, local_dsentry->type_array[0]);
3863         }
3864         local_dsentry->sentry.type = &local_dsentry->type;
3865         local_dsentry->sentry.type->contained_types = local_dsentry->type_array;
3866     }
3867 
3868     assert(local_dsentry);
3869     assert(local_dsentry->parent_name && strcmp(local_dsentry->parent_name, ""));
3870     assert(local_dsentry->sentry.name && strcmp(local_dsentry->sentry.name, ""));
3871     assert(magic_check_dsentry(local_dsentry, 0));
3872     *local_dsentry_ptr = local_dsentry;
3873 
3874     if (is_type_mismatch)
3875         local_dsentry->sentry.flags |= MAGIC_STATE_TYPE_SIZE_MISMATCH;
3876 
3877     /*
3878      * Dsentries allocated by shared libraries have the names stored in dsentry
3879      * buffers (for now).
3880      * Readjust the local_sentry to do this as well, since after state transfer
3881      * cleanup the existing names will become invalid.
3882      */
3883     if (!local_dsindex && MAGIC_SENTRY_IS_LIB_ALLOC(cached_sentry)) {
3884         strncpy(local_dsentry->name_ext_buff, local_dsentry->sentry.name,
3885             MAGIC_DSENTRY_EXT_NAME_BUFF_SIZE);
3886         local_dsentry->sentry.name = local_dsentry->name_ext_buff;
3887     }
3888 
3889     return OK;
3890 }
3891 
3892 PRIVATE int check_unpaired_sentry(st_init_info_t *info,
3893     struct _magic_sentry* cached_sentry)
3894 {
3895     int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(cached_sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
3896     int report;
3897 
3898     if (!sentry_needs_transfer && !MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3899         return OK;
3900     }
3901 
3902     if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
3903         report = st_policies & ST_REPORT_UNPAIRED_DSENTRIES;
3904     }
3905     else if(MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3906         report = st_policies & ST_REPORT_UNPAIRED_STRINGS;
3907     }
3908     else {
3909         report = st_policies & ST_REPORT_UNPAIRED_SENTRIES;
3910     }
3911     if (report) {
3912         printf("check_unpaired_sentry: Unpaired sentry found: ");
3913         ST_SENTRY_PRINT(cached_sentry,MAGIC_EXPAND_TYPE_STR);
3914         printf("\n");
3915     }
3916 
3917     return OK;
3918 }
3919 
3920 PUBLIC struct _magic_sentry* st_cached_to_remote_sentry(st_init_info_t *info, struct _magic_sentry *cached_sentry)
3921 {
3922     struct _magic_sentry *remote_sentry;
3923     void *local_data_addr;
3924     ST_CHECK_INIT();
3925 
3926     /* Copy metadata into metadata buffer. */
3927     if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
3928         magic_copy_dsentry(MAGIC_DSENTRY_FROM_SENTRY(cached_sentry), st_dsentry_buff);
3929         remote_sentry = MAGIC_DSENTRY_TO_SENTRY(st_dsentry_buff);
3930     }
3931     else {
3932         memcpy(&st_dsentry_buff->sentry, cached_sentry, sizeof(struct _magic_sentry));
3933         remote_sentry = &st_dsentry_buff->sentry;
3934     }
3935 
3936     /* Have the remote sentry point to local data. */
3937     local_data_addr = NULL;
3938     /* See if we have the data locally already first. */
3939     ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
3940     if (!local_data_addr) {
3941         /* Copy remote data into local data buffer. */
3942         if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) remote_sentry->address
3943                 , remote_sentry->type->size, (uint32_t) st_data_buff))
3944         {
3945             printf("ERROR transferring sentry data to local buffer.\n");
3946             return NULL;
3947         }
3948         local_data_addr = st_data_buff;
3949     }
3950     remote_sentry->address = local_data_addr;
3951 
3952     return remote_sentry;
3953 }
3954 
3955 PRIVATE int transfer_data_sentry(st_init_info_t *info,
3956     struct _magic_sentry* cached_sentry)
3957 {
3958 
3959     int r;
3960     int st_cb_flags = ST_CB_DEFAULT_FLAGS;
3961     struct _magic_sentry *local_sentry, *remote_sentry;
3962     int flags = ST_SEL_ANALYZE_FLAGS;
3963     struct st_cb_info cb_info_buff;
3964     struct st_cb_info *cb_info = &cb_info_buff;
3965     static _magic_selement_t magic_local_selements[MAGIC_MAX_RECURSIVE_TYPES+1];
3966     static int magic_flags_by_depth[MAGIC_MAX_RECURSIVE_TYPES+1];
3967 
3968     /* Skip extern weak symbols. */
3969     if (!cached_sentry->address) {
3970         assert(MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_EXTERNAL));
3971         st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL);
3972         return OK;
3973     }
3974 
3975     /* Determine local and remote sentries from the cached version. */
3976     local_sentry = NULL;
3977     st_lookup_sentry_pair(&cached_sentry, &local_sentry);
3978     assert(local_sentry && "Unexpected unpaired sentry!");
3979     remote_sentry = st_cached_to_remote_sentry(info, cached_sentry);
3980     if (!remote_sentry) {
3981         printf("No remote sentry found for cached sentry: ");
3982         MAGIC_SENTRY_PRINT(cached_sentry, 0);
3983         printf("\n");
3984         return EFAULT;
3985     }
3986 
3987     cb_info->local_selements = magic_local_selements;
3988     cb_info->local_selement = magic_selement_from_sentry(local_sentry, &magic_local_selements[0]);
3989     cb_info->walk_flags = MAGIC_TYPE_WALK_DEFAULT_FLAGS;
3990     cb_info->st_cb_flags = st_cb_flags;
3991     cb_info->init_info = info;
3992     cb_info->st_cb_saved_flags = magic_flags_by_depth;
3993     magic_flags_by_depth[0] = st_cb_flags;
3994 
3995     EXEC_WITH_MAGIC_VARS(
3996         r = magic_sentry_analyze(remote_sentry , flags, transfer_data_selement, cb_info, NULL);
3997         , &st_cached_magic_vars
3998     );
3999     if (r < 0) {
4000         return r;
4001     }
4002 
4003     st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL);
4004     return OK;
4005 }
4006 
4007 PRIVATE int transfer_data_selement(_magic_selement_t *selement, _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, void *cb_args)
4008 {
4009 
4010     int r = ST_CB_NOT_PROCESSED;
4011     int depth, cb_flags;
4012     struct st_cb_info *cb_info = (struct st_cb_info *) cb_args;
4013     _magic_selement_t *local_selement, *local_parent_selement;
4014     st_cb_selement_transfer_t *cb;
4015 
4016     register_typenames_and_callbacks();
4017 
4018     if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
4019         depth = selement->depth;
4020         local_selement = &cb_info->local_selements[depth];
4021         if (depth > 0) {
4022             local_parent_selement = &cb_info->local_selements[depth-1];
4023             local_selement->sentry = local_parent_selement->sentry;
4024             local_selement->parent_type = local_parent_selement->type;
4025             local_selement->parent_address = local_parent_selement->address;
4026             cb_info->st_cb_flags = cb_info->st_cb_saved_flags[depth-1];
4027         }
4028         /* Map the cached and the local selement. */
4029         st_map_selement(selement, local_selement, cb_info, FALSE);
4030         if (local_selement->type == NULL) {
4031             /* Unpaired selement. */
4032             if (st_policies & ST_REPORT_UNPAIRED_SELEMENTS) {
4033                 printf("transfer_data_selement: Unpaired selement found: ");
4034                 MAGIC_SELEMENT_PRINT(selement, MAGIC_EXPAND_TYPE_STR);
4035                 printf("\n");
4036             }
4037             return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
4038         }
4039         cb_info->local_selement = local_selement;
4040 
4041         /* See if identity transfer has been requested. */
4042         if (cb_info->st_cb_flags & ST_CB_FORCE_IXFER) {
4043             r = transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
4044             assert(r != ST_CB_NOT_PROCESSED);
4045             cb_info->st_cb_saved_flags[depth] = cb_info->st_cb_flags;
4046             return r;
4047         }
4048     }
4049 
4050     cb_flags = ST_CB_TYPE_SELEMENT;
4051     if (ST_TYPE_NAME_KEY(selement->type) != NULL) {
4052         cb_flags |= ST_CB_TYPE_TYPENAME;
4053     }
4054     if (selement->num == 1) {
4055         cb_flags |= ST_CB_TYPE_SENTRY;
4056     }
4057 
4058     cb = st_cbs.st_cb_selement_transfer[cb_flags];
4059     while (TRUE) {
4060 
4061         if (*cb != NULL) {
4062             r = (*cb)(selement, sel_analyzed, sel_stats, cb_info);
4063         } else {
4064             r = default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
4065             assert(r != ST_CB_NOT_PROCESSED
4066                 && "Default selement callback should always process the selement.");
4067         }
4068 
4069         if (r != ST_CB_NOT_PROCESSED) {
4070             assert((r<0 || MAGIC_SENTRY_ANALYZE_IS_VALID_RET(r)) && "Invalid callback return code!");
4071             if (!ST_CB_FLAG(ST_CB_CHECK_ONLY)) {
4072                 cb_info->st_cb_saved_flags[depth] = cb_info->st_cb_flags;
4073             }
4074             return r;
4075         }
4076 
4077         cb++;
4078     }
4079 
4080     /* Not reachable. */
4081     return EINTR;
4082 }
4083 
4084 PRIVATE int lookup_trg_info(_magic_selement_t *selement,
4085     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats, struct st_cb_info *cb_info,
4086     _magic_selement_t *cached_trg_selement, _magic_selement_t *local_trg_selement)
4087 {
4088     _magic_selement_t *local_selement, *trg_selement;
4089     struct _magic_sentry *cached_trg_sentry, *local_trg_sentry = NULL;
4090     struct _magic_function *cached_trg_function, *local_trg_function = NULL;
4091     _magic_sel_analyzed_t local_sel_analyzed;
4092     _magic_sel_stats_t local_sel_stats;
4093     void *local_trg_root_address;
4094     struct _magic_type *cached_trg_root_type, *local_trg_root_type;
4095     int first_legal_trg_type, is_same_type, is_same_trg_type, local_trg_has_addr_not_taken;
4096 
4097     local_selement = cb_info->local_selement;
4098     first_legal_trg_type = sel_analyzed->u.ptr.first_legal_trg_type;
4099     assert(first_legal_trg_type >= 0);
4100     trg_selement = &sel_analyzed->u.ptr.trg_selements[first_legal_trg_type];
4101     local_trg_root_type = NULL;
4102 
4103     /* Lookup cached and local targets. */
4104     if (MAGIC_SEL_ANALYZED_PTR_HAS_TRG_SENTRY(sel_analyzed)) {
4105         cached_trg_sentry = trg_selement->sentry;
4106         local_trg_sentry = NULL;
4107         st_lookup_sentry_pair(&cached_trg_sentry, &local_trg_sentry);
4108         *cached_trg_selement = *trg_selement;
4109         cached_trg_root_type = cached_trg_sentry->type;
4110         local_trg_has_addr_not_taken = local_trg_sentry && MAGIC_STATE_FLAG(local_trg_sentry, MAGIC_STATE_ADDR_NOT_TAKEN);
4111         local_trg_selement->sentry = local_trg_sentry;
4112         if (local_trg_sentry) {
4113             local_trg_root_address = local_trg_sentry->address;
4114             local_trg_root_type = local_trg_sentry->type;
4115         }
4116     }
4117     else if(MAGIC_SEL_ANALYZED_PTR_HAS_TRG_FUNCTION(sel_analyzed)) {
4118         cached_trg_function = MAGIC_DFUNCTION_TO_FUNCTION(&sel_analyzed->u.ptr.trg.dfunction);
4119         local_trg_function = NULL;
4120         st_lookup_function_pair(&cached_trg_function, &local_trg_function);
4121         *cached_trg_selement = *trg_selement;
4122         cached_trg_root_type = cached_trg_function->type;
4123         local_trg_has_addr_not_taken = local_trg_function && MAGIC_STATE_FLAG(local_trg_function, MAGIC_STATE_ADDR_NOT_TAKEN);
4124         local_trg_selement->sentry = NULL;
4125         if (local_trg_function) {
4126             local_trg_root_address = local_trg_function->address;
4127             local_trg_root_type = local_trg_function->type;
4128         }
4129     }
4130 
4131     /* Check unpaired targets. */
4132     if (!local_trg_root_type) {
4133         local_trg_selement->type = NULL;
4134         return OK;
4135     }
4136 
4137     /* Check address not taken violations. */
4138     if (local_trg_has_addr_not_taken) {
4139         ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with paired target whose address is not taken", selement, sel_analyzed, sel_stats, cb_info);
4140         return EFAULT;
4141     }
4142 
4143     /* Check types and return immediately in case of perfect pointer match. */
4144     is_same_type = selement->type == local_selement->type || ST_PTR_TYPE_IS_CACHED_COUNTERPART(selement->type, local_selement->type);
4145     is_same_trg_type = ST_TYPE_IS_CACHED_COUNTERPART(cached_trg_root_type, local_trg_root_type);
4146     if (is_same_type && is_same_trg_type) {
4147         local_trg_selement->type = cached_trg_selement->type;
4148         local_trg_selement->address = (char*) local_trg_root_address + sel_analyzed->u.ptr.trg_offset;
4149         return OK;
4150     }
4151 #if CHECK_ASR && !FORCE_SOME_UNPAIRED_TYPES
4152     if (cb_info->init_info->flags & ST_LU_ASR) {
4153         st_cbs_os.panic("ASR should never get here!");
4154     }
4155 #endif
4156 
4157     /* Map sel_analyzed to its local counterpart. */
4158     if (is_same_trg_type) {
4159         local_sel_analyzed = *sel_analyzed;
4160         local_sel_analyzed.u.ptr.trg_selements[0].address = (char*) local_trg_root_address + sel_analyzed->u.ptr.trg_offset;
4161     }
4162     else {
4163         st_map_sel_analyzed_from_target(sel_analyzed, &local_sel_analyzed, local_trg_sentry, local_trg_function, cb_info);
4164         if (local_sel_analyzed.u.ptr.num_trg_types == 0) {
4165             /* Unpaired target selements. */
4166             local_trg_selement->type = NULL;
4167             return OK;
4168         }
4169     }
4170 
4171     /* Check violations on the local target. */
4172     memset(&local_sel_stats, 0, sizeof(local_sel_stats));
4173     magic_selement_analyze_ptr_type_invs(local_selement, &local_sel_analyzed, &local_sel_stats);
4174     if (MAGIC_SEL_STATS_HAS_VIOLATIONS(&local_sel_stats)) {
4175         /* Local pointer with violations found */
4176         ST_CB_PRINT(ST_CB_ERR, "uncaught ptr with after-transfer violations", selement, sel_analyzed, sel_stats, cb_info);
4177         ST_CB_PRINT(ST_CB_ERR, "transferred ptr with violations", local_selement, &local_sel_analyzed, &local_sel_stats, cb_info);
4178         return EFAULT;
4179     }
4180 
4181     /* All the targets mapped correctly. */
4182     local_trg_selement->type = local_sel_analyzed.u.ptr.trg_selements[0].type;
4183     local_trg_selement->address = local_sel_analyzed.u.ptr.trg_selements[0].address;
4184     return OK;
4185 }
4186 
4187 /* transfer helper functions */
4188 
4189 PRIVATE int md_transfer_str(st_init_info_t *info, char **str_pt)
4190 {
4191     char buff[ST_STR_BUFF_SIZE + 2];
4192 
4193     if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) *str_pt, ST_STR_BUFF_SIZE + 1, (uint32_t) buff)) {
4194         st_cbs_os.panic("md_transfer_str(): ERROR transferring string.\n");
4195         return EGENERIC;
4196     }
4197     buff[ST_STR_BUFF_SIZE + 1] = '\0';
4198     if (strlen(buff) > ST_STR_BUFF_SIZE) {
4199         st_cbs_os.panic("md_transfer_str(): transferred string has a wrong size: %d\n", strlen(buff));
4200         return EGENERIC;
4201     }
4202 
4203     *str_pt = st_buff_allocate(info, strlen(buff) + 1);
4204     if (!*str_pt) {
4205         st_cbs_os.panic("md_transfer_str(): string buffer could not be allocated.\n");
4206         return EGENERIC;
4207     }
4208     strcpy(*str_pt, buff);
4209     return OK;
4210 }
4211 
4212 PRIVATE int md_transfer(st_init_info_t *info, void *from, void **to, int len)
4213 {
4214     /* backup from value, in case &from == to */
4215     void *from_backup = from;
4216     *to = st_buff_allocate(info, len);
4217     if (!*to) {
4218         st_cbs_os.panic("md_transfer(): buffer could not be allocated.\n");
4219         return EGENERIC;
4220     }
4221     if (st_cbs_os.copy_state_region(info->info_opaque, (uint32_t) from_backup, len, (uint32_t) *to)) {
4222         st_cbs_os.panic("md_transfer(): ERROR transferring remote data to buffer.\n");
4223         return EGENERIC;
4224     }
4225     return OK;
4226 }
4227 
4228 
4229 /* Buffer allocation */
4230 
4231 PRIVATE void *persistent_mmap(__MA_ARGS__ st_init_info_t *info, void *start, size_t length, int prot, int flags, int fd, off_t offset, struct _magic_dsentry *dsentry) {
4232     if (USE_PRE_ALLOCATED_BUFFER(info)) {
4233         size_t alloc_length = length + (length % magic_get_sys_pagesize() == 0 ? 0 : magic_get_sys_pagesize() - (length % magic_get_sys_pagesize()));
4234         char *ptr, *data_ptr;
4235 
4236         assert(((char *)info->init_buff_cleanup_start) + alloc_length + magic_get_sys_pagesize() <= st_pre_allocated_page_pt && "mmap region hits temporary buffer.");
4237         assert(((char *)info->init_buff_cleanup_start) + alloc_length + magic_get_sys_pagesize() <= ((char *) info->init_buff_start) + info->init_buff_len && "mmap region hits end of pre-allocated buffer");
4238 
4239         ptr = ((char *)info->init_buff_cleanup_start) + magic_get_sys_pagesize() - MAGIC_SIZE_TO_REAL(0);
4240         data_ptr = magic_alloc(__MA_VALUES__ ptr, alloc_length, (int) MAGIC_STATE_MAP);
4241         MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_flags = flags;
4242         MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(data_ptr))->alloc_mmap_prot = prot;
4243         info->init_buff_cleanup_start = &data_ptr[alloc_length];
4244         return data_ptr;
4245     } else {
4246         /* no pre-allocated mmap buffer. Call magic_mmap to allocate region. */
4247         return magic_mmap_positioned(type, name, parent_name
4248             , NULL, length, prot, flags, -1, 0, dsentry);
4249     }
4250 }
4251 
4252 PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages)
4253 {
4254     void *result;
4255     int len = num_pages * magic_get_sys_pagesize();
4256 
4257     if (USE_PRE_ALLOCATED_BUFFER(info)) {
4258         if (!st_pre_allocated_page_pt) {
4259 #if ST_DEBUG_LEVEL > 0
4260             printf("st_pages_allocate: initializing pre-allocated page buffer.\n");
4261 #endif
4262             st_pre_allocated_page_pt = &((char *)info->init_buff_start)[info->init_buff_len];
4263         }
4264         st_pre_allocated_page_pt -= len;
4265         assert(st_pre_allocated_page_pt >= (char *)info->init_buff_cleanup_start
4266             && "Temporary buffer ran into perminently pre-allocated mmapped pages.");
4267         return st_pre_allocated_page_pt;
4268     }
4269 
4270     result = st_cbs_os.alloc_contig(len, 0, NULL);
4271     if (result == NULL) {
4272         printf("st_pages_allocate: alloc_contig(%d) failed.\n", len);
4273         return NULL;
4274     }
4275 
4276     *phys = (uint32_t) NULL; /* we don't know or need the physical address in order to free */
4277 
4278     return result;
4279 }
4280 
4281 PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page)
4282 {
4283     st_alloc_pages *to_be_freed;
4284     int result;
4285 
4286     if (USE_PRE_ALLOCATED_BUFFER(info)) {
4287         /* nothing to do */
4288         return;
4289     }
4290 
4291     while (current_page != NULL) {
4292         to_be_freed = current_page;
4293         current_page = current_page->previous;
4294 
4295         result = st_cbs_os.free_contig(to_be_freed->virt_addr, to_be_freed->num_pages * magic_get_sys_pagesize());
4296 
4297         if (result != OK) {
4298             printf("munmap result != ok, using free()\n");
4299             /*
4300              * NOTE: in case this is moved out of a magic_* module it needs to be
4301              * manually annotated so it doesn't get instrumented.
4302              */
4303             free(to_be_freed->virt_addr);
4304         }
4305 
4306     }
4307 
4308 }
4309 
4310 PUBLIC void *st_buff_allocate(st_init_info_t *info, size_t size)
4311 {
4312     void *result;
4313 
4314     if (size > st_alloc_buff_available) {
4315 
4316         int pagesize = magic_get_sys_pagesize();
4317         uint32_t phys;
4318         st_alloc_pages *buff_previous_page = st_alloc_pages_current;
4319 
4320         /* calculate number of pages needed */
4321         int pages_needed = (size + sizeof(st_alloc_pages)) / pagesize;
4322         if ((size + sizeof(st_alloc_pages)) % pagesize)
4323             pages_needed++;
4324 
4325         /* allocate pages */
4326         st_alloc_pages_current
4327             = st_cbs.st_cb_pages_allocate(info, &phys, pages_needed);
4328 
4329         if (!st_alloc_pages_current) {
4330             printf("Could not allocate buffer.\n");
4331             return NULL;
4332         }
4333 
4334         /* set allocation struct */
4335         st_alloc_pages_current->virt_addr = st_alloc_pages_current;
4336         st_alloc_pages_current->phys_addr = phys;
4337         st_alloc_pages_current->num_pages = pages_needed;
4338         st_alloc_pages_current->previous = buff_previous_page;
4339 
4340         /* requested space is right after the struct */
4341         st_alloc_buff_pt = (char *) st_alloc_pages_current;
4342         st_alloc_buff_pt += sizeof(st_alloc_pages);
4343         /* subtract the struct size from the available buffer */
4344         st_alloc_buff_available = pages_needed * pagesize - sizeof(st_alloc_pages);
4345 
4346     }
4347 
4348     /* return current buffer pointer */
4349     result = st_alloc_buff_pt;
4350     /* set buffer pointer after space that is requested, ready for next allocation */
4351     st_alloc_buff_pt += size;
4352     /* adjust available space */
4353     st_alloc_buff_available -= size;
4354 
4355     return result;
4356 
4357 }
4358 
4359 PUBLIC void st_buff_cleanup(st_init_info_t *info)
4360 {
4361     st_cbs.st_cb_pages_free(info, st_alloc_pages_current);
4362     st_alloc_pages_current = NULL;
4363     st_alloc_buff_available = 0;
4364     st_alloc_buff_pt = NULL;
4365 }
4366 
4367 PUBLIC void st_cleanup(st_init_info_t *info)
4368 {
4369 
4370 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
4371     st_cleanup_rl_index(info, &st_cached_magic_vars);
4372     st_cleanup_rl_index(info, _magic_vars);
4373 #endif
4374 
4375 #if MAGIC_LOOKUP_SENTRY_ALLOW_NAME_HASH
4376     st_cleanup_sentry_hash(info, &st_cached_magic_vars);
4377     st_cleanup_sentry_hash(info, _magic_vars);
4378 #endif
4379 
4380 #if MAGIC_LOOKUP_FUNCTION_ALLOW_ADDR_HASH
4381     st_cleanup_function_hash(info, &st_cached_magic_vars);
4382     st_cleanup_function_hash(info, _magic_vars);
4383 #endif
4384 
4385 #if !ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
4386     assert(
4387         deallocate_nonxferred_dsentries(st_cached_magic_vars.first_dsentry,
4388             &st_counterparts) == OK &&
4389             "ERROR occurred during call to deallocate_nonxferred_dsentries().");
4390 #endif
4391 
4392     /*
4393      * Free all temporary allocated memory.
4394      */
4395     st_buff_cleanup(info);
4396 
4397     /*
4398      * Reset all values in case of successive state transfers.
4399      */
4400     st_init_done = FALSE;
4401     st_pre_allocated_page_pt = NULL;
4402     st_dsentry_buff = NULL;
4403     st_data_buff = NULL;
4404     st_num_type_transformations = 0;
4405     st_local_magic_vars_ptr = &_magic_vars_buff;
4406     st_policies = ST_POLICIES_DEFAULT;
4407     st_unpaired_types_ratio = ST_UNPAIRED_TYPES_RATIO_DEFAULT;
4408     st_unpaired_struct_types_ratio = ST_UNPAIRED_STRUCT_TYPES_RATIO_DEFAULT;
4409 
4410     /* Reallow mempool dsentries lookups. */
4411     magic_lookup_nested_dsentries = 1;
4412 }
4413 
4414 /* State cleanup/checking functions. */
4415 
4416 /*===========================================================================*
4417  *                         do_st_before_receive                              *
4418  *===========================================================================*/
4419 PUBLIC void do_st_before_receive()
4420 {
4421 /* Handle State transfer before receive events. */
4422   int num_violations;
4423 
4424   assert(st_state_checking_before_receive_is_enabled());
4425 
4426   num_violations = st_do_state_checking();
4427   if (__st_before_receive_sc_max_cycles < LONG_MAX) {
4428       __st_before_receive_sc_max_cycles--;
4429   }
4430   if (__st_before_receive_sc_max_violations < LONG_MAX) {
4431       __st_before_receive_sc_max_violations -= num_violations;
4432   }
4433   if (__st_before_receive_sc_max_cycles <= 0) {
4434       st_state_checking_before_receive_set_enabled(0, 0, 0);
4435       printf("Maximum number of cycles reached\n");
4436   }
4437   if (__st_before_receive_sc_max_violations <= 0) {
4438       st_state_checking_before_receive_set_enabled(0, 0, 0);
4439       printf("Maximum number of violations reached\n");
4440   }
4441 }
4442 
4443 /*===========================================================================*
4444  *                st_state_checking_before_receive_is_enabled                *
4445  *===========================================================================*/
4446 PUBLIC int st_state_checking_before_receive_is_enabled()
4447 {
4448     return __st_before_receive_enabled;
4449 }
4450 
4451 /*===========================================================================*
4452  *               st_state_checking_before_receive_set_enabled                *
4453  *===========================================================================*/
4454 PUBLIC int st_state_checking_before_receive_set_enabled(int enabled,
4455     int max_cycles, int max_violations)
4456 {
4457     int was_enabled = __st_before_receive_enabled;
4458     __st_before_receive_enabled = enabled;
4459     if (enabled) {
4460         if (max_cycles <= 0) {
4461             max_cycles = ST_STATE_CHECKING_DEFAULT_MAX_CYCLES;
4462         }
4463         if (max_violations <= 0) {
4464             max_violations = ST_STATE_CHECKING_DEFAULT_MAX_VIOLATIONS;
4465         }
4466         __st_before_receive_sc_max_cycles = max_cycles;
4467         __st_before_receive_sc_max_violations = max_violations;
4468         printf("Continuous state checking enabled, max cycles=%d, max violations=%d\n",
4469             max_cycles == LONG_MAX ? 0 : max_cycles,
4470             max_violations == LONG_MAX ? 0 : max_violations);
4471     }
4472     else {
4473         printf("Continuous state checking disabled\n");
4474     }
4475     return was_enabled;
4476 }
4477 
4478 /*===========================================================================*
4479  *                         st_cb_state_checking_wrapper                      *
4480  *===========================================================================*/
4481 PRIVATE int st_cb_state_checking_wrapper(_magic_selement_t* selement,
4482     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
4483     void* cb_args)
4484 {
4485     struct st_cb_info cb_info_buff;
4486     struct st_cb_info *cb_info = &cb_info_buff;
4487     int *num_violations = (int*) cb_args;
4488     int ret;
4489 
4490     cb_info->local_selements = NULL;
4491     cb_info->local_selement = NULL;
4492     cb_info->walk_flags = MAGIC_TYPE_WALK_DEFAULT_FLAGS;
4493     cb_info->st_cb_flags = ST_CB_CHECK_ONLY;
4494     cb_info->st_cb_saved_flags = NULL;
4495     cb_info->init_info = NULL;
4496 
4497     ret = transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info);
4498     if (ret < 0) {
4499         ret = st_cbs.st_cb_state_checking(selement, sel_analyzed, sel_stats, cb_args);
4500         (*num_violations)++;
4501     }
4502     return ret;
4503 }
4504 
4505 /*===========================================================================*
4506  *                         st_do_state_checking                              *
4507  *===========================================================================*/
4508 PUBLIC int st_do_state_checking()
4509 {
4510     int num_violations = 0;
4511     magic_sentries_analyze(ST_SEL_ANALYZE_FLAGS,
4512         st_cb_state_checking_wrapper, &num_violations, NULL);
4513     return num_violations;
4514 }
4515 
4516 /*===========================================================================*
4517  *                         st_cb_state_checking_null                         *
4518  *===========================================================================*/
4519 PUBLIC int st_cb_state_checking_null(_magic_selement_t* selement,
4520     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
4521     void* cb_args)
4522 {
4523     return EINTR;
4524 }
4525 
4526 /*===========================================================================*
4527  *                         st_cb_state_checking_print                        *
4528  *===========================================================================*/
4529 PUBLIC int st_cb_state_checking_print(_magic_selement_t* selement,
4530     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
4531     void* cb_args)
4532 {
4533     printf("%s. Found state violation:\n", st_cbs_os.debug_header());
4534     magic_sentry_print_el_cb(selement, sel_analyzed, sel_stats, cb_args);
4535     return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
4536 }
4537 
4538 /*===========================================================================*
4539  *                         st_cb_state_checking_panic                        *
4540  *===========================================================================*/
4541 PUBLIC int st_cb_state_checking_panic(_magic_selement_t* selement,
4542     _magic_sel_analyzed_t *sel_analyzed, _magic_sel_stats_t *sel_stats,
4543     void* cb_args)
4544 {
4545     st_cb_state_checking_print(selement, sel_analyzed, sel_stats, cb_args);
4546     st_cbs_os.panic("Time to panic...");
4547     return MAGIC_SENTRY_ANALYZE_STOP;
4548 }
4549 
4550 /*===========================================================================*
4551  *                         st_do_state_cleanup                               *
4552  *===========================================================================*/
4553 PUBLIC int st_do_state_cleanup()
4554 {
4555     return st_cbs.st_cb_state_cleanup();
4556 }
4557 
4558 /*===========================================================================*
4559  *                         st_cb_state_cleanup_null                          *
4560  *===========================================================================*/
4561 PUBLIC int st_cb_state_cleanup_null() {
4562     return OK;
4563 }
4564 
4565 #ifndef __MINIX
4566 /*===========================================================================*
4567  *                        st_msync_all_shm_dsentries                         *
4568  *===========================================================================*/
4569 PUBLIC void st_msync_all_shm_dsentries(void) {
4570     struct _magic_dsentry *prev_dsentry, *dsentry;
4571     struct _magic_sentry *sentry;
4572     MAGIC_DSENTRY_ALIVE_ITER(_magic_first_dsentry, prev_dsentry,
4573         dsentry, sentry,
4574 
4575         /*
4576          * TODO:
4577          * - Don't msync mmaps of /dev/zero
4578          */
4579         if (MAGIC_STATE_FLAGS(sentry, MAGIC_STATE_SHM | MAGIC_STATE_MAP) &&
4580             !(dsentry->alloc_mmap_flags & MAP_ANONYMOUS))
4581             msync(MAGIC_PTR_TO_DATA(dsentry), sentry->type->size,
4582                 MS_SYNC | MS_INVALIDATE);
4583 
4584     );
4585 }
4586 #endif
4587 
4588