summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOle André Vadla Ravnås <oleavr@gmail.com>2020-11-12 04:25:58 +0100
committerDave Watson <dade.watson@gmail.com>2020-12-03 07:22:38 -0800
commit3f7ab0b7ca447e5038fd2050c0c660f88125e7b0 (patch)
treecb9d840605ad5c5652e11b0491cb62e5c812c134
parentcee5505a99d42a423059a1add8b87b75aeb45daa (diff)
downloadlibunwind-3f7ab0b7ca447e5038fd2050c0c660f88125e7b0.tar.gz
Add support for older versions of Android
Based on: - dl_iterate_phdr() patch by Jeff Muizelaar. - maps_next() improvement from AOSP: 7d46a21. - unwi_unwind_method and x86_local_resume() from AOSP: 1c82a52.
-rw-r--r--include/dwarf.h3
-rw-r--r--include/tdep-arm/libunwind_i.h1
-rw-r--r--src/Makefile.am2
-rw-r--r--src/arm/Gglobal.c5
-rw-r--r--src/coredump/_UPT_get_dyn_info_list_addr.c2
-rw-r--r--src/dl-iterate-phdr.c95
-rw-r--r--src/dwarf/Gfind_proc_info-lsb.c2
-rw-r--r--src/os-linux.c2
-rw-r--r--src/os-linux.h19
-rw-r--r--src/os-solaris.c2
-rw-r--r--src/ptrace/_UPT_get_dyn_info_list_addr.c2
-rw-r--r--src/x86/Gos-linux.c4
12 files changed, 132 insertions, 7 deletions
diff --git a/include/dwarf.h b/include/dwarf.h
index 4ab8b0e8..175c419b 100644
--- a/include/dwarf.h
+++ b/include/dwarf.h
@@ -46,6 +46,9 @@ struct elf_dyn_info;
#else
#error Could not find <link.h>
#endif
+ #if defined(__ANDROID__) && defined(__arm__) && __ANDROID_API__ < 21
+ int dl_iterate_phdr(int (*)(struct dl_phdr_info *, size_t, void *), void *);
+ #endif
#endif
#include <pthread.h>
diff --git a/include/tdep-arm/libunwind_i.h b/include/tdep-arm/libunwind_i.h
index 36ceca38..88ebfb06 100644
--- a/include/tdep-arm/libunwind_i.h
+++ b/include/tdep-arm/libunwind_i.h
@@ -320,6 +320,7 @@ extern void tdep_stash_frame (struct dwarf_cursor *c,
#define UNW_ARM_METHOD_DWARF 0x01
#define UNW_ARM_METHOD_FRAME 0x02
#define UNW_ARM_METHOD_EXIDX 0x04
+#define UNW_ARM_METHOD_LR 0x08
#define unwi_unwind_method UNW_OBJ(unwind_method)
extern int unwi_unwind_method;
diff --git a/src/Makefile.am b/src/Makefile.am
index 4b146bcd..ca126acc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -147,7 +147,7 @@ libunwind_la_SOURCES_local = \
$(libunwind_la_SOURCES_local_unwind)
noinst_HEADERS += os-linux.h
-libunwind_la_SOURCES_os_linux = os-linux.c
+libunwind_la_SOURCES_os_linux = os-linux.c dl-iterate-phdr.c
libunwind_la_SOURCES_os_hpux = os-hpux.c
diff --git a/src/arm/Gglobal.c b/src/arm/Gglobal.c
index 2fb1d211..0700f930 100644
--- a/src/arm/Gglobal.c
+++ b/src/arm/Gglobal.c
@@ -29,7 +29,12 @@ HIDDEN define_lock (arm_lock);
HIDDEN atomic_bool tdep_init_done = 0;
/* Unwinding methods to use. See UNW_METHOD_ enums */
+#if defined(__ANDROID__)
+/* Android only supports three types of unwinding methods. */
+HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_DWARF | UNW_ARM_METHOD_EXIDX | UNW_ARM_METHOD_LR;
+#else
HIDDEN int unwi_unwind_method = UNW_ARM_METHOD_ALL;
+#endif
HIDDEN void
tdep_init (void)
diff --git a/src/coredump/_UPT_get_dyn_info_list_addr.c b/src/coredump/_UPT_get_dyn_info_list_addr.c
index dcc6f8ea..c411cccc 100644
--- a/src/coredump/_UPT_get_dyn_info_list_addr.c
+++ b/src/coredump/_UPT_get_dyn_info_list_addr.c
@@ -43,7 +43,7 @@ get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
int count = 0;
maps_init (&mi, ui->pid);
- while (maps_next (&mi, &lo, &hi, &off))
+ while (maps_next (&mi, &lo, &hi, &off, NULL))
{
if (off)
continue;
diff --git a/src/dl-iterate-phdr.c b/src/dl-iterate-phdr.c
new file mode 100644
index 00000000..65e3a007
--- /dev/null
+++ b/src/dl-iterate-phdr.c
@@ -0,0 +1,95 @@
+/* libunwind - a platform-independent unwind library
+ Copyright (C) 2003-2005 Hewlett-Packard Co
+ Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
+
+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. */
+
+#if defined(__ANDROID__) && __ANDROID_API__ < 21
+
+#include <dlfcn.h>
+#include <link.h>
+
+#include "libunwind_i.h"
+#include "os-linux.h"
+
+#ifndef IS_ELF
+/* Copied from NDK header. */
+#define IS_ELF(ehdr) ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+ (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+ (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+ (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+#endif
+
+typedef int (*unw_iterate_phdr_impl) (int (*callback) (
+ struct dl_phdr_info *info,
+ size_t size, void *data),
+ void *data);
+
+HIDDEN int
+dl_iterate_phdr (int (*callback) (struct dl_phdr_info *info, size_t size, void *data),
+ void *data)
+{
+ static int initialized = 0;
+ static unw_iterate_phdr_impl libc_impl;
+ int rc = 0;
+ struct map_iterator mi;
+ unsigned long start, end, offset, flags;
+
+ if (!initialized)
+ {
+ libc_impl = dlsym (RTLD_NEXT, "dl_iterate_phdr");
+ initialized = 1;
+ }
+
+ if (libc_impl != NULL)
+ return libc_impl (callback, data);
+
+ if (maps_init (&mi, getpid()) < 0)
+ return -1;
+
+ while (maps_next (&mi, &start, &end, &offset, &flags))
+ {
+ Elf_W(Ehdr) *ehdr = (Elf_W(Ehdr) *) start;
+ Dl_info canonical_info;
+
+ if (mi.path[0] != '\0' && (flags & PROT_EXEC) != 0 && IS_ELF (*ehdr)
+ && dladdr (ehdr, &canonical_info) == 0
+ && ehdr == canonical_info.dli_fbase)
+ {
+ struct dl_phdr_info info;
+ Elf_W(Phdr) *phdr = (Elf_W(Phdr) *) (start + ehdr->e_phoff);
+
+ info.dlpi_addr = start;
+ info.dlpi_name = canonical_info.dli_fname;
+ info.dlpi_phdr = phdr;
+ info.dlpi_phnum = ehdr->e_phnum;
+
+ rc = callback (&info, sizeof (info), data);
+ }
+ }
+
+ maps_close (&mi);
+
+ return rc;
+}
+
+#endif
diff --git a/src/dwarf/Gfind_proc_info-lsb.c b/src/dwarf/Gfind_proc_info-lsb.c
index 0496ca7e..1f48714e 100644
--- a/src/dwarf/Gfind_proc_info-lsb.c
+++ b/src/dwarf/Gfind_proc_info-lsb.c
@@ -212,7 +212,7 @@ find_binary_for_address (unw_word_t ip, char *name, size_t name_size)
if (maps_init (&mi, pid) != 0)
return 1;
- while (maps_next (&mi, &segbase, &hi, &mapoff))
+ while (maps_next (&mi, &segbase, &hi, &mapoff, NULL))
if (ip >= segbase && ip < hi)
{
size_t len = strlen (mi.path);
diff --git a/src/os-linux.c b/src/os-linux.c
index d233fd40..c42d2c5f 100644
--- a/src/os-linux.c
+++ b/src/os-linux.c
@@ -46,7 +46,7 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
if (maps_init (&mi, pid) < 0)
return -1;
- while (maps_next (&mi, segbase, &hi, mapoff))
+ while (maps_next (&mi, segbase, &hi, mapoff, NULL))
if (ip >= *segbase && ip < hi)
{
found = 1;
diff --git a/src/os-linux.h b/src/os-linux.h
index 5a9b0b40..29aab5cf 100644
--- a/src/os-linux.h
+++ b/src/os-linux.h
@@ -201,7 +201,8 @@ scan_string (char *cp, char *valp, size_t buf_size)
static inline int
maps_next (struct map_iterator *mi,
- unsigned long *low, unsigned long *high, unsigned long *offset)
+ unsigned long *low, unsigned long *high, unsigned long *offset,
+ unsigned long *flags)
{
char perm[16], dash = 0, colon = 0, *cp;
unsigned long major, minor, inum;
@@ -275,6 +276,22 @@ maps_next (struct map_iterator *mi,
cp = scan_string (cp, NULL, 0);
if (dash != '-' || colon != ':')
continue; /* skip line with unknown or bad format */
+ if (flags)
+ {
+ *flags = 0;
+ if (perm[0] == 'r')
+ {
+ *flags |= PROT_READ;
+ }
+ if (perm[1] == 'w')
+ {
+ *flags |= PROT_WRITE;
+ }
+ if (perm[2] == 'x')
+ {
+ *flags |= PROT_EXEC;
+ }
+ }
return 1;
}
return 0;
diff --git a/src/os-solaris.c b/src/os-solaris.c
index 3c140ef2..f0210db1 100644
--- a/src/os-solaris.c
+++ b/src/os-solaris.c
@@ -41,7 +41,7 @@ tdep_get_elf_image (struct elf_image *ei, pid_t pid, unw_word_t ip,
if (maps_init (&mi, pid) < 0)
return -1;
- while (maps_next (&mi, segbase, &hi, mapoff))
+ while (maps_next (&mi, segbase, &hi, mapoff, NULL))
if (ip >= *segbase && ip < hi)
{
found = 1;
diff --git a/src/ptrace/_UPT_get_dyn_info_list_addr.c b/src/ptrace/_UPT_get_dyn_info_list_addr.c
index f2864abc..a71f80d3 100644
--- a/src/ptrace/_UPT_get_dyn_info_list_addr.c
+++ b/src/ptrace/_UPT_get_dyn_info_list_addr.c
@@ -41,7 +41,7 @@ get_list_addr (unw_addr_space_t as, unw_word_t *dil_addr, void *arg,
int count = 0;
maps_init (&mi, ui->pid);
- while (maps_next (&mi, &lo, &hi, &off))
+ while (maps_next (&mi, &lo, &hi, &off, NULL))
{
if (off)
continue;
diff --git a/src/x86/Gos-linux.c b/src/x86/Gos-linux.c
index fb9a5e34..d448dce7 100644
--- a/src/x86/Gos-linux.c
+++ b/src/x86/Gos-linux.c
@@ -298,12 +298,16 @@ x86_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
Debug (8, "resuming at ip=%x via sigreturn(%p)\n", c->dwarf.ip, sc);
+#if !defined(__ANDROID__)
x86_sigreturn (sc);
+#endif
}
else
{
Debug (8, "resuming at ip=%x via setcontext()\n", c->dwarf.ip);
+#if !defined(__ANDROID__)
setcontext (uc);
+#endif
}
return -UNW_EINVAL;
}