am f4a8df5f: Fix maps caching for local processes.

* commit 'f4a8df5f4f338f1a12c25213227e98b34b42447f':
  Fix maps caching for local processes.
diff --git a/Android.mk b/Android.mk
index 91c6fda..e3d1ed9 100644
--- a/Android.mk
+++ b/Android.mk
@@ -69,7 +69,8 @@
 	src/mi/dyn-cancel.c \
 	src/mi/dyn-info-list.c \
 	src/mi/dyn-register.c \
-	src/mi/maps.c \
+	src/mi/map.c \
+	src/mi/Lmap.c \
 	src/mi/Ldyn-extract.c \
 	src/mi/Lfind_dynamic_proc_info.c \
 	src/mi/Lget_proc_info_by_ip.c \
@@ -109,7 +110,9 @@
 	src/dwarf/Gpe.c \
 	src/dwarf/Gstep.c \
 	src/dwarf/global.c \
+	src/os-common.c \
 	src/os-linux.c \
+	src/Los-common.c \
 
 # Arch specific source files.
 $(foreach arch,$(libunwind_arches), \
@@ -181,6 +184,9 @@
 libunwind_shared_libraries_target := \
 	libdl \
 
+libunwind_ldlibs_host := \
+	-lpthread \
+
 ifeq ($(debug),true)
 libunwind_shared_libraries += \
 	liblog \
@@ -216,6 +222,9 @@
 libunwind-ptrace_shared_libraries := \
 	libunwind \
 
+libunwind_ldlibs_host := \
+	-lpthread \
+
 ifeq ($(debug),true)
 libunwind-ptrace_shared_libraries += \
 	liblog \
diff --git a/include/libunwind-common.h b/include/libunwind-common.h
index b44e939..31e307f 100644
--- a/include/libunwind-common.h
+++ b/include/libunwind-common.h
@@ -280,12 +280,17 @@
 extern int unw_backtrace (void **, int);
 
 /* ANDROID support update. */
-extern void unw_map_local_set (unw_map_cursor_t *);
+extern int unw_map_local_cursor_valid (unw_map_cursor_t *);
+extern void unw_map_local_cursor_get (unw_map_cursor_t *);
+extern int unw_map_local_cursor_get_next (unw_map_cursor_t *, unw_map_t *);
+extern int unw_map_local_create (void);
+extern void unw_map_local_destroy (void);
 extern void unw_map_set (unw_addr_space_t, unw_map_cursor_t *);
 extern void unw_map_cursor_reset (unw_map_cursor_t *);
+extern void unw_map_cursor_clear (unw_map_cursor_t *);
 extern int unw_map_cursor_create (unw_map_cursor_t *, pid_t);
 extern void unw_map_cursor_destroy (unw_map_cursor_t *);
-extern int unw_map_cursor_get (unw_map_cursor_t *, unw_map_t *);
+extern int unw_map_cursor_get_next (unw_map_cursor_t *, unw_map_t *);
 /* End of ANDROID update. */
 
 extern unw_addr_space_t unw_local_addr_space;
diff --git a/include/libunwind_i.h b/include/libunwind_i.h
index 524b301..bb940da 100644
--- a/include/libunwind_i.h
+++ b/include/libunwind_i.h
@@ -187,22 +187,37 @@
 #endif
 
 /* ANDROID support update. */
+#define __lock_acquire_internal(l, m, acquire_func)	\
+do {							\
+  SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &(m));	\
+  acquire_func (l);					\
+} while (0)
+#define __lock_release_internal(l, m, release_func)	\
+do {							\
+  release_func (l);					\
+  SIGPROCMASK (SIG_SETMASK, &(m), NULL);		\
+} while (0)
+
+#define lock_rdwr_var(name)				\
+  pthread_rwlock_t name
+#define lock_rdwr_init(l)	pthread_rwlock_init (l, NULL)
+#define lock_rdwr_wr_acquire(l, m)			\
+  __lock_acquire_internal(l, m, pthread_rwlock_wrlock)
+#define lock_rdwr_rd_acquire(l, m)			\
+  __lock_acquire_internal(l, m, pthread_rwlock_rdlock)
+#define lock_rdwr_release(l, m)				\
+  __lock_release_internal(l, m, pthread_rwlock_unlock)
+
 #define lock_var(name) \
   pthread_mutex_t name
 #define define_lock(name) \
   lock_var (name) = PTHREAD_MUTEX_INITIALIZER
-/* End of ANDROID update. */
 #define lock_init(l)		mutex_init (l)
 #define lock_acquire(l,m)				\
-do {							\
-  SIGPROCMASK (SIG_SETMASK, &unwi_full_mask, &(m));	\
-  mutex_lock (l);					\
-} while (0)
+  __lock_acquire_internal(l, m, mutex_lock)
 #define lock_release(l,m)			\
