示例#1
0
static int
is_flag_set (unw_word_t addr, int flag, size_t bytes)
{
  struct map_info *map;
  int ret = 0;
  intrmask_t saved_mask;

  lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
  map = map_find_from_addr (local_map_list, addr);
  if (map != NULL)
    {
      if (map->flags & MAP_FLAGS_DEVICE_MEM)
        {
          lock_rdwr_release (&local_rdwr_lock, saved_mask);
          return 0;
        }
      /* Do not bother checking if the next map is readable and right at
       * the end of this map. All of the reads/writes are of small values
       * that should never span a map.
       */
      if (map->end - addr < bytes)
        ret = 0;
      else
        ret = map->flags & flag;
    }
  lock_rdwr_release (&local_rdwr_lock, saved_mask);

  if (!ret && rebuild_if_necessary (addr, flag, bytes) == 0)
    {
      return 1;
    }
  return ret;
}
示例#2
0
PROTECTED int
local_get_elf_image (unw_addr_space_t as, struct elf_image *ei, unw_word_t ip,
                     unsigned long *segbase, unsigned long *mapoff, char **path, void *as_arg)
{
  struct map_info *map;
  intrmask_t saved_mask;
  int return_value = -UNW_ENOINFO;

  lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
  map = map_find_from_addr (local_map_list, ip);
  if (!map)
    {
      lock_rdwr_release (&local_rdwr_lock, saved_mask);
      if (rebuild_if_necessary (ip, 0, sizeof(unw_word_t)) < 0)
        return -UNW_ENOINFO;

      lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
      map = map_find_from_addr (local_map_list, ip);
    }

  if (map && elf_map_cached_image (as, as_arg, map, ip, true))
    {
      /* It is absolutely necessary that the elf structure is a copy of
       * the map data. The map could be rebuilt and the old ei pointer
       * will be modified and thrown away.
       */
      *ei = map->ei;
      *segbase = map->start;
      if (ei->mapped)
        *mapoff = map->offset;
      else
        /* Always use zero as the map offset for in memory maps. The
         * dlopen of a shared library from an APK will result in a
         * non-zero offset so it won't match the elf data and cause
         * unwinds to fail. Currently, only in memory unwinds of an APK
         * are possible, so only modify this path.
         */
        *mapoff = 0;
      if (path != NULL)
        {
          if (map->path)
            *path = strdup(map->path);
          else
            *path = NULL;
        }
      return_value = 0;
    }
  lock_rdwr_release (&local_rdwr_lock, saved_mask);

  return return_value;
}
PROTECTED int
unw_map_local_cursor_get_next (unw_map_cursor_t *map_cursor, unw_map_t *unw_map)
{
  struct map_info *map_info = map_cursor->cur_map;
  intrmask_t saved_mask;
  int ret = 1;

  if (map_info == NULL)
    return 0;

  lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
  if (map_cursor->map_list != local_map_list)
    {
      map_cursor->map_list = local_map_list;
      ret = -UNW_EINVAL;
    }
  else
    {
      unw_map->start = map_info->start;
      unw_map->end = map_info->end;
      unw_map->flags = map_info->flags;
      if (map_info->path)
        unw_map->path = strdup (map_info->path);
      else
        unw_map->path = NULL;

      map_cursor->cur_map = map_info->next;
    }
  lock_rdwr_release (&local_rdwr_lock, saved_mask);

  return ret;
}
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);
}
示例#6
0
PROTECTED char *
map_local_get_image_name (unw_word_t ip)
{
  struct map_info *map;
  intrmask_t saved_mask;
  char *image_name = NULL;

  lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
  map = map_find_from_addr (local_map_list, ip);
  if (!map)
    {
      lock_rdwr_release (&local_rdwr_lock, saved_mask);
      if (rebuild_if_necessary (ip, 0, sizeof(unw_word_t)) < 0)
        return NULL;

      lock_rdwr_rd_acquire (&local_rdwr_lock, saved_mask);
      map = map_find_from_addr (local_map_list, ip);
    }
  if (map)
    image_name = strdup (map->path);
  lock_rdwr_release (&local_rdwr_lock, saved_mask);

  return image_name;
}
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;
}
示例#8
0
/* 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;
}