Fix maps caching for local processes.

It is possible for the map to change while running libunwind. For example,
if lots of threads are doing local unwinds at the same time. Allow the
cached map to regenerate when it detects this case.

Included in this change is a refactor of all of the os code so that it can
also be used to do caching. This is a prelude to being able to attempt to
push the code upstream.

Also, this moves the code back closer to the original upstream code.
Hopefully, this will allow me to upstream all of these changes.

Change-Id: Ia219fa61e16e36416133bc95b1dd2161bd5b8ff7
diff --git a/src/Los-common.c b/src/Los-common.c
new file mode 100644
index 0000000..dc6f175
--- /dev/null
+++ b/src/Los-common.c
@@ -0,0 +1,188 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2014 The Android Open Source Project
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include "libunwind_i.h"
+
+/* Global to hold the map for all local unwinds. */
+extern struct map_info *local_map_list;
+extern lock_rdwr_var (local_rdwr_lock);
+
+HIDDEN void
+map_local_init (void)
+{
+  lock_rdwr_init (&local_rdwr_lock);
+}
+
+static void
+move_cached_elf_data (struct map_info *old_list, struct map_info *new_list)
+{
+  while (old_list)
+    {
+      if (old_list->ei.image == NULL)
+        {
+          old_list = old_list->next;
+          continue;
+        }
+      /* Both lists are in order, so it's not necessary to scan through
+         from the beginning of new_list each time looking for a match to
+         the current map. As we progress, simply start from the last element
+         in new_list we checked. */
+      while (new_list && old_list->start <= new_list->start)
+        {
+          if (old_list->start == new_list->start
+              && old_list->end == new_list->end)
+            {
+              /* No need to do any lock, the entire local_map_list is locked
+                 at this point. */
+              new_list->ei.size = old_list->ei.size;
+              new_list->ei.image = old_list->ei.image;
+              old_list->ei.size = 0;
+              old_list->ei.image = NULL;
+              /* Don't bother breaking out of the loop, the next while check
+                 is guaranteed to fail, causing us to break out of the loop
+                 after advancing to the next map element. */
+            }
+          new_list = new_list->next;
+        }
+      old_list = old_list->next;
+    }
+}
+
+/* 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)
+{
+  struct map_info *map;
+  struct map_info *new_list;
+  int ret_value = -1;
+  intrmask_t saved_mask;
+
+  new_list = map_create_list (getpid());
+  map = map_find_from_addr (new_list, addr);
+  if (map && (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 || (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;
+}
+
+static int
+is_flag_set (unw_word_t addr, int flag)
+{
+  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)
+    ret = map->flags & flag;
+  lock_rdwr_release (&local_rdwr_lock, saved_mask);
+
+  if (!ret && rebuild_if_necessary (addr, flag) == 0)
+    {
+      return 1;
+    }
+  return ret;
+}
+
+PROTECTED int
+map_local_is_readable (unw_word_t addr)
+{
+  return is_flag_set (addr, PROT_READ);
+}
+
+PROTECTED int
+map_local_is_writable (unw_word_t addr)
+{
+  return is_flag_set (addr, PROT_WRITE);
+}
+
+PROTECTED int
+local_get_elf_image (struct elf_image *ei, unw_word_t ip,
+                     unsigned long *segbase, unsigned long *mapoff, char **path)
+{
+  struct map_info *map;
+  intrmask_t saved_mask;
+
+  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) < 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 (map, ip) < 0)
+    map = NULL;
+  else
+    {
+      *ei = map->ei;
+      *segbase = map->start;
+      *mapoff = map->offset;
+      if (path != NULL)
+        {
+          if (map->path)
+            *path = strdup(map->path);
+          else
+            *path = NULL;
+        }
+    }
+  lock_rdwr_release (&local_rdwr_lock, saved_mask);
+
+  return 0;
+}
diff --git a/src/aarch64/Ginit.c b/src/aarch64/Ginit.c
index 60b8937..7ccb74f 100644
--- a/src/aarch64/Ginit.c
+++ b/src/aarch64/Ginit.c
@@ -88,7 +88,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (as->map_list, addr))
         {
 #endif
           Debug (16, "mem[%lx] <- %lx\n", addr, *val);
@@ -107,7 +107,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (as->map_list, addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -210,6 +210,8 @@
   local_addr_space.acc.resume = aarch64_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/aarch64/Ginit_local.c b/src/aarch64/Ginit_local.c
index 7b8a8cc..dee6fd3 100644
--- a/src/aarch64/Ginit_local.c
+++ b/src/aarch64/Ginit_local.c
@@ -48,9 +48,6 @@
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }
diff --git a/src/arm/Ginit.c b/src/arm/Ginit.c
index b8cb6dd..03eef53 100644
--- a/src/arm/Ginit.c
+++ b/src/arm/Ginit.c
@@ -80,7 +80,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (16, "mem[%x] <- %x\n", addr, *val);
@@ -99,7 +99,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -203,6 +203,8 @@
   local_addr_space.acc.resume = arm_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/arm/Ginit_local.c b/src/arm/Ginit_local.c
index ffad8ba..e1cc30c 100644
--- a/src/arm/Ginit_local.c
+++ b/src/arm/Ginit_local.c
@@ -48,9 +48,6 @@
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }
diff --git a/src/elfxx.c b/src/elfxx.c
index 38d69fc..372202d 100644
--- a/src/elfxx.c
+++ b/src/elfxx.c
@@ -348,14 +348,14 @@
 elf_w (get_proc_name) (unw_addr_space_t as, pid_t pid, unw_word_t ip,
 		       char *buf, size_t buf_len, unw_word_t *offp)
 {
+  unsigned long segbase, mapoff;
+  struct elf_image ei;
   int ret;
-  struct map_info *map = tdep_get_elf_image (as, pid, ip);
 
-  if (map == NULL)
-    return -UNW_ENOINFO;
+  ret = tdep_get_elf_image(as, &ei, pid, ip, &segbase, &mapoff, NULL);
+  if (ret < 0)
+    return ret;
 
-  ret = elf_w (get_proc_name_in_image) (as, &map->ei, map->start, map->offset, ip, buf, buf_len, offp);
-
-  return ret;
+  return elf_w (get_proc_name_in_image) (as, &ei, segbase, mapoff, ip, buf, buf_len, offp);
 }
 /* ANDROID support update. */