-do {						\
-  mutex_unlock (l);				\
-  SIGPROCMASK (SIG_SETMASK, &(m), NULL);	\
-} while (0)
+  __lock_release_internal(l, m, mutex_unlock)
+/* End of ANDROID update. */
 
 #define SOS_MEMORY_SIZE 16384	/* see src/mi/mempool.c */
 
diff --git a/include/map_info.h b/include/map_info.h
index 0285069..7179993 100644
--- a/include/map_info.h
+++ b/include/map_info.h
@@ -39,14 +39,23 @@
     struct map_info *next;
   };
 
+extern struct mempool map_pool;
 extern struct map_info *local_map_list;
 
-int maps_is_readable(struct map_info *map_list, unw_word_t addr);
+void map_local_init (void);
 
-int maps_is_writable(struct map_info *map_list, unw_word_t addr);
+int map_local_is_readable (unw_word_t);
 
-struct map_info *maps_create_list(pid_t pid);
+int map_local_is_writable (unw_word_t);
 
-void maps_destroy_list(struct map_info *map_info);
+struct map_info *map_alloc_info (void);
+
+void map_free_info (struct map_info *);
+
+struct map_info *map_find_from_addr (struct map_info *, unw_word_t);
+
+struct map_info *maps_create_list (pid_t);
+
+void map_destroy_list (struct map_info *);
 
 #endif /* map_info_h */
diff --git a/include/tdep-aarch64/libunwind_i.h b/include/tdep-aarch64/libunwind_i.h
index e15d39c..9254159 100644
--- a/include/tdep-aarch64/libunwind_i.h
+++ b/include/tdep-aarch64/libunwind_i.h
@@ -290,8 +290,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index e45fc5f..4577fb8 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -283,8 +283,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-hppa/libunwind_i.h b/include/tdep-hppa/libunwind_i.h
index 485bb6d..1a595ad 100644
--- a/include/tdep-hppa/libunwind_i.h
+++ b/include/tdep-hppa/libunwind_i.h
@@ -273,8 +273,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-ia64/libunwind_i.h b/include/tdep-ia64/libunwind_i.h
index a3ae1bc..95a9bee 100644
--- a/include/tdep-ia64/libunwind_i.h
+++ b/include/tdep-ia64/libunwind_i.h
@@ -268,8 +268,10 @@
 extern void *tdep_uc_addr (ucontext_t *uc, unw_regnum_t regnum,
 			   uint8_t *nat_bitnr);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-mips/libunwind_i.h b/include/tdep-mips/libunwind_i.h
index a75ed02..9dae555 100644
--- a/include/tdep-mips/libunwind_i.h
+++ b/include/tdep-mips/libunwind_i.h
@@ -325,8 +325,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-ppc32/libunwind_i.h b/include/tdep-ppc32/libunwind_i.h
index 1ff8979..56af153 100644
--- a/include/tdep-ppc32/libunwind_i.h
+++ b/include/tdep-ppc32/libunwind_i.h
@@ -306,8 +306,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t * uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t * valp, int write);
diff --git a/include/tdep-ppc64/libunwind_i.h b/include/tdep-ppc64/libunwind_i.h
index 7a619f4..b6f2224 100644
--- a/include/tdep-ppc64/libunwind_i.h
+++ b/include/tdep-ppc64/libunwind_i.h
@@ -306,8 +306,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t * uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t * valp, int write);
diff --git a/include/tdep-sh/libunwind_i.h b/include/tdep-sh/libunwind_i.h
index c4504bc..dd361bf 100644
--- a/include/tdep-sh/libunwind_i.h
+++ b/include/tdep-sh/libunwind_i.h
@@ -274,8 +274,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (unw_tdep_context_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-x86/libunwind_i.h b/include/tdep-x86/libunwind_i.h
index fdedcea..d0fdd65 100644
--- a/include/tdep-x86/libunwind_i.h
+++ b/include/tdep-x86/libunwind_i.h
@@ -289,8 +289,10 @@
 				     int need_unwind_info, void *arg);
 extern void *tdep_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
diff --git a/include/tdep-x86_64/libunwind_i.h b/include/tdep-x86_64/libunwind_i.h
index 0558f39..90b2ae3 100644
--- a/include/tdep-x86_64/libunwind_i.h
+++ b/include/tdep-x86_64/libunwind_i.h
@@ -235,8 +235,10 @@
 				     int need_unwind_info, void *arg);
 extern void *x86_64_r_uc_addr (ucontext_t *uc, int reg);
 /* ANDROID support update. */
-extern struct map_info *tdep_get_elf_image (unw_addr_space_t as, pid_t pid,
-					    unw_word_t ip);
+extern 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);
 /* End of ANDROID update. */
 extern int tdep_access_reg (struct cursor *c, unw_regnum_t reg,
 			    unw_word_t *valp, int write);
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);
 }