Merge "Change return type of get_load_offset to bool."
diff --git a/include/libunwind-common.h b/include/libunwind-common.h
index 17cf001..f4cbc88 100644
--- a/include/libunwind-common.h
+++ b/include/libunwind-common.h
@@ -238,6 +238,7 @@
 
 /* These routines work both for local and remote unwinding.  */
 
+#define unw_local_access_addr_space_init UNW_OBJ(local_access_addr_space_init)
 #define unw_local_addr_space	UNW_OBJ(local_addr_space)
 #define unw_create_addr_space	UNW_OBJ(create_addr_space)
 #define unw_destroy_addr_space	UNW_OBJ(destroy_addr_space)
@@ -262,6 +263,7 @@
 #define unw_flush_cache		UNW_ARCH_OBJ(flush_cache)
 #define unw_strerror		UNW_ARCH_OBJ(strerror)
 
+extern void unw_local_access_addr_space_init (unw_addr_space_t);
 extern unw_addr_space_t unw_create_addr_space (unw_accessors_t *, int);
 extern void unw_destroy_addr_space (unw_addr_space_t);
 extern unw_accessors_t *unw_get_accessors (unw_addr_space_t);
diff --git a/include/map_info.h b/include/map_info.h
index 4b53c32..9c50236 100644
--- a/include/map_info.h
+++ b/include/map_info.h
@@ -28,6 +28,12 @@
 /* Must not conflict with PROT_{NONE,READ,WRITE}. */
 #define MAP_FLAGS_DEVICE_MEM  0x8000
 