diff --git a/src/elfxx.h b/src/elfxx.h
index dd1e346..c331e50 100644
--- a/src/elfxx.h
+++ b/src/elfxx.h
@@ -31,6 +31,7 @@
 #include <sys/stat.h>
 
 #include "libunwind_i.h"
+#include "map_info.h"
 
 #if ELF_CLASS == ELFCLASS32
 # define ELF_W(x)	ELF32_##x
@@ -96,3 +97,25 @@
 
   return 0;
 }
+
+/* ANDROID support update */
+static inline int
+elf_map_cached_image (struct map_info *map, unw_word_t ip)
+{
+  intrmask_t saved_mask;
+  int return_value = 0;
+
+  /* Lock while loading the cached elf image. */
+  lock_acquire (&map->ei_lock, saved_mask);
+  if (map->ei.image == NULL)
+    {
+      if (elf_map_image(&map->ei, map->path) < 0)
+        {
+          map->ei.image = NULL;
+          return_value = -1;
+        }
+    }
+  lock_release (&map->ei_lock, saved_mask);
+  return return_value;
+}
+/* End of ANDROID update */
diff --git a/src/hppa/Ginit.c b/src/hppa/Ginit.c
index 5cd22bf..d98ad20 100644
--- a/src/hppa/Ginit.c
+++ b/src/hppa/Ginit.c
@@ -93,7 +93,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (12, "mem[%x] <- %x\n", addr, *val);
@@ -112,7 +112,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -217,6 +217,8 @@
   local_addr_space.acc.resume = hppa_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/hppa/Ginit_local.c b/src/hppa/Ginit_local.c
