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);
}