summaryrefslogtreecommitdiff
path: root/src/dl-iterate-phdr.c
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 /src/dl-iterate-phdr.c
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.
Diffstat (limited to 'src/dl-iterate-phdr.c')
-rw-r--r--src/dl-iterate-phdr.c95
1 files changed, 95 insertions, 0 deletions
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