index 3f51cf0..628fcdb 100644
--- a/src/hppa/Ginit_local.c
+++ b/src/hppa/Ginit_local.c
@@ -48,9 +48,6 @@
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }
diff --git a/src/ia64/Ginit.c b/src/ia64/Ginit.c
index 105c703..204f334 100644
--- a/src/ia64/Ginit.c
+++ b/src/ia64/Ginit.c
@@ -80,7 +80,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable(addr))
         {
 #endif
           Debug (12, "mem[%lx] <- %lx\n", addr, *val);
@@ -99,7 +99,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -399,6 +399,8 @@
   local_addr_space.acc.resume = ia64_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/ia64/Ginit_local.c b/src/ia64/Ginit_local.c
index 13c808a..5f82c01 100644
--- a/src/ia64/Ginit_local.c
+++ b/src/ia64/Ginit_local.c
@@ -89,9 +89,6 @@
   Debug (1, "(cursor=%p)\n", c);
 
   c->as = unw_local_addr_space;
-  /* ANDROID support update. */
-  c->as->map_list = local_map_list;
-  /* End of ANDROID update. */
   set_as_arg (c, uc);
 
   if ((ret = get_initial_stack_pointers (c, uc, &sp, &bsp)) < 0)
diff --git a/src/mi/Gdestroy_addr_space.c b/src/mi/Gdestroy_addr_space.c
index fd5039e..6e8e81e 100644
--- a/src/mi/Gdestroy_addr_space.c
+++ b/src/mi/Gdestroy_addr_space.c
@@ -34,7 +34,7 @@
 # endif
   /* ANDROID support update. */
   if (as->map_list)
-    maps_destroy_list(as->map_list);
+    map_destroy_list(as->map_list);
   /* End of ANDROID update. */
   free (as);
 #endif
diff --git a/src/mi/Lmap.c b/src/mi/Lmap.c
new file mode 100644
index 0000000..e07a50a
--- /dev/null
+++ b/src/mi/Lmap.c
@@ -0,0 +1,119 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2014 The Android Open Source Project
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#define UNW_LOCAL_ONLY
+#include <libunwind.h>
+#include "libunwind_i.h"
+
+/* Globals to hold the map data for local unwinds. */
+HIDDEN struct map_info *local_map_list = NULL;
+HIDDEN int local_map_list_refs = 0;
+HIDDEN lock_rdwr_var (local_rdwr_lock);
+
+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 int
+unw_map_local_cursor_valid (unw_map_cursor_t *map_cursor)
+{
+  if (map_cursor->map_list == local_map_list)
+    return 0;
+  return -1;
+}
+
+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;
+}
+
+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_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;
+}
diff --git a/src/mi/map.c b/src/mi/map.c
new file mode 100644
index 0000000..7204b97
--- /dev/null
+++ b/src/mi/map.c
@@ -0,0 +1,137 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2014 The Android Open Source Project
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+#include <libunwind.h>
+#include "libunwind_i.h"
+
+HIDDEN int map_init_done = 0;
+HIDDEN define_lock (map_init_lock);
+HIDDEN struct mempool map_pool;
+
+PROTECTED void
+unw_map_set (unw_addr_space_t as, unw_map_cursor_t *map_cursor)
+{
+  if (map_cursor != NULL)
+    as->map_list = map_cursor->map_list;
+  else
+    as->map_list = NULL;
+}
+
+PROTECTED int
+unw_map_cursor_create (unw_map_cursor_t *map_cursor, pid_t pid)
+{
+  map_cursor->map_list = map_create_list (pid);
+
+  return map_cursor->map_list == NULL;
+}
+
+PROTECTED void
+unw_map_cursor_destroy (unw_map_cursor_t *map_cursor)
+{
+  map_destroy_list (map_cursor->map_list);
+}
+
+PROTECTED void
+unw_map_cursor_reset (unw_map_cursor_t *map_cursor)
+{
+  map_cursor->cur_map = map_cursor->map_list;
+}
+
+PROTECTED void
+unw_map_cursor_clear (unw_map_cursor_t *cursor_map)
+{
+  cursor_map->map_list = NULL;
+  cursor_map->cur_map = NULL;
+}
+
+PROTECTED int
+unw_map_cursor_get_next (unw_map_cursor_t *map_cursor, unw_map_t *unw_map)
+{
+  struct map_info *map_info = map_cursor->cur_map;
+
+  if (map_info == NULL)
+    return 0;
+
+  unw_map->start = map_info->start;
+  unw_map->end = map_info->end;
+  unw_map->flags = map_info->flags;
+  unw_map->path = map_info->path;
+
+  map_cursor->cur_map = map_info->next;
+
+  return 1;
+}
+
+HIDDEN struct map_info *
+map_alloc_info (void)
+{
+  if (!map_init_done)
+    {
+      intrmask_t saved_mask;
+
+      lock_acquire (&map_init_lock, saved_mask);
+      /* Check again under the lock. */
+      if (!map_init_done)
+        {
+          mempool_init (&map_pool, sizeof(struct map_info), 0);
+          map_init_done = 1;
+        }
+      lock_release (&map_init_lock, saved_mask);
+    }
+  return mempool_alloc (&map_pool);
+}
+
+HIDDEN void
+map_free_info (struct map_info *map)
+{
+  mempool_free (&map_pool, map);
+}
+
+HIDDEN void
+map_destroy_list (struct map_info *map_info)
+{
+  struct map_info *map;
+  while (map_info)
+    {
+      map = map_info;
+      map_info = map->next;
+      if (map->ei.image != MAP_FAILED && map->ei.image != NULL)
+        munmap (map->ei.image, map->ei.size);
+      if (map->path)
+        free (map->path);
+      map_free_info (map);
+    }
+}
+
+HIDDEN struct map_info *
+map_find_from_addr (struct map_info *map_list, unw_word_t addr)
+{
+  while (map_list)
+    {
+      if (addr >= map_list->start && addr < map_list->end)
+        return map_list;
+      map_list = map_list->next;
+    }
+  return NULL;
+}
diff --git a/src/mi/maps.c b/src/mi/maps.c
deleted file mode 100644
index 774780d..0000000
--- a/src/mi/maps.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* libunwind - a platform-independent unwind library
-   Copyright (C) 2014 The Android Open Source Project
-
-This file is part of libunwind.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
-
-#include "libunwind_i.h"
-
-/* Global to hold the map for all local unwinds. */
-HIDDEN struct map_info *local_map_list = NULL;
-
-PROTECTED void
-unw_map_local_set (unw_map_cursor_t *map_cursor)
-{
-  if (map_cursor != NULL)
-    local_map_list = map_cursor->map_list;
-  else
-    local_map_list = NULL;
-}
-
-PROTECTED void
-unw_map_set (unw_addr_space_t as, unw_map_cursor_t *map_cursor)
-{
-  if (map_cursor != NULL)
-    as->map_list = map_cursor->map_list;
-  else
-    as->map_list = NULL;
-}
-
-PROTECTED int
-unw_map_cursor_create (unw_map_cursor_t *map_cursor, pid_t pid)
-{
-  map_cursor->map_list = maps_create_list (pid);
-
-  return map_cursor->map_list == NULL;
-}
-
-PROTECTED void
-unw_map_cursor_destroy (unw_map_cursor_t *map_cursor)
-{
-  maps_destroy_list (map_cursor->map_list);
-}
-
-PROTECTED void
-unw_map_cursor_reset (unw_map_cursor_t *map_cursor)
-{
-  map_cursor->cur_map = map_cursor->map_list;
-}
-
-PROTECTED int
-unw_map_cursor_get (unw_map_cursor_t *map_cursor, unw_map_t *unw_map)
-{
-  struct map_info *map_info = map_cursor->cur_map;
-
-  if (map_info == NULL)
-    return 0;
-
-  unw_map->start = map_info->start;
-  unw_map->end = map_info->end;
-  unw_map->flags = map_info->flags;
-  unw_map->path = map_info->path;
-
-  map_cursor->cur_map = map_info->next;
-
-  return 1;
-}
diff --git a/src/mips/Ginit.c b/src/mips/Ginit.c
index 9d671a4..89031c5 100644
--- a/src/mips/Ginit.c
+++ b/src/mips/Ginit.c
@@ -98,7 +98,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val);
@@ -118,7 +118,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -234,6 +234,8 @@
   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);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/mips/Ginit_local.c b/src/mips/Ginit_local.c
