| 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..00d18189d6683030153b0b231f8eaa8597738ef4 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,13 @@ bool LinuxDumper::Init() {
|
| return ReadAuxv() && EnumerateThreads() && EnumerateMappings();
|
| }
|
|
|
| +bool LinuxDumper::LateInit() {
|
| +#if defined(__ANDROID__)
|
| + LatePostprocessMappings();
|
| +#endif
|
| + return true;
|
| +}
|
| +
|
| bool
|
| LinuxDumper::ElfFileIdentifierForMapping(const MappingInfo& mapping,
|
| bool member,
|
| @@ -395,6 +418,108 @@ bool LinuxDumper::EnumerateMappings() {
|
| return !mappings_.empty();
|
| }
|
|
|
| +#if defined(__ANDROID__)
|
| +
|
| +bool LinuxDumper::GetLoadedElfHeader(uintptr_t start_addr, ElfW(Ehdr)* ehdr) {
|
| + CopyFromProcess(ehdr, pid_,
|
| + reinterpret_cast<const void*>(start_addr),
|
| + sizeof(*ehdr));
|
| + return my_memcmp(&ehdr->e_ident, ELFMAG, SELFMAG) == 0;
|
| +}
|
| +
|
| +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) {
|
| + uintptr_t phdr_addr = start_addr + ehdr->e_phoff;
|
| +
|
| + const uintptr_t max_addr = UINTPTR_MAX;
|
| + 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) {
|
| + 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);
|
| + }
|
| +
|
| + *min_vaddr_ptr = min_vaddr;
|
| + *dyn_vaddr_ptr = dyn_vaddr;
|
| + *dyn_count_ptr = dyn_count;
|
| +}
|
| +
|
| +bool LinuxDumper::HasAndroidPackedRelocations(uintptr_t load_bias,
|
| + uintptr_t dyn_vaddr,
|
| + size_t dyn_count) {
|
| + uintptr_t dyn_addr = load_bias + dyn_vaddr;
|
| + 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;
|
| +}
|
| +
|
| +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;
|
| + 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;
|
| +}
|
| +
|
| +void 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[0] == '/')) {
|
| + continue;
|
| + }
|
| + ElfW(Ehdr) ehdr;
|
| + if (!GetLoadedElfHeader(mapping->start_addr, &ehdr)) {
|
| + continue;
|
| + }
|
| + 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);
|
| + }
|
| + }
|
| +}
|
| +
|
| +#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.
|
|
|