HIDDEN void mips_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); #if _MIPS_SIM == _ABIO32 local_addr_space.abi = UNW_MIPS_ABI_O32; #elif _MIPS_SIM == _ABIN32 local_addr_space.abi = UNW_MIPS_ABI_N32; #elif _MIPS_SIM == _ABI64 local_addr_space.abi = UNW_MIPS_ABI_N64; #else # error Unsupported ABI #endif local_addr_space.addr_size = sizeof (void *); local_addr_space.caching_policy = UNW_CACHE_GLOBAL; local_addr_space.acc.find_proc_info = dwarf_find_proc_info; local_addr_space.acc.put_unwind_info = put_unwind_info; local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; local_addr_space.acc.access_mem = access_mem; local_addr_space.acc.access_reg = access_reg; local_addr_space.acc.access_fpreg = access_fpreg; local_addr_space.acc.resume = NULL; /* mips_local_resume? FIXME! */ local_addr_space.acc.get_proc_name = get_static_proc_name; unw_flush_cache (&local_addr_space, 0, 0); }
HIDDEN void x86_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); local_addr_space.caching_policy = UNW_CACHE_GLOBAL; local_addr_space.acc.find_proc_info = dwarf_find_proc_info; local_addr_space.acc.put_unwind_info = put_unwind_info; local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; local_addr_space.acc.access_mem = access_mem; local_addr_space.acc.access_reg = access_reg; local_addr_space.acc.access_fpreg = access_fpreg; local_addr_space.acc.resume = x86_local_resume; local_addr_space.acc.get_proc_name = get_static_proc_name; unw_flush_cache (&local_addr_space, 0, 0); }
HIDDEN void aarch64_local_addr_space_init (void) { memset (&local_addr_space, 0, sizeof (local_addr_space)); local_addr_space.caching_policy = UNWI_DEFAULT_CACHING_POLICY; local_addr_space.acc.find_proc_info = dwarf_find_proc_info; local_addr_space.acc.put_unwind_info = put_unwind_info; local_addr_space.acc.get_dyn_info_list_addr = get_dyn_info_list_addr; local_addr_space.acc.access_mem = access_mem; local_addr_space.acc.access_reg = access_reg; local_addr_space.acc.access_fpreg = access_fpreg; local_addr_space.acc.resume = aarch64_local_resume; local_addr_space.acc.get_proc_name = get_static_proc_name; local_addr_space.big_endian = (__BYTE_ORDER == __BIG_ENDIAN); unw_flush_cache (&local_addr_space, 0, 0); }
PROTECTED int unw_set_caching_policy (unw_addr_space_t as, unw_caching_policy_t policy) { if (!tdep_init_done) tdep_init (); // We don't support per-thread caching (not warranted/helpful), mutate it. if (policy == UNW_CACHE_PER_THREAD) policy = UNW_CACHE_GLOBAL; if (policy == as->caching_policy) return 0; /* no change */ as->caching_policy = policy; /* Ensure caches are empty (and initialized). */ unw_flush_cache (as, 0, 0); return 0; }
PROTECTED int unw_set_caching_policy (unw_addr_space_t as, unw_caching_policy_t policy) { if (!tdep_init_done) tdep_init (); #ifndef HAVE___THREAD if (policy == UNW_CACHE_PER_THREAD) policy = UNW_CACHE_GLOBAL; #endif if (policy == as->caching_policy) return 0; /* no change */ as->caching_policy = policy; /* Ensure caches are empty (and initialized). */ unw_flush_cache (as, 0, 0); return 0; }
static inline int validate_cache (unw_addr_space_t as) { /* Note: we don't need to serialize here with respect to dl_iterate_phdr() because if somebody were to remove an object that is required to complete the unwind on whose behalf we're validating the cache here, we'd be hosed anyhow. What we're guarding against here is the case where library FOO gets mapped, unwind info for FOO gets cached, FOO gets unmapped, BAR gets mapped in the place where FOO was and then we unwind across a function in FOO. Since no thread can execute in BAR before FOO has been removed, we are guaranteed that dl_phdr_removals_counter() would have been incremented before we get here. */ unsigned long long removals = dl_phdr_removals_counter (); if (removals == as->shared_object_removals) return 1; as->shared_object_removals = removals; unw_flush_cache (as, 0, 0); return -1; }
HIDDEN int unwi_dyn_validate_cache (unw_addr_space_t as, void *arg) { unw_word_t addr, gen; unw_accessors_t *a; if (!as->dyn_info_list_addr) /* If we don't have the dyn_info_list_addr, we don't have anything in the cache. */ return 0; a = unw_get_accessors (as); addr = as->dyn_info_list_addr; if (fetchw (as, a, &addr, &gen, arg) < 0) return 1; if (gen == as->dyn_generation) return 1; unw_flush_cache (as, 0, 0); as->dyn_generation = gen; return -1; }
static int check_callback (struct dl_phdr_info *info, size_t size, void *ptr) { # ifdef HAVE_STRUCT_DL_PHDR_INFO_DLPI_SUBS unw_addr_space_t as = ptr; if (size < offsetof (struct dl_phdr_info, dlpi_subs) + sizeof (info->dlpi_subs)) /* It would be safer to flush the cache here, but that would disable caching for older libc's which would be incompatible with the behavior of older versions of libunwind so we return 1 instead and hope nobody runs into stale cache info... */ return 1; if (info->dlpi_subs == as->shared_object_removals) return 1; as->shared_object_removals = info->dlpi_subs; unw_flush_cache (as, 0, 0); return -1; /* indicate that there were removals */ # else return 1; # endif }