index 78af76a..86abd74 100644
--- a/src/mips/Ginit_local.c
+++ b/src/mips/Ginit_local.c
@@ -47,9 +47,6 @@
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }
diff --git a/src/os-common.c b/src/os-common.c
new file mode 100644
index 0000000..5e62327
--- /dev/null
+++ b/src/os-common.c
@@ -0,0 +1,58 @@
+/* libunwind - a platform-independent unwind library
+   Copyright (C) 2014 The Android Open Source Project
+
+This file is part of libunwind.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
+
+
+#include "libunwind_i.h"
+#include "map_info.h"
+
+extern struct map_info *local_get_elf_image (unw_word_t, struct elf_image *,
+                                             unsigned long *, unsigned long *,
+                                             char **);
+
+PROTECTED int
+tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+                    pid_t pid, unw_word_t ip,
+                    unsigned long *segbase, unsigned long *mapoff, char **path)
+{
+  struct map_info *map;
+
+  if (pid == getpid())
+    return local_get_elf_image (ei, ip, segbase, mapoff, path);
+
+  map = map_find_from_addr (as->map_list, ip);
+  if (!map)
+    return -UNW_ENOINFO;
+
+  if (elf_map_cached_image (map, ip) < 0)
+    return -UNW_ENOINFO;
+
+  *ei = map->ei;
+  *segbase = map->start;
+  *mapoff = map->offset;
+  if (path != NULL)
+    {
+      *path = strdup (map->path);
+    }
+  return 0;
+}
diff --git a/src/os-freebsd.c b/src/os-freebsd.c
index fee2317..b81b752 100644
--- a/src/os-freebsd.c
+++ b/src/os-freebsd.c
@@ -88,14 +88,15 @@
   return (pid);
 }
 
-PROTECTED int
-tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-		    unsigned long *segbase, unsigned long *mapoff, char *path, size_t pathlen)
+/* ANDROID support update. */
+struct map_info *
+map_create_list(pid_t pid)
 {
   int mib[4], error, ret;
   size_t len, len1;
   char *buf, *bp, *eb;
   struct kinfo_vmentry *kv;
+  struct map_info *map_list = NULL;
 
   len = 0;
   mib[0] = CTL_KERN;
@@ -105,13 +106,15 @@
 
   error = sysctl(mib, 4, NULL, &len, NULL, 0);
   if (error == -1) {
-    if (errno == ESRCH) {
-      mib[3] = get_pid_by_tid(pid);
-      if (mib[3] != -1)
-        error = sysctl(mib, 4, NULL, &len, NULL, 0);
-      if (error == -1)
-	return (-UNW_EUNSPEC);
-    } else
+    if (errno == ESRCH)
+      {
+        mib[3] = get_pid_by_tid(pid);
+        if (mib[3] != -1)
+          error = sysctl(mib, 4, NULL, &len, NULL, 0);
+        if (error == -1)
+          return (-UNW_EUNSPEC);
+      }
+    else
       return (-UNW_EUNSPEC);
   }
   len1 = len * 4 / 3;
@@ -120,42 +123,33 @@
     return (-UNW_EUNSPEC);
   len = len1;
   error = sysctl(mib, 4, buf, &len, NULL, 0);
-  if (error == -1) {
-    free_mem(buf, len1);
-    return (-UNW_EUNSPEC);
-  }
+  if (error == -1)
+    {
+      free_mem(buf, len1);
+      return (-UNW_EUNSPEC);
+    }
   ret = -UNW_EUNSPEC;
-  for (bp = buf, eb = buf + len; bp < eb; bp += kv->kve_structsize) {
-     kv = (struct kinfo_vmentry *)(uintptr_t)bp;
-     if (ip < kv->kve_start || ip >= kv->kve_end)
-       continue;
-     if (kv->kve_type != KVME_TYPE_VNODE)
-       continue;
-     *segbase = kv->kve_start;
-     *mapoff = kv->kve_offset;
-     if (path)
-       {
-         strncpy(path, kv->kve_path, pathlen);
-       }
-     ret = elf_map_image (ei, kv->kve_path);
-     break;
-  }
+  for (bp = buf, eb = buf + len; bp < eb; bp += kv->kve_structsize)
+    {
+      kv = (struct kinfo_vmentry *)(uintptr_t)bp;
+      if (kv->kve_type != KVME_TYPE_VNODE)
+        continue;
+
+      cur_map = map_alloc_info ();
+      if (cur_map == NULL)
+        break;
+      cur_map->next = map_list;
+      cur_map->start = kv->kve_start;
+      cur_map->end = kv->kv_end;
+      cur_map->offset = kv->kve_offset;
+      cur_map->path = strdup(kv->kve_path);
+      mutex_init (&cur_map->ei_lock);
+      cur_map->ei.size = 0;
+      cur_map->ei.image = NULL;
+      cur_map->ei_shared = 0;
+    }
   free_mem(buf, len1);
-  return (ret);
-}
 
