Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(236)

Unified Diff: client/linux/minidump_writer/linux_dumper.cc

Issue 1189823002: Update breakpad for Android packed relocations. (Closed) Base URL: https://chromium.googlesource.com/external/google-breakpad/src.git@master
Patch Set: memcmp -> my_memcmp Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: client/linux/minidump_writer/linux_dumper.cc
diff --git a/client/linux/minidump_writer/linux_dumper.cc b/client/linux/minidump_writer/linux_dumper.cc
index ebb008d6692e6ffa5d7a788db811c4076cf35d11..da03380c697a73ed3cef32bb591717e014d0cb6f 100644
--- a/client/linux/minidump_writer/linux_dumper.cc
+++ b/client/linux/minidump_writer/linux_dumper.cc
@@ -52,6 +52,22 @@
#include "common/linux/safe_readlink.h"
#include "third_party/lss/linux_syscall_support.h"
+#if defined(__ANDROID__)
+
+// Android packed relocations definitions are not yet available from the
+// NDK header files, so we have to provide them manually here.
+#ifndef DT_LOOS
+#define DT_LOOS 0x6000000d
+#endif
+#ifndef DT_ANDROID_REL
+static const int DT_ANDROID_REL = DT_LOOS + 2;
+#endif
+#ifndef DT_ANDROID_RELA
+static const int DT_ANDROID_RELA = DT_LOOS + 4;
+#endif
+
+#endif // __ANDROID __
+
static const char kMappedFileUnsafePrefix[] = "/dev/";
static const char kDeletedSuffix[] = " (deleted)";
static const char kReservedFlags[] = " ---p";
@@ -92,6 +108,14 @@ bool LinuxDumper::Init() {
return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
}
+bool LinuxDumper::LateInit() {
+#if defined(__ANDROID__)
+ return LatePostprocessMappings();
+#else
+ return true;
+#endif
+}
+
bool
LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
bool member,
@@ -395,6 +419,128 @@ bool LinuxDumper::EnumerateMappings() {
return !mappings_.empty();
}
+#if defined(__ANDROID__)
+
+// Read the memory at start_addr, expecting to find an ELF header. The first
+// LOAD segment in an ELF shared library has offset zero, so the ELF file
+// header is at the start of this map entry, and in already mapped memory.
+bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) {
+ CopyFromProcess(ehdr, pid_,
+ reinterpret_cast<const void*>(start_addr),
+ sizeof(*ehdr));
+ if (my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
+ return false;
+ }
+ return true;
+}
+
+// Iterate ELF program headers to find the min vaddr of LOAD segments, and
+// the vaddr and count of entries for the DYNAMIC table. The program header
+// table is also in already mapped memory.
+void LinuxDumper::ParseLoadedElfProgramHeaders(ElfW(Ehdr)* ehdr,
+ uintptr_t start_addr,
+ uintptr_t* min_vaddr_ptr,
+ uintptr_t* dyn_vaddr_ptr,
+ size_t* dyn_count_ptr) {
+ uint8_t* phdr_addr = reinterpret_cast<uint8_t*>(start_addr) + ehdr->e_phoff;
+
+ const uintptr_t max_addr = ~static_cast<uintptr_t>(0);
Primiano Tucci (use gerrit) 2015/06/18 10:59:38 Isn't this just UINTPTR_MAX from stdint.h? Or is t
simonb (inactive) 2015/06/18 16:24:38 Done.
+ uintptr_t min_vaddr = max_addr;
+ uintptr_t dyn_vaddr = 0;
+ size_t dyn_count = 0;
+
+ for (size_t i = 0; i < ehdr->e_phnum; ++i) {
+ ElfW(Phdr) phdr;
+ CopyFromProcess(&phdr, pid_,
+ reinterpret_cast<const void*>(phdr_addr),
+ sizeof(phdr));
+ if (phdr.p_type == PT_LOAD && phdr.p_vaddr < min_vaddr) {
Primiano Tucci (use gerrit) 2015/06/18 10:59:38 Just doublechecking. I thought you meant to look f
simonb (inactive) 2015/06/18 16:24:38 I do want the min(vaddr). Typically this will be
+ min_vaddr = phdr.p_vaddr;
+ }
+ if (phdr.p_type == PT_DYNAMIC) {
+ dyn_vaddr = phdr.p_vaddr;
+ dyn_count = phdr.p_memsz / sizeof(ElfW(Dyn));
+ }
+ phdr_addr += sizeof(phdr);
+ }
+ assert(min_vaddr != max_addr);
rmcilroy 2015/06/18 09:42:10 Do we want to be a bit more permissive to failures
simonb (inactive) 2015/06/18 10:46:39 I don't think so. We strongly assume that a libra
rmcilroy 2015/06/18 17:13:36 Sure, but we wouldn't see a crash since this would
simonb (inactive) 2015/06/18 17:33:40 Okay, I've removed the assert. If we fail (inexpl
+
+ *min_vaddr_ptr = min_vaddr;
+ *dyn_vaddr_ptr = dyn_vaddr;
+ *dyn_count_ptr = dyn_count;
+}
+
+// Retrieve and check dynamic tags, checking for the telltale that marks
rmcilroy 2015/06/18 09:42:10 nit - "Retrieve and check dynamic task, returning
simonb (inactive) 2015/06/18 10:46:39 Done.
+// Android packed relocations as present. Dynamic tags are found at dyn_vaddr
+// past the load_bias.
+bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias,
+ uintptr_t dyn_vaddr,
+ size_t dyn_count) {
+ uint8_t* dyn_addr = reinterpret_cast<uint8_t*>(load_bias) + dyn_vaddr;
Primiano Tucci (use gerrit) 2015/06/18 10:59:38 I think (dyn_addr) this can stay an uintptr_t with
simonb (inactive) 2015/06/18 16:24:38 Done. Also phdr_addr at 445 above.
+ for (size_t i = 0; i < dyn_count; ++i) {
+ ElfW(Dyn) dyn;
+ CopyFromProcess(&dyn, pid_,
+ reinterpret_cast<const void*>(dyn_addr),
+ sizeof(dyn));
+ if (dyn.d_tag == DT_ANDROID_REL || dyn.d_tag == DT_ANDROID_RELA) {
+ return true;
+ }
+ dyn_addr += sizeof(dyn);
+ }
+ return false;
+}
+
+// Return the effective load_bias, used by the system linker (or Chromium
+// crazy linker) for the ELF shared library mapped at the given start_addr.
+// The effective load_bias is start_addr adjusted downwards by the min vaddr
+// in the library LOAD segments.
+uintptr_t LinuxDumper::GetEffectiveLoadBias(ElfW(Ehdr)* ehdr,
+ uintptr_t start_addr) {
+ uintptr_t min_vaddr = 0;
+ uintptr_t dyn_vaddr = 0;
+ size_t dyn_count = 0;
+ ParseLoadedElfProgramHeaders(ehdr, start_addr,
+ &min_vaddr, &dyn_vaddr, &dyn_count);
+ // If min vaddr is non-zero and we find Android packed relocation tags,
+ // return the effective load_bias.
+ if (min_vaddr != 0) {
+ const uintptr_t load_bias = start_addr - min_vaddr;
Primiano Tucci (use gerrit) 2015/06/18 10:59:38 should you also check here that min_vadr < start_a
simonb (inactive) 2015/06/18 16:24:38 Not sure this would offer much protection. If the
+ if (HasAndroidPackedRelocations(load_bias, dyn_vaddr, dyn_count)) {
+ return load_bias;
+ }
+ }
+ // Either min vaddr is zero, or it is non-zero but we did not find the
+ // expected Android packed relocations tags.
+ return start_addr;
+}
+
+// Iterate mappings_, and adjust any start_addr fields that are for mapped
+// libraries that contain Android packed relocations.
+bool LinuxDumper::LatePostprocessMappings() {
+ for (size_t i = 0; i < mappings_.size(); ++i) {
+ // Only consider exec mappings that indicate a file path was mapped, and
+ // where the ELF header indicates a mapped shared library.
+ MappingInfo* mapping = mappings_[i];
+ if (!(mapping->exec && mapping->name && mapping->name[0] == '/')) {
Primiano Tucci (use gerrit) 2015/06/18 10:59:38 I think you don't really need the middle check (ma
simonb (inactive) 2015/06/18 16:24:38 Done (and thanks, I know from annoying prior exper
+ continue;
+ }
+ ElfW(Ehdr) ehdr;
+ if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) {
+ return false;
Primiano Tucci (use gerrit) 2015/06/18 10:59:38 Hmm should you really return here or just continue
simonb (inactive) 2015/06/18 16:24:38 Done.
+ }
+ if (ehdr.e_type == ET_DYN) {
+ // Compute the effective load_bias for this mapped library, and update
+ // the mapping to hold that rather than start_addr. Where the library
+ // does not contain Android packed relocations, GetEffectiveLoadBias()
+ // returns start_addr and the mapping entry is not changed.
+ mapping->start_addr = GetEffectiveLoadBias(&ehdr, mapping->start_addr);
+ }
+ }
+ return true;
+}
+
+#endif // __ANDROID__
+
// Get information about the stack, given the stack pointer. We don't try to
// walk the stack since we might not have all the information needed to do
// unwind. So we just grab, up to, 32k of stack.

Powered by Google App Engine
This is Rietveld 408576698