PROTECTED void unw_map_local_cursor_get (unw_map_cursor_t *map_cursor) { intrmask_t saved_mask; lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); map_cursor->map_list = local_map_list; map_cursor->cur_map = local_map_list; lock_rdwr_release (&local_rdwr_lock, saved_mask); }
PROTECTED void unw_map_local_destroy (void) { intrmask_t saved_mask; lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); if (local_map_list != NULL && --local_map_list_refs == 0) { map_destroy_list (local_map_list); local_map_list = NULL; } lock_rdwr_release (&local_rdwr_lock, saved_mask); }
PROTECTED int unw_map_local_create (void) { intrmask_t saved_mask; int ret_value = 0; lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); if (local_map_list_refs == 0) { local_map_list = map_create_list (getpid()); if (local_map_list != NULL) local_map_list_refs = 1; else ret_value = -1; } else local_map_list_refs++; lock_rdwr_release (&local_rdwr_lock, saved_mask); return ret_value; }
/* In order to cache as much as possible while unwinding the local process, we gather a map of the process before starting. If the cache is missing a map, or a map exists but doesn't have the "expected_flags" set, then check if the cache needs to be regenerated. While regenerating the list, grab a write lock to avoid any readers using the list while it's being modified. */ static int rebuild_if_necessary (unw_word_t addr, int expected_flags, size_t bytes) { struct map_info *map; struct map_info *new_list; int ret_value = -1; intrmask_t saved_mask; new_list = map_create_list (UNW_MAP_CREATE_LOCAL, getpid()); map = map_find_from_addr (new_list, addr); if (map && (map->end - addr >= bytes) && (expected_flags == 0 || (map->flags & expected_flags))) { /* Get a write lock on local_map_list since it's going to be modified. */ lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask); /* Just in case another thread rebuilt the map, check to see if the ip with expected_flags is in local_map_list. If not, the assumption is that new_list is newer than local_map_list because the map only gets new maps with new permissions. If this is not true, then it would be necessary to regenerate the list one more time. */ ret_value = 0; map = map_find_from_addr (local_map_list, addr); if (!map || (map->end - addr < bytes) || (expected_flags != 0 && !(map->flags & expected_flags))) { /* Move any cached items to the new list. */ move_cached_elf_data (local_map_list, new_list); map = local_map_list; local_map_list = new_list; new_list = map; } lock_rdwr_release (&local_rdwr_lock, saved_mask); } map_destroy_list (new_list); return ret_value; }