-struct map_info *
-maps_create_list(pid_t pid)
-{
-  return NULL;
+  return map_list;
 }
-
-int maps_is_readable(struct map_info *map_list, unw_word_t addr)
-{
-  return true;
-}
-
-int maps_is_writable(struct map_info *map_list, unw_word_t addr)
-{
-  return true;
-}
+/* End of ANDROID update. */
diff --git a/src/os-hpux.c b/src/os-hpux.c
index ba498f9..2127c94 100644
--- a/src/os-hpux.c
+++ b/src/os-hpux.c
@@ -31,13 +31,23 @@
 
 #include "elf64.h"
 
-HIDDEN int
-tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-		    unsigned long *segbase, unsigned long *mapoff,
-		    char *path, size_t pathlen)
+/* ANDROID support update. */
+extern struct map_info *local_map_list;
+HIDDEN define_lock(os_map_lock);
+
+HIDDEN struct map_info *
+maps_create_list (pid_t pid)
+{
+  return NULL;
+}
+
+PROTECTED int
+tdep_get_elf_image (unw_addr_space_t as, struct elf_image *ei,
+                    pid_t pid, unw_word_t ip,
+                    unsigned long *segbase, unsigned long *mapoff, char **path)
 {
   struct load_module_desc lmd;
-  const char *path2;
+  const char *path;
 
   if (pid != getpid ())
     {
@@ -45,39 +55,90 @@
       return -UNW_ENOINFO;
     }
 
+  /* First check to see if this ip is in our cache. */
+  map = map_find_from_addr(as->map_list, ip);
+  if (map)
+    goto finish;
+
+  /* Lock while we update the list. */
+  lock_acquire (&os_map_lock, saved_mask);
+
+  /* Check again if ip is in the map. */
+  map = map_find_from_addr(as->map_list, ip);
+  if (map)
+    goto release_lock;
+
+  /* Not in the cache, try and find the data. */
   if (!dlmodinfo (ip, &lmd, sizeof (lmd), NULL, 0, 0))
-    return -UNW_ENOINFO;
+    goto release_lock;
 
-  *segbase = lmd.text_base;
-  *mapoff = 0;			/* XXX fix me? */
+  path = dlgetname (&lmd, sizeof (lmd), NULL, 0, 0);
+  if (!path)
+    goto release_lock;
 
-  path2 = dlgetname (&lmd, sizeof (lmd), NULL, 0, 0);
-  if (!path2)
-    return -UNW_ENOINFO;
-  if (path)
+  map = mempool_alloc (&map_pool);
+  if (!map)
+    goto release_lock;
+
+  map->start = lmd.text_base;
+  map->end = cur_map->start + lmd.text_size;
+  map->offset = 0;			/* XXX fix me? */
+  map->flags = ;
+  map->path = strdup(path2);
+  mutex_init (&cur_map->ei_lock);
+  map->ei.size = 0;
+  map->ei.image = NULL;
+  map->ei_shared = 0;
+  Debug(1, "segbase=%lx, mapoff=%lx, path=%s\n", map->start, map->offset, map->path);
+
+  if (elf_map_cached_image (map, ip) < 0)
     {
-      strncpy(path, path2, pathlen);
-      path[pathlen - 1] = '\0';
-      if (strcmp(path, path2) != 0)
-        Debug(1, "buffer size (%d) not big enough to hold path\n", pathlen);
+      free(map);
+      map = NULL;
     }
-  Debug(1, "segbase=%lx, mapoff=%lx, path=%s\n", *segbase, *mapoff, path);
+  else
+    {
+      /* Add this element into list in descending order by start. */
+      struct map_info *map_list = as->map_list;
+      if (as->map_list == NULL || map->start > as->map_list->start)
+        {
+          map->next = as->map_list;
+          as->map_list = map;
+        }
+      else
+        {
+          while (map_list->next != NULL && map->start <= map_list->next->start)
+            map_list = map_list->next;
+          map->next = map_list->next;
+          map_list->next = map;
+        }
+    }
+release_lock:
+  lock_release (&os_map_lock, saved_mask);
 
-  return elf_map_image (ei, path);
+finish:
+  if (map)
+    {
+      *ei = map->ei;
+      *segbase = map->start;
+      *mapoff = map->offset;
+      if (path != NULL)
+        {
+          *path = strdup (map->path);
+        }
+    }
+  return 0;
 }
 
