diff options
author | Ole André Vadla Ravnås <oleavr@gmail.com> | 2020-11-12 04:25:58 +0100 |
---|---|---|
committer | Dave Watson <dade.watson@gmail.com> | 2020-12-03 07:22:38 -0800 |
commit | 3f7ab0b7ca447e5038fd2050c0c660f88125e7b0 (patch) | |
tree | cb9d840605ad5c5652e11b0491cb62e5c812c134 | |
parent | cee5505a99d42a423059a1add8b87b75aeb45daa (diff) | |
download | libunwind-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.h | 3 | ||||
-rw-r--r-- | include/tdep-arm/libunwind_i.h | 1 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/arm/Gglobal.c | 5 | ||||
-rw-r--r-- | src/coredump/_UPT_get_dyn_info_list_addr.c | 2 | ||||
-rw-r--r-- | src/dl-iterate-phdr.c | 95 | ||||
-rw-r--r-- | src/dwarf/Gfind_proc_info-lsb.c | 2 | ||||
-rw-r--r-- | src/os-linux.c | 2 | ||||
-rw-r--r-- | src/os-linux.h | 19 | ||||
-rw-r--r-- | src/os-solaris.c | 2 | ||||
-rw-r--r-- | src/ptrace/_UPT_get_dyn_info_list_addr.c | 2 | ||||
-rw-r--r-- | src/x86/Gos-linux.c | 4 |
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; } |