Remove building with NOCRYPTO option
[minix.git] / minix / lib / libmagicrt / magic_st.c
blob086136f421d225417e217b45a0baa7fc69e1361d
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>
11 #define printf _magic_printf
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
21 #define DO_SKIP_INVARIANTS_VIOLATIONS 0
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;
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;
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;
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);
45 /* State transfer callbacks. */
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
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
66 /* State transfer prototypes for st_receive(). */
67 PUBLIC void do_st_before_receive(void);
69 /* Callback setters */
71 PUBLIC void st_setcb_pages_allocate (st_cb_pages_allocate_t cb)
73 assert(cb != NULL);
74 st_cbs.st_cb_pages_allocate = cb;
77 PUBLIC void st_setcb_pages_free (st_cb_pages_free_t cb)
79 assert(cb != NULL);
80 st_cbs.st_cb_pages_free = cb;
83 PUBLIC void st_setcb_state_cleanup (st_cb_state_cleanup_t cb)
85 assert(cb != NULL);
86 st_cbs.st_cb_state_cleanup = cb;
87 magic_setcb_sentries_analyze_pre(cb);
90 PUBLIC void st_setcb_state_checking (st_cb_state_checking_t cb)
92 assert(cb != NULL);
93 st_cbs.st_cb_state_checking = cb;
96 PUBLIC void st_setcb_selement_map(st_cb_selement_map_t cb)
98 assert(cb != NULL);
99 st_cbs.st_cb_selement_map = cb;
102 PUBLIC void st_setcb_selement_transfer(st_cb_selement_transfer_t cb, int flags)
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;
115 assert(is_registered && "Number of registered callbacks exceeds MAX_NUM_CBS");
120 /* OS Callback setters. */
122 PUBLIC void st_setcb_os_panic(st_cb_os_panic_t cb)
124 assert(cb != NULL && "No callback defined for panic().");
125 st_cbs_os.panic = cb;
128 PUBLIC void st_setcb_os_old_state_table_lookup(st_cb_os_old_state_table_lookup_t cb)
130 assert(cb != NULL && "No callback defined for old_state_table_lookup().");
131 st_cbs_os.old_state_table_lookup = cb;
134 PUBLIC void st_setcb_os_copy_state_region(st_cb_os_copy_state_region_t cb)
136 assert(cb != NULL && "No callback defined for copy_state_region().");
137 st_cbs_os.copy_state_region = cb;
140 PUBLIC void st_setcb_os_alloc_contig(st_cb_os_alloc_contig_t cb)
142 assert(cb != NULL && "No callback defined for alloc_contig().");
143 st_cbs_os.alloc_contig = cb;
146 PUBLIC void st_setcb_os_free_contig(st_cb_os_free_contig_t cb)
148 assert(cb != NULL && "No callback defined for free_contig().");
149 st_cbs_os.free_contig = cb;
152 PUBLIC void st_setcb_os_debug_header(st_cb_os_debug_header_t cb)
154 assert(cb != NULL && "No callback defined for debug_header().");
155 st_cbs_os.debug_header = cb;
159 PUBLIC void st_setcb_os_all(struct st_cbs_os_t *cbs)
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);
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;
174 /* Typedef registration and lookup */
176 int st_strcmp_wildcard(const char *with_wildcard, const char *without_wildcard)
178 /* Note: this implementation only supports basic regexes with a '*'
179 * at the beginning or the end of the string.
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;
191 return strncmp(with_wildcard+1, match_without_wildcard, len);
193 return strncmp(with_wildcard, without_wildcard, star - with_wildcard);
195 return strcmp(with_wildcard, without_wildcard);
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 };
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 };
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 };
226 const char *st_typename_key_registrations[MAX_NUM_TYPENAMES];
228 static int is_typename(const char *search_key, struct _magic_type *type)
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;
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;
242 /* No match is found */
243 return FALSE;
246 PUBLIC void st_register_typename_key(const char *key)
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;
256 assert(is_registered && "Error, number of typename registrations > MAX_NUM_TYPENAMES.\n");
259 PUBLIC void st_register_typename_keys(const char **keys)
261 int i = 0;
262 while (keys[i] != NULL) {
263 st_register_typename_key(keys[i]);
264 i++;
268 PRIVATE void set_typename_key(struct _magic_type *type)
270 const char **registration = st_typename_key_registrations;
272 while (*registration != NULL) {
273 if (is_typename(*registration, type)) {
274 type->ext = *registration;
275 break;
277 registration++;
281 PRIVATE void register_typenames(void)
284 int i;
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);
293 for(i = 0 ; i < _magic_types_num ; i++) {
294 set_typename_key(&_magic_types[i]);
299 PRIVATE INLINE void register_typenames_and_callbacks(void)
302 static int st_is_registered = FALSE;
303 if(st_is_registered) {
304 return;
307 register_typenames();
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);
312 st_is_registered = TRUE;
316 PRIVATE int st_type_name_match_any(const char **registered_type_name_keys,
317 const char *key)
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;
324 i++;
326 return FALSE;
329 PRIVATE int st_sentry_name_match_any(const char **sentry_wildcard_names,
330 const char *name)
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;
337 i++;
339 return FALSE;
342 PRIVATE int st_dsentry_parent_name_match_any(const char **wildcard_names,
343 const char *name)
345 int i = 0;
346 while (wildcard_names[i] != NULL) {
347 if (ST_DSENTRY_PARENT_NAME_MATCH(wildcard_names[i], name)) {
348 return TRUE;
350 i++;
352 return FALSE;
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)
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");
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)
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;
379 /* Stack management. */
381 PUBLIC void st_stack_refs_save_restore(char* stack_buff, int is_save)
383 struct _magic_dsentry *prev_dsentry, *dsentry;
384 struct _magic_sentry* sentry;
385 struct st_stack_refs_buff *buff_ptr;
386 int i;
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
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;
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);
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));
410 return;
413 /* Restore. */
414 if (_magic_first_dsentry == _magic_last_stack_dsentry) {
415 _magic_first_dsentry = buff_ptr->last_stack_dsentry;
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;
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;
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));
438 /* Metadata management. */
439 PUBLIC int st_add_special_mmapped_region(void *address, size_t size,
440 const char* name)
442 struct _magic_obdsentry* obdsentry;
443 char addr_name[24];
445 if (!_magic_enabled) return OK;
447 if (!name) {
448 snprintf(addr_name, sizeof(addr_name), "%%MMAP_0x%08x",
449 (unsigned int) address);
450 name = addr_name;
452 obdsentry = magic_create_obdsentry(address, MAGIC_VOID_TYPE,
453 size, MAGIC_STATE_MAP, name, NULL);
454 return obdsentry ? OK : EINVAL;
457 PUBLIC int st_del_special_mmapped_region_by_addr(void *address)
459 int ret;
461 if (!_magic_enabled) return OK;
463 ret = magic_destroy_obdsentry_by_addr(address);
464 if (ret < 0) {
465 return EINVAL;
467 return OK;
470 /* Selement transfer callbacks. */
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)
474 /* Do nothing for complex type. process only its members, not the complex type itself */
475 return MAGIC_SENTRY_ANALYZE_CONTINUE;
478 PRIVATE INLINE int transfer_try_raw_copy_sel_cb(_magic_selement_t *selement, struct st_cb_info *cb_info)
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;
486 return MAGIC_SENTRY_ANALYZE_CONTINUE;
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)
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;
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!");
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;
505 cb_info->st_cb_flags |= ST_CB_FORCE_IXFER;
506 return MAGIC_SENTRY_ANALYZE_CONTINUE;
508 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
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)
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);
522 return r;
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)
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;
531 return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
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;
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;
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);
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));
557 /* Force code below to transfer the pointer normally. */
558 trg_transferred = TRUE;
561 if (trg_transferred && trg_paired) {
562 *local_selement_address = local_trg_selement.address;
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;
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("");
573 else {
574 *local_selement_address = NULL;
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);
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);
584 else {
585 ST_CB_PRINT(ST_CB_ERR, "uncaught ptr lookup for unpaired target", selement, sel_analyzed, sel_stats, cb_info);
587 #if DO_SKIP_UNPAIRED_PTR_TARGETS
588 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
589 #else
590 return ENOENT;
591 #endif
594 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
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)
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;
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);
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) {
612 /* NULL pointer or special value. Don't adjust value */
613 return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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);
621 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
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.
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;
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
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
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)
651 static int st_counter = 0;
652 unsigned parent_offset, offset;
653 int walk_flags, ret;
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;
659 if (selement->type->type_id == MAGIC_TYPE_STRUCT || st_counter > 0) {
660 return MAGIC_SENTRY_ANALYZE_CONTINUE;
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;
678 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
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)
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;
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;
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);
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);
709 /* Not reachable. */
710 ST_CB_PRINT(ST_CB_ERR, "Bug!", selement, sel_analyzed, sel_stats, cb_info);
711 return EINTR;
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)
716 const char *sentry_name = selement->sentry->name;
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;
723 #endif
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);
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);
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;
740 /* Skip memory management related sentries only when memory functions have
741 * been instrumented (which is *not* the case for the MINIX3 VM service).
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;
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);
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;
761 return ST_CB_NOT_PROCESSED;
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)
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);
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);
775 if (ST_TYPE_NAME_MATCH_ANY(st_typename_noxfers, typename_key)) {
776 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
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);
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);
787 return ST_CB_NOT_PROCESSED;
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)
792 return transfer_walkable_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
797 return transfer_ptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
802 return transfer_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
807 return transfer_cond_identity_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
812 return transfer_nonptr_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
817 return transfer_struct_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
822 return default_transfer_selement_sel_cb(selement, sel_analyzed, sel_stats, cb_info);
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)
827 return transfer_data_selement(selement, sel_analyzed, sel_stats, cb_info);
830 /* Selement mapping functions and callbacks. */
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)
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;
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;
861 if (address == selement_address && type == selement->type) {
862 return MAGIC_TYPE_WALK_STOP;
864 if (type->num_child_types == 0) {
865 return EINVAL;
867 local_selement->parent_type = local_selement->type;
868 local_selement->parent_address = local_selement->address;
869 return MAGIC_TYPE_WALK_CONTINUE;
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)
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;
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)
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;
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;
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;
927 address = lsel->address;
929 assert(local_sel_analyzed->u.ptr.num_trg_types > 0);
933 PUBLIC void st_map_local_selement_from_child_num(_magic_selement_t *local_selement, struct st_cb_info *cb_info, int child_num)
935 local_selement->child_num = child_num;
936 magic_selement_fill_from_parent_info(local_selement, cb_info->walk_flags);
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)
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;
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;
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;
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);
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);
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;
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);
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)
982 size_t cached_size = cached_selement->type->num_child_types, local_size = local_selement->type->num_child_types;
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;
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;
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);
1004 else {
1005 report = is_string ? (st_policies & ST_REPORT_LARGER_STRINGS) : (st_policies & ST_REPORT_LARGER_ARRAYS);
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");
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)
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);
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)
1024 /* Match unions just like structs. */
1025 st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
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)
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;
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;
1046 local_selement->type = NULL;
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)
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;
1059 /* Match struct/unions by name(s). */
1060 if (!strcmp(cached_type->name, local_type->name)) {
1061 return;
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;
1073 local_selement->type = NULL;
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)
1078 int r;
1079 static char magic_value_buffer[32];
1081 r = magic_selement_value_cast(cached_selement, local_selement, magic_value_buffer);
1082 if (r == 0) {
1083 return;
1085 if (r < 0 && r != MAGIC_ERANGE && r != MAGIC_ESIGN) {
1086 local_selement->type = NULL;
1087 return;
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");
1100 cached_selement->address = magic_value_buffer;
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)
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;
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;
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;
1120 default:
1121 st_cbs_os.panic("Invalid parent type!");
1122 break;
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)
1128 assert(cached_selement->type);
1129 if (local_selement->type == NULL) {
1130 return;
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;
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;
1142 case MAGIC_TYPE_UNION:
1143 st_cb_map_child_union_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1144 break;
1146 case MAGIC_TYPE_STRUCT:
1147 st_cb_map_child_struct_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
1148 break;
1150 default:
1151 st_cbs_os.panic("Invalid parent type!");
1152 break;
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)
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);
1165 st_cb_map_child_selement_generic(cached_selement, local_selement, cb_info, is_trg_mapping);
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)
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;
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;
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;
1187 else {
1188 local_selement->type = NULL;
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;
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!");
1202 #endif
1204 st_num_type_transformations++;
1205 st_cbs.st_cb_selement_map(cached_selement, local_selement, cb_info, is_trg_mapping);
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;
1215 /* main functions */
1217 PUBLIC int st_state_transfer(st_init_info_t *info)
1219 int r;
1222 * Set all OS dependent callbacks first.
1224 st_setcb_os_all(&info->st_cbs_os);
1226 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
1227 _magic_vars->fake_malloc = 1;
1228 #endif
1230 r = st_init(info);
1232 #if ST_ASSUME_RAW_COPY_BEFORE_TRANSFER
1233 _magic_vars->fake_malloc = 0;
1234 #endif
1236 if (r != OK) {
1237 return r;
1240 r = st_data_transfer(info);
1241 if (r != OK) {
1242 return r;
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
1249 st_cleanup(info);
1251 return OK;
1254 #if APPARENTLY_UNUSED
1255 PUBLIC void st_set_policies(int policies)
1257 st_policies = policies;
1259 #endif
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)
1265 size_t buff_size;
1266 void *buff;
1268 EXEC_WITH_MAGIC_VARS(
1269 buff_size = magic_sentry_rl_estimate_index_buff_size(0);
1270 , magic_vars
1272 buff = st_buff_allocate(info, buff_size);
1274 EXEC_WITH_MAGIC_VARS(
1275 magic_sentry_rl_build_index(buff, buff_size);
1276 , magic_vars
1280 PRIVATE void st_cleanup_rl_index(st_init_info_t *info,
1281 struct _magic_vars_t *magic_vars)
1283 EXEC_WITH_MAGIC_VARS(
1284 magic_sentry_rl_destroy_index();
1285 , magic_vars
1288 #endif
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)
1294 size_t buff_size;
1295 void *buff;
1297 EXEC_WITH_MAGIC_VARS(
1298 buff_size = magic_sentry_hash_estimate_buff_size(0);
1299 , magic_vars
1301 buff = st_buff_allocate(info, buff_size);
1303 EXEC_WITH_MAGIC_VARS(
1304 magic_sentry_hash_build(buff, buff_size);
1305 , magic_vars
1309 PRIVATE void st_cleanup_sentry_hash(st_init_info_t *info,
1310 struct _magic_vars_t *magic_vars)
1312 EXEC_WITH_MAGIC_VARS(
1313 magic_sentry_hash_destroy();
1314 , magic_vars
1317 #endif
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)
1323 size_t buff_size;
1324 void *buff;
1326 EXEC_WITH_MAGIC_VARS(
1327 buff_size = magic_function_hash_estimate_buff_size(0);
1328 , magic_vars
1330 buff = st_buff_allocate(info, buff_size);
1332 EXEC_WITH_MAGIC_VARS(
1333 magic_function_hash_build(buff, buff_size);
1334 , magic_vars
1338 PRIVATE void st_cleanup_function_hash(st_init_info_t *info,
1339 struct _magic_vars_t *magic_vars)
1341 EXEC_WITH_MAGIC_VARS(
1342 magic_function_hash_destroy();
1343 , magic_vars
1346 #endif
1348 PRIVATE void st_vars_clear_ptrs(struct _magic_vars_t *magic_vars)
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;
1356 for (i = 0 ; i < sizeof(offset_list) / sizeof(size_t) ; i++)
1357 *((void **)(((char *)magic_vars) + offset_list[i])) = NULL;
1361 #ifdef __MINIX
1362 PRIVATE void st_unmap_mem(struct _magic_vars_t *magic_vars)
1364 int i, r;
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);
1379 #endif
1381 PUBLIC int st_init(st_init_info_t *info)
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;
1389 if (!_magic_enabled) return ENOSYS;
1390 st_init_done = TRUE;
1392 /* Ignore nested mempool dsentries for now. */
1393 magic_lookup_nested_dsentries = 0;
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;
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
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();
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.");
1414 * Clear all pointers not explictly transferred, as they are not valid in
1415 * the new address space.
1417 st_vars_clear_ptrs(&st_remote_magic_vars);
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.
1424 st_cached_magic_vars = st_remote_magic_vars;
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.");
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;
1444 st_data_buff = &st_dsentry_buff[1];
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.");
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.");
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.");
1463 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
1464 st_init_rl_index(info, &st_cached_magic_vars);
1465 #endif
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
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
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
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
1497 /* Set state transfer status defaults from the predefined policies. */
1498 st_set_status_defaults(info);
1500 #if MAGIC_LOOKUP_SENTRY_ALLOW_RANGE_INDEX
1501 st_init_rl_index(info, _magic_vars);
1502 #endif
1504 return OK;
1507 PRIVATE INLINE char* st_lookup_str_local_data(struct _magic_sentry *cached_sentry)
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;
1516 #if ST_DEBUG_DATA_TRANSFER
1517 PRIVATE void st_print_sentities(struct _magic_vars_t *magic_vars)
1519 struct _magic_dsentry *dsentry = magic_vars->first_dsentry;
1520 int i;
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");
1528 while (dsentry != NULL) {
1529 ST_DSENTRY_PRINT(dsentry, 0);
1530 printf("\n");
1531 dsentry = dsentry->next;
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");
1540 #endif
1542 PUBLIC void st_map_str_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
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));
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;
1566 if (!match_by_content) {
1567 /* No match. */
1568 return;
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
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;
1586 *cached_sentry_ptr = cached_sentry;
1587 *local_sentry_ptr = local_sentry;
1590 PUBLIC void st_map_sentries(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
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));
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;
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
1609 assert(!local_sentry || MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC));
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
1616 assert(!cached_sentry || MAGIC_STATE_FLAG(local_sentry, MAGIC_STATE_DYNAMIC) == MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC));
1618 *cached_sentry_ptr = cached_sentry;
1619 *local_sentry_ptr = local_sentry;
1622 PRIVATE struct _magic_sentry *st_lookup_cached_sentry(struct _magic_sentry *local_sentry)
1624 int i;
1625 struct _magic_dsentry *cached_dsentry;
1626 assert(local_sentry);
1628 for (i = 0 ; i < st_counterparts.sentries_size ; i++) {
1629 if (st_counterparts.sentries[i].counterpart == local_sentry) {
1630 break;
1633 if (i >= st_counterparts.sentries_size) {
1634 return NULL;
1636 if (i < st_cached_magic_vars.sentries_num) {
1637 return &st_cached_magic_vars.sentries[i];
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--;
1648 return MAGIC_DSENTRY_TO_SENTRY(cached_dsentry);
1651 PUBLIC void st_lookup_sentry_pair(struct _magic_sentry **cached_sentry_ptr, struct _magic_sentry **local_sentry_ptr)
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));
1658 if (cached_sentry) {
1659 ST_GET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
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;
1672 else {
1673 cached_sentry = st_lookup_cached_sentry(local_sentry);
1675 *cached_sentry_ptr = cached_sentry;
1676 *local_sentry_ptr = local_sentry;
1679 PRIVATE INLINE void st_unpair_local_alloc_sentry(struct _magic_sentry *local_sentry)
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!");
1684 else if (st_policies & ST_ON_ALLOC_UNPAIR_DEALLOCATE) {
1685 deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry));
1689 PUBLIC void st_add_sentry_pair(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry)
1691 ST_CHECK_INIT();
1692 assert(cached_sentry || local_sentry);
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);
1700 if (!cached_sentry && MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
1701 st_unpair_local_alloc_sentry(local_sentry);
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);
1710 ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
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)
1716 int r;
1717 struct _magic_dsentry *local_dsentry;
1718 ST_CHECK_INIT();
1719 assert(cached_sentry);
1721 if (!local_dsindex) {
1722 st_add_sentry_pair(cached_sentry, NULL);
1723 return OK;
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;
1730 st_add_sentry_pair(cached_sentry, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
1731 return OK;
1734 PUBLIC void st_map_functions(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr)
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));
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
1747 else {
1748 EXEC_WITH_MAGIC_VARS(
1749 cached_function = magic_function_lookup_by_name(NULL, local_function->name);
1750 , &st_cached_magic_vars
1753 *cached_function_ptr = cached_function;
1754 *local_function_ptr = local_function;
1757 PUBLIC void st_lookup_function_pair(struct _magic_function **cached_function_ptr, struct _magic_function **local_function_ptr)
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));
1765 if (cached_function) {
1766 if ((int)cached_function->id - 1 >= st_counterparts.functions_size) {
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.
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;
1781 assert(local_function != NULL && "No counterpart found for function.");
1782 } else {
1783 ST_GET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
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;
1795 *cached_function_ptr = cached_function;
1796 *local_function_ptr = local_function;
1799 PUBLIC void st_add_function_pair(struct _magic_function *cached_function, struct _magic_function *local_function)
1801 ST_CHECK_INIT();
1802 assert(cached_function || local_function);
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);
1811 if (cached_function) {
1812 ST_SET_CACHED_COUNTERPART(cached_function, functions, functions, local_function);
1816 PUBLIC int st_sentry_equals(struct _magic_sentry *cached_sentry, struct _magic_sentry *local_sentry)
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;
1824 if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_STRING)) {
1825 return !strcmp(st_lookup_str_local_data(cached_sentry), (char*)local_sentry->address);
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;
1831 if (strcmp(cached_sentry->name, local_sentry->name) || strcmp(cached_parent_name, local_parent_name)) {
1832 return FALSE;
1834 return magic_type_compatible(cached_sentry->type, local_sentry->type, MAGIC_TYPE_COMPARE_ALL);
1837 PUBLIC int st_function_equals(struct _magic_function *cached_function, struct _magic_function *local_function)
1839 if (MAGIC_STATE_FLAGS_TO_NONEXTF(local_function->flags) != MAGIC_STATE_FLAGS_TO_NONEXTF(cached_function->flags)) {
1840 return FALSE;
1842 return !strcmp(cached_function->name, local_function->name);
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)
1847 int is_paired_sentry;
1848 ST_CHECK_INIT();
1850 if (!cached_sentry || !local_sentry) {
1851 if (raw_diff) {
1852 st_map_sentries(&cached_sentry, &local_sentry);
1854 else {
1855 st_lookup_sentry_pair(&cached_sentry, &local_sentry);
1858 is_paired_sentry = (cached_sentry != NULL && local_sentry != NULL);
1859 if (is_paired_sentry && st_sentry_equals(cached_sentry, local_sentry)) {
1860 return;
1862 if (is_paired_sentry && !print_changed) {
1863 return;
1865 if (cached_sentry) {
1866 printf("-"); ST_SENTRY_PRINT(cached_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n");
1868 if (local_sentry) {
1869 printf("+"); ST_SENTRY_PRINT(local_sentry, MAGIC_EXPAND_TYPE_STR); printf("\n");
1871 printf("\n");
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)
1876 int is_paired_function;
1877 ST_CHECK_INIT();
1879 if (!cached_function || !local_function) {
1880 if (raw_diff) {
1881 st_map_functions(&cached_function, &local_function);
1883 else {
1884 st_lookup_function_pair(&cached_function, &local_function);
1887 is_paired_function = (cached_function != NULL && local_function != NULL);
1888 if (is_paired_function && st_function_equals(cached_function, local_function)) {
1889 return;
1891 if (is_paired_function && !print_changed) {
1892 return;
1894 if (cached_function) {
1895 printf("-"); ST_FUNCTION_PRINT(cached_function, MAGIC_EXPAND_TYPE_STR); printf("\n");
1897 if (local_function) {
1898 printf("+"); ST_FUNCTION_PRINT(local_function, MAGIC_EXPAND_TYPE_STR); printf("\n");
1900 printf("\n");
1903 PUBLIC void st_print_sentries_diff(st_init_info_t *info, int raw_diff, int print_changed)
1905 int i;
1906 ST_CHECK_INIT();
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);
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);
1920 PUBLIC void st_print_dsentries_diff(st_init_info_t *info, int raw_diff, int print_changed)
1922 struct _magic_dsentry *dsentry;
1923 ST_CHECK_INIT();
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;
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;
1941 PUBLIC void st_print_functions_diff(st_init_info_t *info, int raw_diff, int print_changed)
1943 int i;
1944 ST_CHECK_INIT();
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);
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);
1958 PUBLIC void st_print_state_diff(st_init_info_t *info, int raw_diff, int print_changed)
1960 ST_CHECK_INIT();
1962 printf("Index: sentries\n");
1963 printf("===================================================================\n");
1964 st_print_sentries_diff(info, raw_diff, print_changed);
1966 printf("\nIndex: dsentries\n");
1967 printf("===================================================================\n");
1968 st_print_dsentries_diff(info, raw_diff, print_changed);
1970 printf("\nIndex: functions\n");
1971 printf("===================================================================\n");
1972 st_print_functions_diff(info, raw_diff, print_changed);
1973 printf("\n");
1976 PUBLIC int st_data_transfer(st_init_info_t *info)
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();
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;
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;
2009 dsentry = dsentry->next;
2012 /* Data transfer. */
2013 do {
2014 sentry_transferred = 0;
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
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;
2034 sentry_transferred = 1;
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;
2052 sentry_transferred = 1;
2054 dsentry = dsentry->next;
2057 } while(sentry_transferred);
2059 return OK;
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)
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; \
2087 if (cached_sentry) {
2088 __st_set_transfer_status(cached_sentry);
2090 else {
2091 assert(cached_function);
2092 __st_set_transfer_status(cached_function);
2096 PUBLIC void st_set_unpaired_types_ratios(float unpaired_types_ratio,
2097 float unpaired_struct_types_ratio)
2099 st_unpaired_types_ratio = unpaired_types_ratio;
2100 st_unpaired_struct_types_ratio = unpaired_struct_types_ratio;
2103 PUBLIC void st_set_status_defaults(st_init_info_t *info)
2105 int match_all = ~0, skip_none = 0;
2106 int skip_state_flags = (st_policies & ST_DEFAULT_SKIP_STACK) ? MAGIC_STATE_STACK : 0;
2108 if (!(st_policies & ST_DEFAULT_TRANSFER_NONE)) {
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.
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) {
2118 * If requested, mark non-stack dsentries for cascade transfer
2119 * instead of regular transfer.
2121 st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET,
2122 MAGIC_STATE_HEAP | MAGIC_STATE_MAP, skip_none);
2125 else {
2127 * Don't transfer any (d)sentries by default. Mark all the (d)sentries
2128 * for cascade transfer (except for stack dsentries when requested).
2130 st_set_status_by_state_flags(ST_ON_PTRXFER_CASCADE, ST_OP_SET,
2131 match_all, skip_state_flags);
2135 * Always transfer all immutable objects.
2137 st_set_status_by_state_flags(ST_NEEDS_TRANSFER, ST_OP_SET,
2138 MAGIC_STATE_IMMUTABLE, skip_none);
2141 * If requested, mark library state dsentries as already transferred too.
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);
2149 * In addition, mark functions, out-of-band/string sentries
2150 * and shared dsentries as already transferred.
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);
2157 * Finally, if we only want to transfer dirty sentries, mark all the other ones
2158 * as already transferred.
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);
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
2172 PUBLIC void st_set_status_by_state_flags(int status_flags, int status_op,
2173 int match_state_flags, int skip_state_flags)
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();
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);
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);
2199 dsentry = dsentry->next;
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]);
2214 PUBLIC int st_set_status_by_function_ids(int status_flags, int status_op, _magic_id_t *ids)
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;
2222 i++;
2224 return OK;
2227 PUBLIC int st_set_status_by_sentry_ids(int status_flags, int status_op, _magic_id_t *ids)
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;
2235 i++;
2237 return OK;
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)
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;
2253 i++;
2255 return OK;
2258 PUBLIC int st_set_status_by_local_addrs(int status_flags, int status_op,
2259 void **addrs)
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;
2267 i++;
2269 return OK;
2272 PUBLIC void st_set_status_by_sentry(int status_flags, int status_op,
2273 void *cached_sentry)
2275 ST_CHECK_INIT();
2277 st_set_transfer_status(status_flags, status_op,
2278 (struct _magic_sentry*) cached_sentry, NULL);
2281 PUBLIC void st_set_status_by_function(int status_flags, int status_op,
2282 void *cached_function)
2284 ST_CHECK_INIT();
2286 st_set_transfer_status(status_flags, status_op,
2287 NULL, (struct _magic_function*) cached_function);
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)
2293 struct _magic_sentry *cached_sentry = NULL;
2294 struct _magic_function *cached_function = NULL;
2295 ST_CHECK_INIT();
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);
2302 , &st_cached_magic_vars
2304 if (!cached_sentry && !cached_function) {
2305 return ENOENT;
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;
2312 * Alloc sentries may have multiple instances with the same name.
2313 * Use the site_id to distinguish between them.
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);
2321 return OK;
2324 PUBLIC int st_set_status_by_function_id(int status_flags, int status_op,
2325 _magic_id_t id)
2327 struct _magic_function *cached_function = NULL;
2328 ST_CHECK_INIT();
2330 EXEC_WITH_MAGIC_VARS(
2331 cached_function = magic_function_lookup_by_id(id, NULL);
2332 , &st_cached_magic_vars
2335 if (!cached_function) {
2336 return ENOENT;
2339 st_set_transfer_status(status_flags, status_op, NULL, cached_function);
2340 return OK;
2343 PUBLIC int st_set_status_by_sentry_id(int status_flags, int status_op,
2344 _magic_id_t id)
2346 struct _magic_sentry *cached_sentry = NULL;
2347 ST_CHECK_INIT();
2349 EXEC_WITH_MAGIC_VARS(
2350 cached_sentry = magic_sentry_lookup_by_id(id, NULL);
2351 , &st_cached_magic_vars
2354 if (!cached_sentry) {
2355 return ENOENT;
2358 st_set_transfer_status(status_flags, status_op, cached_sentry, NULL);
2359 return OK;
2362 PUBLIC int st_set_status_by_local_addr(int status_flags, int status_op,
2363 void *addr)
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();
2371 sentry = magic_sentry_lookup_by_addr(addr, NULL);
2372 if (!sentry) {
2373 function = magic_function_lookup_by_addr(addr, NULL);
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);
2380 else if (function && !MAGIC_STATE_FLAG(function, MAGIC_STATE_DYNAMIC)) {
2381 name = function->name;
2382 parent_name = MAGIC_FUNCTION_PARENT(function);
2384 else {
2385 return ENOENT;
2387 st_set_status_by_name(status_flags, status_op, parent_name, name, dsentry_site_id);
2388 return OK;
2391 PUBLIC int st_pair_by_function_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op)
2393 int r, i=0;
2394 ST_CHECK_INIT();
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;
2402 i++;
2404 return OK;
2407 PUBLIC int st_pair_by_sentry_ids(unsigned long *cached_ids, unsigned long *local_ids, int status_flags, int status_op)
2409 int r, i=0;
2410 ST_CHECK_INIT();
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;
2418 i++;
2420 return OK;
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)
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;
2437 i++;
2439 return OK;
2442 PUBLIC void st_pair_by_sentry(void *cached_sentry, void *local_sentry, int status_flags, int status_op)
2444 ST_CHECK_INIT();
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);
2452 PUBLIC void st_pair_by_function(void *cached_function, void* local_function, int status_flags, int status_op)
2454 ST_CHECK_INIT();
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);
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)
2464 int r;
2465 ST_CHECK_INIT();
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;
2471 if (cached_sentry) {
2472 st_set_status_by_sentry(status_flags, status_op, cached_sentry);
2474 return OK;
2477 PUBLIC int st_pair_by_function_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op)
2479 struct _magic_function *cached_function = NULL, *local_function = NULL;
2480 ST_CHECK_INIT();
2481 assert(cached_id || local_id);
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
2488 if (!cached_function) {
2489 return ENOENT;
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
2497 if (!local_function) {
2498 return ENOENT;
2502 st_pair_by_function(cached_function, local_function, status_flags, status_op);
2503 return OK;
2506 PUBLIC int st_pair_by_sentry_id(unsigned long cached_id, unsigned long local_id, int status_flags, int status_op)
2508 struct _magic_sentry *cached_sentry = NULL, *local_sentry = NULL;
2509 ST_CHECK_INIT();
2510 assert(cached_id || local_id);
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
2517 if (!cached_sentry) {
2518 return ENOENT;
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
2526 if (!local_sentry) {
2527 return ENOENT;
2531 st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
2532 return OK;
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)
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);
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;
2550 if (!cached_sentry) {
2551 cached_function = magic_function_lookup_by_name(NULL, cached_name);
2553 , &st_cached_magic_vars
2555 if (!cached_sentry && !cached_function) {
2556 return ENOENT;
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;
2567 if (!cached_sentry && !local_sentry) {
2568 local_function = magic_function_lookup_by_name(NULL, local_name);
2570 , st_local_magic_vars_ptr
2572 if (!local_sentry && !local_function) {
2573 return ENOENT;
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;
2581 assert(cached_sentry || local_sentry);
2582 st_pair_by_sentry(cached_sentry, local_sentry, status_flags, status_op);
2583 return OK;
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)
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;
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)
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)));
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;
2616 , &st_cached_magic_vars
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;
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;
2631 if (local_sentry) assert(local_dsindex);
2632 is_local_alloc = is_local_alloc || local_dsindex != NULL;
2634 , st_local_magic_vars_ptr
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;
2642 return ENOENT;
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;
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;
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);
2667 if (!cached_sentry) {
2668 return OK;
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);
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;
2688 return OK;
2691 /* Metadata transfer and adjustment functions */
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)
2699 int i;
2700 struct _magic_function *cached_function;
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));
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];
2712 return OK;
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)
2721 struct _magic_dfunction **dfunction_ptr;
2722 struct _magic_dfunction *cached_dfunction, *prev_dfunction = NULL;
2723 struct _magic_function *cached_function;
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;
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;
2739 } else {
2740 printf("ERROR. dfunction->parent_name == NULL.\n");
2741 return EGENERIC;
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];
2749 if (cached_dfunction->prev != NULL)
2750 cached_dfunction->prev = prev_dfunction;
2752 dfunction_ptr = &cached_dfunction->next;
2753 prev_dfunction = cached_dfunction;
2756 cached_magic_vars->last_dfunction = prev_dfunction;
2758 return OK;
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)
2766 int i;
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));
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;
2777 set_typename_key(&cached_magic_vars->types[i]);
2780 return OK;
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)
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;
2791 num_elements++;
2792 MD_TRANSFER(info, type->value_set, (void **)&type->value_set, num_elements *sizeof(int));
2793 return OK;
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)
2798 int r;
2799 int num_child = MAGIC_TYPE_NUM_CONTAINED_TYPES(type), i;
2801 MD_TRANSFER_STR(info, &type->name);
2802 MD_TRANSFER_STR(info, &type->type_str);
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]);
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]); \
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
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))
2838 printf("ERROR transferring compatible types array metadata.\n");
2839 return EGENERIC;
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]);
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]);
2860 if (num_child>0 && type->member_offsets != NULL) {
2861 MD_TRANSFER(info, type->member_offsets, (void **)&type->member_offsets, num_child * sizeof(unsigned));
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;
2870 return OK;
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)
2878 int i;
2879 int skipped_sentries = 0;
2880 struct _magic_sentry *cached_sentry;
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 */
2887 /* adjust sentries */
2888 for (i = 0 ; i < cached_magic_vars->sentries_num ; i++) {
2889 cached_sentry = &cached_magic_vars->sentries[i];
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;
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];
2906 if (transfer_metadata_sentry_members(info, cached_sentry)) {
2907 printf("ERROR transferring sentry members metadata.\n");
2908 return EGENERIC;
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.
2915 cached_sentry->type = &cached_magic_vars->types[cached_sentry->type - remote_magic_vars->types];
2917 if (cached_sentry->type->size > *max_buff_sz) {
2918 *max_buff_sz = cached_sentry->type->size;
2922 if (skipped_sentries > 0)
2923 cached_magic_vars->sentries_num -= skipped_sentries;
2925 return OK;
2928 PRIVATE int transfer_metadata_sentry_members(st_init_info_t *info, struct _magic_sentry *sentry)
2930 if (sentry->name != NULL) {
2931 MD_TRANSFER_STR(info, &sentry->name);
2932 } else {
2933 printf("ERROR. sentry->name == NULL.\n");
2934 return EGENERIC;
2936 return OK;
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)
2943 struct _magic_dsentry **dsentry_ptr;
2944 #if MAGIC_DSENTRY_ALLOW_PREV
2945 struct _magic_dsentry *prev_dsentry = NULL;
2946 #endif
2947 int r;
2949 *dsentries_num = 0;
2951 cached_magic_vars->first_dsentry = remote_magic_vars->first_dsentry;
2952 dsentry_ptr = &cached_magic_vars->first_dsentry;
2953 while (*dsentry_ptr != NULL) {
2955 struct _magic_dsentry *cached_dsentry, *remote_dsentry = *dsentry_ptr;
2956 struct _magic_sentry *sentry;
2958 /* transfer dsentry */
2959 MD_TRANSFER(info, *dsentry_ptr, (void **) dsentry_ptr, sizeof(struct _magic_dsentry));
2960 cached_dsentry = *dsentry_ptr;
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;
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;
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;
2985 } else {
2986 printf("ERROR. dsentry->parent_name == NULL.\n");
2987 return EGENERIC;
2990 sentry = &cached_dsentry->sentry;
2991 if (transfer_metadata_sentry_members(info, sentry)) {
2992 printf("ERROR transferring sentry members metadata.\n");
2993 return EGENERIC;
2996 /* Override original id to simplify pairing later. */
2997 sentry->id = cached_magic_vars->sentries_num + *dsentries_num + 1;
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.
3003 if (!strcmp(sentry->name, MAGIC_ALLOC_INITIAL_STACK_NAME)) {
3004 sentry->flags |= MAGIC_STATE_ADDR_NOT_TAKEN;
3008 * Adjust the type, so that the local and remote type can be compared
3009 * during a server version update
3011 if (sentry->type == &remote_dsentry->type) {
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.
3021 /* Adjust pointer to cached location */
3022 sentry->type = &cached_dsentry->type;
3024 /* Adjust contained_types to type_array located in dsentry struct. */
3025 sentry->type->contained_types = cached_dsentry->type_array;
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.
3032 sentry->type->contained_types[0] = &cached_magic_vars->types[sentry->type->contained_types[0] - remote_magic_vars->types];
3034 /* Adjust empty strings. */
3035 sentry->type->name = "";
3036 sentry->type->type_str = "";
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;
3045 } else {
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.
3052 sentry->type = &cached_magic_vars->types[sentry->type - remote_magic_vars->types];
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;
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;
3070 return OK;
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)
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;
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++;
3088 if (ST_IS_UNPAIRABLE_TYPE(type)) {
3089 num_total_types++;
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);
3095 num_unpaired_types_left = num_unpaired_types;
3096 num_unpaired_struct_types_left = num_unpaired_struct_types;
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;
3103 if (num_unpaired_types_left > 0 && ST_IS_UNPAIRABLE_TYPE(type)) {
3104 num_unpaired_types_left--;
3105 continue;
3107 else if (num_unpaired_struct_types_left > 0 && ST_IS_UNPAIRABLE_STRUCT_TYPE(type)) {
3108 num_unpaired_struct_types_left--;
3109 continue;
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.
3117 if (magic_type_compatible(type, &_magic_types[j], MAGIC_TYPE_COMPARE_ALL)) {
3118 counterparts->types[i].counterpart = &_magic_types[j];
3119 break;
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;
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);
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;
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;
3151 j++;
3153 if (MAGIC_TYPE_HAS_COMP_TYPE(type, j) || MAGIC_TYPE_HAS_COMP_TYPE(local_type, j)) {
3154 continue;
3157 counterparts->ptr_types[i].counterpart = local_type;
3161 return OK;
3164 PRIVATE int pair_metadata_functions(st_init_info_t *info,
3165 struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
3167 int i;
3168 struct _magic_function *cached_function, *local_function;
3169 #if ST_DEBUG_LEVEL > 0
3170 int num_relocated = 0;
3171 #endif
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);
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;
3193 #endif
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);
3202 #endif
3205 #if ST_DEBUG_LEVEL > 0
3206 printf("total remote functions: %d. relocated: %d\n", cached_magic_vars->functions_num, num_relocated);
3207 #endif
3209 return OK;
3212 PRIVATE int pair_metadata_sentries(st_init_info_t *info,
3213 struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
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
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];
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;
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;
3239 local_data_addr = string;
3241 ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries_data, local_data_addr);
3243 local_sentry = NULL;
3244 st_map_sentries(&cached_sentry, &local_sentry);
3245 ST_SET_CACHED_COUNTERPART(cached_sentry, sentries, sentries, local_sentry);
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;
3260 #endif
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++;
3267 else {
3268 num_relocated_normal++;
3269 if (ST_DEBUG_LEVEL > 1) {
3270 printf("- relocated non-string sentry: '%s'\n", cached_sentry->name);
3274 #endif
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
3281 return OK;
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)
3288 struct _magic_dsentry *dsentry;
3289 int remote_dsentries = 0, unpaired_dsentries = 0;
3291 #if ST_DEBUG_LEVEL > 3
3292 EXEC_WITH_MAGIC_VARS(
3293 magic_print_dsentries();
3294 , &st_cached_magic_vars
3296 magic_print_dsentries();
3297 #endif
3299 dsentry = cached_magic_vars->first_dsentry;
3300 while (dsentry != NULL) {
3301 struct _magic_sentry *local_sentry = NULL, *sentry = MAGIC_DSENTRY_TO_SENTRY(dsentry);
3303 /* Initialize counterpart to NULL. */
3304 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL);
3306 remote_dsentries++;
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
3316 #else
3317 local_sentry = magic_sentry_lookup_by_addr(sentry->address, NULL);
3318 #endif
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
3327 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, local_sentry);
3328 dsentry = dsentry->next;
3331 #if ST_DEBUG_LEVEL > 0
3332 printf("total remote dsentries: %d (%d unpaired)\n", remote_dsentries, unpaired_dsentries);
3333 #endif
3335 return OK;
3338 #else
3340 PRIVATE int allocate_pair_metadata_dsentries(st_init_info_t *info,
3341 struct _magic_vars_t *cached_magic_vars, st_counterparts_t *counterparts)
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
3349 #if ST_DEBUG_LEVEL > 3
3350 EXEC_WITH_MAGIC_VARS(
3351 magic_print_dsentries();
3352 , &st_cached_magic_vars
3354 magic_print_dsentries();
3355 #endif
3357 #ifdef __MINIX
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.
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)
3373 * The 'ext' field in the dsentry is used here to record
3374 * the padding for ASR.
3376 size_t padding = (size_t) dsentry->ext;
3378 * call munmap(). ptr and size have to be altered,
3379 * in order to free the preceding page, containing the dsentry struct, too.
3381 MAGIC_MEM_WRAPPER_BLOCK(
3382 res = munmap((char *)sentry->address - magic_get_sys_pagesize(), size + magic_get_sys_pagesize() + padding);
3384 if (res != 0) {
3385 printf("ERROR, munmap returned NULL.\n");
3386 return EGENERIC;
3389 dsentry = dsentry->next;
3391 #endif
3393 /* Permute dsentries in case of ASR. */
3394 if (info->flags & ST_LU_ASR) {
3395 magic_asr_permute_dsentries(&cached_magic_vars->first_dsentry);
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;
3405 remote_dsentries++;
3407 #ifdef __MINIX
3408 /* Cannot deal with dead dsentries. */
3409 assert(dsentry->magic_state == MAGIC_DSENTRY_MSTATE_ALIVE);
3410 #else
3412 * If there are dead dsentries, we simply skip them.
3414 if (dsentry->magic_state != MAGIC_DSENTRY_MSTATE_ALIVE) {
3415 dsentry = dsentry->next;
3416 continue;
3418 #endif
3420 /* Initialize counterpart to NULL. */
3421 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, NULL);
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);
3432 dsentry = dsentry->next;
3433 continue;
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];
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;
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;
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;
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;
3479 /* Handle regular alloc dsentries last. */
3480 #ifndef __MINIX
3482 * For Linux, first pair INIT time remote
3483 * dsentries with local dsentries.
3486 if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_INIT)) {
3487 local_sentry = NULL;
3489 if (MAGIC_STATE_FLAG(sentry, MAGIC_STATE_IMMUTABLE)) {
3491 * Immutable init time dsentries should have already been
3492 * preallocated, so just pair them by address.
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);
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;
3506 local_sentry_list = local_sentry_list->next;
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;
3529 MAGIC_DSENTRY_UNLOCK();
3530 } while (0);
3531 #endif
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;
3540 #endif
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.
3548 local_dsindex = magic_dsindex_lookup_by_name(dsentry->parent_name, sentry->name);
3549 if (local_dsindex || MAGIC_SENTRY_IS_LIB_ALLOC(sentry)) {
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;
3557 assert(local_dsentry);
3558 ST_SET_CACHED_COUNTERPART(sentry, sentries, sentries, MAGIC_DSENTRY_TO_SENTRY(local_dsentry));
3561 dsentry = dsentry->next;
3564 #if ST_DEBUG_LEVEL > 0
3565 printf("total remote dsentries: %d\n", remote_dsentries);
3566 #endif
3568 return OK;
3571 PRIVATE int deallocate_nonxferred_dsentries(struct _magic_dsentry *first_dsentry, st_counterparts_t *counterparts)
3573 struct _magic_dsentry *dsentry = first_dsentry;
3574 struct _magic_sentry *local_sentry;
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);
3582 if (MAGIC_STATE_EXTF_GET(sentry, ST_TRANSFER_DONE) || !is_alloc_dsentry) {
3583 dsentry = dsentry->next;
3584 continue;
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");
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");
3599 if (!is_paired_dsentry) {
3600 dsentry = dsentry->next;
3601 continue;
3603 assert(local_sentry);
3604 if (MAGIC_SENTRY_IS_ALLOC(local_sentry)) {
3605 deallocate_local_dsentry(MAGIC_DSENTRY_FROM_SENTRY(local_sentry));
3607 dsentry = dsentry->next;
3610 return OK;
3612 #endif
3614 PRIVATE void deallocate_local_dsentry(struct _magic_dsentry *local_dsentry)
3616 int r, dsentry_type;
3617 struct _magic_sentry *local_sentry = MAGIC_DSENTRY_TO_SENTRY(local_dsentry);
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;
3625 MAGIC_MEM_WRAPPER_BEGIN();
3626 switch (dsentry_type) {
3627 case MAGIC_STATE_HEAP:
3628 /* free */
3629 magic_free(local_sentry->address);
3630 break;
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");
3640 break;
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");
3651 break;
3652 #endif
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");
3662 break;
3664 default:
3665 st_cbs_os.panic("ERROR. UNSUPPORTED DSENTRY TYPE: %d\n", dsentry_type);
3667 MAGIC_MEM_WRAPPER_END();
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)
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;
3680 /* Either a dsindex or a dsentry needs to be set. */
3681 assert(local_dsindex || cached_dsentry);
3683 if (cached_dsentry)
3684 cached_sentry = MAGIC_DSENTRY_TO_SENTRY(cached_dsentry);
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));
3694 * The external allocation parent_name needs to be readjusted.
3695 * The external allocation name is adjusted after the new dsentry
3696 * is created.
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;
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;
3722 MAGIC_DSODESC_UNLOCK();
3723 assert(found_parent_name && "Invalid parent name for cached dsentry!");
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;
3732 assert(num_elements > 0);
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;
3739 } else {
3740 alloc_flags = *p_alloc_flags;
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);
3748 * Use old address for immutable objects.
3750 /* ptr: args || cached_sentry. */
3751 if (!ptr && cached_sentry &&
3752 MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_IMMUTABLE))
3753 ptr = cached_sentry->address;
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);
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;
3772 #endif
3774 /* type: local_dsindex || cached_sentry. */
3775 if (local_dsindex) {
3776 type = local_dsindex->type;
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);
3787 size = num_elements * type->size;
3789 } else {
3791 * The type will need adjusting later.
3793 type = cached_sentry->type;
3794 size = type->size;
3797 *local_dsentry_ptr = NULL;
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;
3806 memset(ptr, 0, size);
3807 local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
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;
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;
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));
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;
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;
3838 local_dsentry = MAGIC_PTR_TO_DSENTRY(MAGIC_PTR_FROM_DATA(ptr));
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);
3849 printf("\n");
3850 return EINVAL;
3853 if (!local_dsindex) {
3855 * This was an externally allocated type and, as such, needs adjusting.
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]);
3864 local_dsentry->sentry.type = &local_dsentry->type;
3865 local_dsentry->sentry.type->contained_types = local_dsentry->type_array;
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;
3874 if (is_type_mismatch)
3875 local_dsentry->sentry.flags |= MAGIC_STATE_TYPE_SIZE_MISMATCH;
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.
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;
3889 return OK;
3892 PRIVATE int check_unpaired_sentry(st_init_info_t *info,
3893 struct _magic_sentry* cached_sentry)
3895 int sentry_needs_transfer = MAGIC_STATE_EXTF_GET(cached_sentry, ST_NEEDS_TRANSFER | ST_TRANSFER_DONE) == ST_NEEDS_TRANSFER;
3896 int report;
3898 if (!sentry_needs_transfer && !MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3899 return OK;
3902 if (MAGIC_STATE_FLAG(cached_sentry, MAGIC_STATE_DYNAMIC)) {
3903 report = st_policies & ST_REPORT_UNPAIRED_DSENTRIES;
3905 else if(MAGIC_SENTRY_IS_STRING(cached_sentry)) {
3906 report = st_policies & ST_REPORT_UNPAIRED_STRINGS;
3908 else {
3909 report = st_policies & ST_REPORT_UNPAIRED_SENTRIES;
3911 if (report) {
3912 printf("check_unpaired_sentry: Unpaired sentry found: ");
3913 ST_SENTRY_PRINT(cached_sentry,MAGIC_EXPAND_TYPE_STR);
3914 printf("\n");
3917 return OK;
3920 PUBLIC struct _magic_sentry* st_cached_to_remote_sentry(st_init_info_t *info, struct _magic_sentry *cached_sentry)
3922 struct _magic_sentry *remote_sentry;
3923 void *local_data_addr;
3924 ST_CHECK_INIT();
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);
3931 else {
3932 memcpy(&st_dsentry_buff->sentry, cached_sentry, sizeof(struct _magic_sentry));
3933 remote_sentry = &st_dsentry_buff->sentry;
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))
3945 printf("ERROR transferring sentry data to local buffer.\n");
3946 return NULL;
3948 local_data_addr = st_data_buff;
3950 remote_sentry->address = local_data_addr;
3952 return remote_sentry;
3955 PRIVATE int transfer_data_sentry(st_init_info_t *info,
3956 struct _magic_sentry* cached_sentry)
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];
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;
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;
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;
3995 EXEC_WITH_MAGIC_VARS(
3996 r = magic_sentry_analyze(remote_sentry , flags, transfer_data_selement, cb_info, NULL);
3997 , &st_cached_magic_vars
3999 if (r < 0) {
4000 return r;
4003 st_set_transfer_status(ST_TRANSFER_DONE, ST_OP_ADD, cached_sentry, NULL);
4004 return OK;
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)
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;
4016 register_typenames_and_callbacks();
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];
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");
4037 return MAGIC_SENTRY_ANALYZE_SKIP_PATH;
4039 cb_info->local_selement = local_selement;
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;
4050 cb_flags = ST_CB_TYPE_SELEMENT;
4051 if (ST_TYPE_NAME_KEY(selement->type) != NULL) {
4052 cb_flags |= ST_CB_TYPE_TYPENAME;
4054 if (selement->num == 1) {
4055 cb_flags |= ST_CB_TYPE_SENTRY;
4058 cb = st_cbs.st_cb_selement_transfer[cb_flags];
4059 while (TRUE) {
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.");
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;
4074 return r;
4077 cb++;
4080 /* Not reachable. */
4081 return EINTR;
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)
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;
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;
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;
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;
4131 /* Check unpaired targets. */
4132 if (!local_trg_root_type) {
4133 local_trg_selement->type = NULL;
4134 return OK;
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;
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;
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!");
4155 #endif
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;
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;
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;
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;
4187 /* transfer helper functions */
4189 PRIVATE int md_transfer_str(st_init_info_t *info, char **str_pt)
4191 char buff[ST_STR_BUFF_SIZE + 2];
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;
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;
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;
4208 strcpy(*str_pt, buff);
4209 return OK;
4212 PRIVATE int md_transfer(st_init_info_t *info, void *from, void **to, int len)
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;
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;
4225 return OK;
4229 /* Buffer allocation */
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;
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");
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);
4252 PUBLIC void *st_cb_pages_allocate(st_init_info_t *info, uint32_t *phys, int num_pages)
4254 void *result;
4255 int len = num_pages * magic_get_sys_pagesize();
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];
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;
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;
4276 *phys = (uint32_t) NULL; /* we don't know or need the physical address in order to free */
4278 return result;
4281 PUBLIC void st_cb_pages_free(st_init_info_t *info, st_alloc_pages *current_page)
4283 st_alloc_pages *to_be_freed;
4284 int result;
4286 if (USE_PRE_ALLOCATED_BUFFER(info)) {
4287 /* nothing to do */
4288 return;
4291 while (current_page != NULL) {
4292 to_be_freed = current_page;
4293 current_page = current_page->previous;
4295 result = st_cbs_os.free_contig(to_be_freed->virt_addr, to_be_freed->num_pages * magic_get_sys_pagesize());
4297 if (result != OK) {
4298 printf("munmap result != ok, using free()\n");
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.
4303 free(to_be_freed->virt_addr);
4310 PUBLIC void *st_buff_allocate(st_init_info_t *info, size_t size)
4312 void *result;
4314 if (size > st_alloc_buff_available) {
4316 int pagesize = magic_get_sys_pagesize();
4317 uint32_t phys;
4318 st_alloc_pages *buff_previous_page = st_alloc_pages_current;
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++;
4325 /* allocate pages */
4326 st_alloc_pages_current
4327 = st_cbs.st_cb_pages_allocate(info, &phys, pages_needed);
4329 if (!st_alloc_pages_current) {
4330 printf("Could not allocate buffer.\n");
4331 return NULL;
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;
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);
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;
4355 return result;
4359 PUBLIC void st_buff_cleanup(st_init_info_t *info)
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;
4367 PUBLIC void st_cleanup(st_init_info_t *info)
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
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
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
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
4393 * Free all temporary allocated memory.
4395 st_buff_cleanup(info);
4398 * Reset all values in case of successive state transfers.
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;
4410 /* Reallow mempool dsentries lookups. */
4411 magic_lookup_nested_dsentries = 1;
4414 /* State cleanup/checking functions. */
4416 /*===========================================================================*
4417 * do_st_before_receive *
4418 *===========================================================================*/
4419 PUBLIC void do_st_before_receive()
4421 /* Handle State transfer before receive events. */
4422 int num_violations;
4424 assert(st_state_checking_before_receive_is_enabled());
4426 num_violations = st_do_state_checking();
4427 if (__st_before_receive_sc_max_cycles < LONG_MAX) {
4428 __st_before_receive_sc_max_cycles--;
4430 if (__st_before_receive_sc_max_violations < LONG_MAX) {
4431 __st_before_receive_sc_max_violations -= num_violations;
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");
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");
4443 /*===========================================================================*
4444 * st_state_checking_before_receive_is_enabled *
4445 *===========================================================================*/
4446 PUBLIC int st_state_checking_before_receive_is_enabled()
4448 return __st_before_receive_enabled;
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)
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;
4463 if (max_violations <= 0) {
4464 max_violations = ST_STATE_CHECKING_DEFAULT_MAX_VIOLATIONS;
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);
4472 else {
4473 printf("Continuous state checking disabled\n");
4475 return was_enabled;
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)
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;
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;
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)++;
4502 return ret;
4505 /*===========================================================================*
4506 * st_do_state_checking *
4507 *===========================================================================*/
4508 PUBLIC int st_do_state_checking()
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;
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)
4523 return EINTR;
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)
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;
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)
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;
4550 /*===========================================================================*
4551 * st_do_state_cleanup *
4552 *===========================================================================*/
4553 PUBLIC int st_do_state_cleanup()
4555 return st_cbs.st_cb_state_cleanup();
4558 /*===========================================================================*
4559 * st_cb_state_cleanup_null *
4560 *===========================================================================*/
4561 PUBLIC int st_cb_state_cleanup_null() {
4562 return OK;
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,
4576 * TODO:
4577 * - Don't msync mmaps of /dev/zero
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);
4586 #endif