-struct map_info *
-maps_create_list(pid_t pid)
+PROTECTED int
+maps_is_local_readable(struct map_info *map_list, unw_word_t addr)
 {
-  return NULL;
+  return 1;
 }
 
-int maps_is_readable(struct map_info *map_list, unw_word_t addr)
+PROTECTED int
+maps_is_local_writable(struct map_info *map_list, unw_word_t addr)
 {
-  return true;
+  return 1;
 }
-
-int maps_is_writable(struct map_info *map_list, unw_word_t addr)
-{
-  return true;
-}
+/* End of ANDROID update. */
diff --git a/src/os-linux.c b/src/os-linux.c
index 6297d87..647ddf9 100644
--- a/src/os-linux.c
+++ b/src/os-linux.c
@@ -31,8 +31,8 @@
 #include "os-linux.h"
 
 /* ANDROID support update. */
-struct map_info *
-maps_create_list(pid_t pid)
+HIDDEN struct map_info *
+map_create_list (pid_t pid)
 {
   struct map_iterator mi;
   unsigned long start, end, offset, flags;
@@ -44,15 +44,15 @@
 
   while (maps_next (&mi, &start, &end, &offset, &flags))
     {
-      cur_map = (struct map_info *)malloc(sizeof(struct map_info));
-      if (cur_map == NULL)
+      cur_map = map_alloc_info ();
+      if (cur_map == MAP_FAILED)
         break;
       cur_map->next = map_list;
       cur_map->start = start;
       cur_map->end = end;
       cur_map->offset = offset;
       cur_map->flags = flags;
-      cur_map->path = strdup(mi.path);
+      cur_map->path = strdup (mi.path);
       mutex_init (&cur_map->ei_lock);
       cur_map->ei.size = 0;
       cur_map->ei.image = NULL;
@@ -64,80 +64,4 @@
 
   return map_list;
 }
-
-void
-maps_destroy_list(struct map_info *map_info)
-{
-  struct map_info *map;
-  while (map_info)
-    {
-      map = map_info;
-      map_info = map->next;
-      if (map->ei.image != MAP_FAILED && map->ei.image != NULL)
-        munmap(map->ei.image, map->ei.size);
-      if (map->path)
-        free(map->path);
-      free(map);
-    }
-}
-
-static struct map_info *
-get_map(struct map_info *map_list, unw_word_t addr)
-{
-  while (map_list)
-    {
-      if (addr >= map_list->start && addr < map_list->end)
-        return map_list;
-      map_list = map_list->next;
-    }
-  return NULL;
-}
-
-int maps_is_readable(struct map_info *map_list, unw_word_t addr)
-{
-  struct map_info *map = get_map(map_list, addr);
-  if (map != NULL)
-    return map->flags & PROT_READ;
-  return 0;
-}
-
-int maps_is_writable(struct map_info *map_list, unw_word_t addr)
-{
-  struct map_info *map = get_map(map_list, addr);
-  if (map != NULL)
-    return map->flags & PROT_WRITE;
-  return 0;
-}
 /* End of ANDROID update. */
-
-PROTECTED struct map_info*
-tdep_get_elf_image(unw_addr_space_t as, pid_t pid, unw_word_t ip)
-{
-  /* ANDROID support update. */
-  struct map_info *map;
-  intrmask_t saved_mask;
-
-  if (as->map_list == NULL)
-    as->map_list = maps_create_list(pid);
-
-  map = as->map_list;
-  while (map)
-    {
-      if (ip >= map->start && ip < map->end)
-        break;
-      map = map->next;
-    }
-  if (!map)
-    return NULL;
-
-  /* Lock while loading the cached elf image. */
-  lock_acquire (&map->ei_lock, saved_mask);
-  if (map->ei.image == NULL)
-    {
-      if (elf_map_image(&map->ei, map->path) < 0)
-        map->ei.image = NULL;
-    }
-  lock_release (&map->ei_lock, saved_mask);
-  /* End of ANDROID update. */
-  return map->ei.image ? map : NULL;
-}
diff --git a/src/os-qnx.c b/src/os-qnx.c
index 8b2c47a..e1149c5 100644
--- a/src/os-qnx.c
+++ b/src/os-qnx.c
@@ -27,43 +27,40 @@
 
 #include "libunwind_i.h"
 
-struct cb_info
-{
-    unw_word_t ip;
-    unsigned long segbase;
-    unsigned long offset;
-    const char *path;
-};
-
+/* ANDROID support update. */
 static int callback(const struct dl_phdr_info *info, size_t size, void *data)
 {
+  struct map_info **map_list = (struct map_info **)data;
+  struct map_info *cur_map;
   int i;
   struct cb_info *cbi = (struct cb_info*)data;
   for(i=0; i<info->dlpi_phnum; i++) {
     int segbase = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
-    if(cbi->ip >= segbase && cbi->ip < segbase + info->dlpi_phdr[i].p_memsz)
-    {
-      cbi->path = info->dlpi_name;
-      cbi->offset = info->dlpi_phdr[i].p_offset;
-      cbi->segbase = segbase;
-      return 1;
-    }
+
+    cur_map = map_alloc_info ();
+    if (cur_map == NULL)
+      break;
+
+    cur_map->next = *map_list;
+    cur_map->start = info->dlpi_addr + info->dlpi_phdr[i].p_vaddr;
+    cur_map->end = cur_map->start + info->dlpi_phdr[i].p_memsz;
+    cur_map->offset = info->dlpi_phdr[i].p_offset;
+    cur_map->path = strdup(info->dlpi_name);
+    mutex_init (&cur_map->ei_lock);
+    cur_map->ei.size = 0;
+    cur_map->ei.image = NULL;
+    cur_map->ei.shared = 0;
+
+    *map_list = cur_map;
   }
 
   return 0;
 }
 
-PROTECTED int
-tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
-                    unsigned long *segbase, unsigned long *mapoff,
-                    char *path, size_t pathlen)
+struct map_info *
+map_create_list (pid_t pid)
 {
-  struct cb_info cbi;
-  int ret = -1;
-  cbi.ip = ip;
-  cbi.segbase = 0;
-  cbi.offset = 0;
-  cbi.path = NULL;
+  struct map_info *map_list = NULL;
 
   /* QNX's support for accessing symbol maps is severely broken.  There is
      a devctl() call that can be made on a proc node (DCMD_PROC_MAPDEBUG)
@@ -85,39 +82,13 @@
   */
 
   if (pid != getpid())
-  {
-    /* Return an error if an attempt is made to perform remote image lookup */
-    return -1;
-  }
-
-  if (dl_iterate_phdr (callback, &cbi) != 0)
-  {
-    if (path)
     {
-      strncpy (path, cbi.path, pathlen);
+      /* Return an error if an attempt is made to perform remote image lookup */
+      return -1;
     }
 
-    *mapoff = cbi.offset;
-    *segbase = cbi.segbase;
-
-    ret = elf_map_image (ei, cbi.path);
-  }
-
-  return ret;
-}
-
-struct map_info *
-maps_create_list(pid_t pid)
-{
+  if (dl_iterate_phdr (callback, &map_list) != 0)
+    return map_list;
   return NULL;
 }