+enum map_create_type
+  {
+    UNW_MAP_CREATE_REMOTE,
+    UNW_MAP_CREATE_LOCAL,
+  };
+
 struct map_info
   {
     uintptr_t start;
@@ -60,7 +66,7 @@
 
 struct map_info *map_find_from_addr (struct map_info *, unw_word_t);
 
-struct map_info *map_create_list (pid_t);
+struct map_info *map_create_list (int, pid_t);
 
 void map_destroy_list (struct map_info *);
 
diff --git a/src/Los-common.c b/src/Los-common.c
index c11cb7b..6341545 100644
--- a/src/Los-common.c
+++ b/src/Los-common.c
@@ -92,7 +92,7 @@
   int ret_value = -1;
   intrmask_t saved_mask;
 
-  new_list = map_create_list (getpid());
+  new_list = map_create_list (UNW_MAP_CREATE_LOCAL, getpid());
   map = map_find_from_addr (new_list, addr);
   if (map && (expected_flags == 0 || (map->flags & expected_flags)))
     {
diff --git a/src/aarch64/Ginit.c b/src/aarch64/Ginit.c
index 82be025..bbf28e8 100644
--- a/src/aarch64/Ginit.c
+++ b/src/aarch64/Ginit.c
@@ -196,6 +196,27 @@
   return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
+static int
+access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
+                         int write, void *arg)
+{
+  if (write)
+    return -1;
+
+  *val = *(unw_word_t *) addr;
+  Debug (16, "mem[%lx] -> %lx\n", addr, *val);
+  return 0;
+}
+
+// This initializes just enough of the address space to call the
+// access memory function.
+PROTECTED void
+unw_local_access_addr_space_init (unw_addr_space_t as)
+{
+  memset (as, 0, sizeof (*as));
+  as->acc.access_mem = access_mem_unrestricted;
+}
+
 HIDDEN void
 aarch64_local_addr_space_init (void)
 {
diff --git a/src/arm/Ginit.c b/src/arm/Ginit.c
index 13629e7..a382ac7 100644
--- a/src/arm/Ginit.c
+++ b/src/arm/Ginit.c
@@ -189,6 +189,27 @@
   return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
+static int
+access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
+                         int write, void *arg)
+{
+  if (write)
+    return -1;
+
+  *val = *(unw_word_t *) addr;
+  Debug (16, "mem[%x] -> %x\n", addr, *val);
+  return 0;
+}
+
+// This initializes just enough of the address space to call the
+// access memory function.
+PROTECTED void
+unw_local_access_addr_space_init (unw_addr_space_t as)
+{
+  memset (as, 0, sizeof (*as));
+  as->acc.access_mem = access_mem_unrestricted;
+}
+
 HIDDEN void
 arm_local_addr_space_init (void)
 {
diff --git a/src/mi/Lmap.c b/src/mi/Lmap.c
index 316b742..9d30fbb 100644
--- a/src/mi/Lmap.c
+++ b/src/mi/Lmap.c
@@ -67,7 +67,7 @@
   lock_rdwr_wr_acquire (&local_rdwr_lock, saved_mask);
   if (local_map_list_refs == 0)
     {
-      local_map_list = map_create_list (getpid());
+      local_map_list = map_create_list (UNW_MAP_CREATE_LOCAL, getpid());
       if (local_map_list != NULL)
         local_map_list_refs = 1;
       else
diff --git a/src/mi/map.c b/src/mi/map.c
index f604755..b37ad14 100644
--- a/src/mi/map.c
+++ b/src/mi/map.c
@@ -41,7 +41,7 @@
 PROTECTED int
 unw_map_cursor_create (unw_map_cursor_t *map_cursor, pid_t pid)
 {
-  map_cursor->map_list = map_create_list (pid);
+  map_cursor->map_list = map_create_list (UNW_MAP_CREATE_REMOTE, pid);
 
   return map_cursor->map_list == NULL;
 }
diff --git a/src/mips/Ginit.c b/src/mips/Ginit.c
index 308c047..d7dddae 100644
--- a/src/mips/Ginit.c
+++ b/src/mips/Ginit.c
@@ -209,6 +209,27 @@
   return elf_w (get_proc_name) (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
+static int
+access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
+                         int write, void *arg)
+{
+  if (write)
+    return -1;
+
+  *(unw_word_t *) (uintptr_t) addr = *val;
+  Debug (16, "mem[%llx] <- %llx\n", (long long) addr, (long long) *val);
+  return 0;
+}
+
+// This initializes just enough of the address space to call the
+// access memory function.
+PROTECTED void
+unw_local_access_addr_space_init (unw_addr_space_t as)
+{
+  memset (as, 0, sizeof (*as));
+  as->acc.access_mem = access_mem_unrestricted;
+}
+
 HIDDEN void
 mips_local_addr_space_init (void)
 {
diff --git a/src/os-linux.c b/src/os-linux.c
index 0265a16..ed69813 100644
--- a/src/os-linux.c
+++ b/src/os-linux.c
@@ -27,17 +27,21 @@
 #include <stdio.h>
 
 #include "libunwind_i.h"
+#include "libunwind-ptrace.h"
 #include "map_info.h"
 #include "os-linux.h"
 
 /* ANDROID support update. */
 HIDDEN struct map_info *
-map_create_list (pid_t pid)
+map_create_list (int map_create_type, pid_t pid)
 {
   struct map_iterator mi;
   unsigned long start, end, offset, flags;
   struct map_info *map_list = NULL;
   struct map_info *cur_map;
+  unw_addr_space_t as = NULL;
+  struct unw_addr_space local_as;
+  void* as_arg = NULL;
 
   if (maps_init (&mi, pid) < 0)
     return NULL;
@@ -74,13 +78,57 @@
           && !(cur_map->flags & MAP_FLAGS_DEVICE_MEM))
         {
           struct elf_image ei;
-          if (elf_map_image (&ei, cur_map->path))
+          // Do not map elf for local unwinds, it's faster to read
+          // from memory directly.
+          if (map_create_type == UNW_MAP_CREATE_REMOTE
+              && elf_map_image (&ei, cur_map->path))
             {
               unw_word_t load_base;
               if (elf_w (get_load_base) (&ei, offset, &load_base))
                 cur_map->load_base = load_base;
               munmap (ei.u.mapped.image, ei.u.mapped.size);
             }
+          else
+            {
+              // Create an address space right here with enough initialized
+              // to read data.
+              if (as == NULL)
+                {
+                  if (map_create_type == UNW_MAP_CREATE_LOCAL)
+                    {
+                      as = &local_as;
+                      unw_local_access_addr_space_init (as);
+                    }
+                  else
+                    {
+                      // For a remote unwind, create the address space
+                      // and arg data the first time we need it.
+                      // We'll reuse these values if we need to attempt
+                      // to get elf data for another map.
+                      as = unw_create_addr_space (&_UPT_accessors, 0);
+                      if (as)
+                        {
+                          as_arg = (void*) _UPT_create (pid);
+                          if (!as_arg)
+                            {
+                              unw_destroy_addr_space (as);
+                              as = NULL;
+                            }
+                        }
+                    }
+                }
+              if (as)
+                {
+                  ei.mapped = false;
+                  ei.u.memory.map = cur_map;
+                  ei.u.memory.as = as;
+                  ei.u.memory.as_arg = as_arg;
+                  ei.valid = elf_w (valid_object_memory) (&ei);
+                  unw_word_t load_base;
+                  if (ei.valid && elf_w (get_load_base) (&ei, cur_map->offset, &load_base))
+                    cur_map->load_base = load_base;
+                }
+            }
         }
 
       map_list = cur_map;
@@ -88,6 +136,12 @@
 
   maps_close (&mi);
 
+  if (as && map_create_type == UNW_MAP_CREATE_REMOTE)
+    {
+      unw_destroy_addr_space (as);
+      _UPT_destroy (as_arg);
+    }
+
   return map_list;
 }
 /* End of ANDROID update. */
diff --git a/src/x86/Ginit.c b/src/x86/Ginit.c
index b9da78a..0ecb6be 100644
--- a/src/x86/Ginit.c
+++ b/src/x86/Ginit.c
@@ -257,6 +257,27 @@
   return _Uelf32_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
+static int
+access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
+                         int write, void *arg)
+{
+  if (write)
+    return -1;
+
+  *val = *(unw_word_t *) addr;
+  Debug (16, "mem[%x] -> %x\n", addr, *val);
+  return 0;
+}
+
+// This initializes just enough of the address space to call the
+// access memory function.
+PROTECTED void
+unw_local_access_addr_space_init (unw_addr_space_t as)
+{
+  memset (as, 0, sizeof (*as));
+  as->acc.access_mem = access_mem_unrestricted;
+}
+
 HIDDEN void
 x86_local_addr_space_init (void)
 {
diff --git a/src/x86_64/Ginit.c b/src/x86_64/Ginit.c
index db18485..468ca99 100644
--- a/src/x86_64/Ginit.c
+++ b/src/x86_64/Ginit.c
@@ -276,6 +276,27 @@
   return _Uelf64_get_proc_name (as, getpid (), ip, buf, buf_len, offp, arg);
 }
 
+static int
+access_mem_unrestricted (unw_addr_space_t as, unw_word_t addr, unw_word_t *val,
+                         int write, void *arg)
+{
+  if (write)
+    return -1;
+
+  *val = *(unw_word_t *) addr;
+  Debug (16, "mem[%016lx] -> %lx\n", addr, *val);
+  return 0;
+}
+
+// This initializes just enough of the address space to call the
+// access memory function.
+PROTECTED void
+unw_local_access_addr_space_init (unw_addr_space_t as)
+{
+  memset (as, 0, sizeof (*as));
+  as->acc.access_mem = access_mem_unrestricted;
+}
+
 HIDDEN void
 x86_64_local_addr_space_init (void)
 {