-
-int maps_is_readable(struct map_info *map_list, unw_word_t addr)
-{
-  return true;
-}
-
-int maps_is_writable(struct map_info *map_list, unw_word_t addr)
-{
-  return true;
-}
+/* End of ANDROID update. */
diff --git a/src/ppc/Ginit_local.c b/src/ppc/Ginit_local.c
index 52fdf1e..3aced15 100644
--- a/src/ppc/Ginit_local.c
+++ b/src/ppc/Ginit_local.c
@@ -55,9 +55,6 @@
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   #ifdef UNW_TARGET_PPC64
     return common_init_ppc64 (c, 1);
diff --git a/src/ppc32/Ginit.c b/src/ppc32/Ginit.c
index f7ea637..c555c5d 100644
--- a/src/ppc32/Ginit.c
+++ b/src/ppc32/Ginit.c
@@ -116,7 +116,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (12, "mem[%lx] <- %lx\n", addr, *val);
@@ -135,7 +135,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -239,6 +239,8 @@
   local_addr_space.acc.resume = ppc32_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/ppc64/Ginit.c b/src/ppc64/Ginit.c
index eced09a..578c282 100644
--- a/src/ppc64/Ginit.c
+++ b/src/ppc64/Ginit.c
@@ -120,7 +120,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (12, "mem[%lx] <- %lx\n", addr, *val);
@@ -139,7 +139,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -248,6 +248,8 @@
   local_addr_space.acc.resume = ppc64_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/ptrace/_UPT_find_proc_info.c b/src/ptrace/_UPT_find_proc_info.c
index 392e5e3..a99a8e3 100644
--- a/src/ptrace/_UPT_find_proc_info.c
+++ b/src/ptrace/_UPT_find_proc_info.c
@@ -36,7 +36,10 @@
 get_unwind_info (struct elf_dyn_info *edi, pid_t pid, unw_addr_space_t as, unw_word_t ip)
 {
   /* ANDROID support update. */
-  struct map_info *map;
+  unsigned long segbase, mapoff;
+  struct elf_image ei;
+  int ret;
+  char *path = NULL;
   /* End of ANDROID update. */
 
 #if UNW_TARGET_IA64 && defined(__linux)
@@ -60,12 +63,13 @@
   invalidate_edi(edi);
 
   /* ANDROID support update. */
-  map = tdep_get_elf_image (as, pid, ip);
-  if (map == NULL)
+  if (tdep_get_elf_image (as, &ei, pid, ip, &segbase, &mapoff, &path) < 0)
     return -UNW_ENOINFO;
 
-  if (tdep_find_unwind_table (edi, &map->ei, as, map->path, map->start, map->offset, ip) < 0)
-    return -UNW_ENOINFO;
+  ret = tdep_find_unwind_table (edi, &ei, as, path, segbase, mapoff, ip);
+  free(path);
+  if (ret < 0)
+    return ret;
   /* End of ANDROID update. */
 
   /* This can happen in corner cases where dynamically generated
diff --git a/src/sh/Ginit.c b/src/sh/Ginit.c
index b8cade5..7a0cd01 100644
--- a/src/sh/Ginit.c
+++ b/src/sh/Ginit.c
@@ -87,7 +87,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (16, "mem[%x] <- %x\n", addr, *val);
@@ -106,7 +106,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -209,6 +209,8 @@
   local_addr_space.acc.resume = sh_local_resume;
   local_addr_space.acc.get_proc_name = get_static_proc_name;
   unw_flush_cache (&local_addr_space, 0, 0);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/sh/Ginit_local.c b/src/sh/Ginit_local.c
index ffad8ba..e1cc30c 100644
--- a/src/sh/Ginit_local.c
+++ b/src/sh/Ginit_local.c
@@ -48,9 +48,6 @@
 
   c->dwarf.as = unw_local_addr_space;
   c->dwarf.as_arg = uc;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }
diff --git a/src/x86/Ginit.c b/src/x86/Ginit.c
index 453ee89..5be6113 100644
--- a/src/x86/Ginit.c
+++ b/src/x86/Ginit.c
@@ -145,7 +145,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (16, "mem[%x] <- %x\n", addr, *val);
@@ -168,7 +168,7 @@
         return -1;
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -271,6 +271,8 @@
   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);
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/x86/Ginit_local.c b/src/x86/Ginit_local.c
index 5bc8876..688209f 100644
--- a/src/x86/Ginit_local.c
+++ b/src/x86/Ginit_local.c
@@ -50,9 +50,6 @@
   c->dwarf.as_arg = c;
   c->uc = uc;
   c->validate = 0;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }
diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c
index f06ac81..3b84e4e 100644
--- a/src/x86_64/Ginit.c
+++ b/src/x86_64/Ginit.c
@@ -162,7 +162,7 @@
     {
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_writable(as->map_list, addr))
+      if (map_local_is_writable (addr))
         {
 #endif
           Debug (16, "mem[%016lx] <- %lx\n", addr, *val);
@@ -187,7 +187,7 @@
 
       /* ANDROID support update. */
 #ifdef UNW_LOCAL_ONLY
-      if (maps_is_readable(as->map_list, addr))
+      if (map_local_is_readable (addr))
         {
 #endif
           *val = *(unw_word_t *) addr;
@@ -293,6 +293,8 @@
 
   memset (last_good_addr, 0, sizeof (unw_word_t) * NLGA);
   lga_victim = 0;
+
+  map_local_init ();
 }
 
 #endif /* !UNW_REMOTE_ONLY */
diff --git a/src/x86_64/Ginit_local.c b/src/x86_64/Ginit_local.c
index 7f7271a..d5a4815 100644
--- a/src/x86_64/Ginit_local.c
+++ b/src/x86_64/Ginit_local.c
@@ -52,9 +52,6 @@
   c->dwarf.as_arg = c;
   c->uc = uc;
   c->validate = 0;
-  /* ANDROID support update. */
-  c->dwarf.as->map_list = local_map_list;
-  /* End of ANDROID update. */
 
   return common_init (c, 1);
 }