Chromium Code Reviews| 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..a06db8f920500927d47d9125d8a65fade300fc22 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,127 @@ bool LinuxDumper::EnumerateMappings() { |
| return !mappings_.empty(); |
| } |
| +#if defined(__ANDROID__) |
| + |
| +// Read the memory at start_addr, expecting to find an ELF header. The first |
|
Lei Zhang
2015/06/18 21:45:37
Comments should go in the header. Ditto below.
simonb (inactive)
2015/06/19 12:19:27
Done.
|
| +// 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) { |
|
Lei Zhang
2015/06/18 21:45:37
Just: return (my_memcmp(...) != 0); ?
simonb (inactive)
2015/06/19 12:19:27
Done.
|
| + 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) { |
| + uintptr_t phdr_addr = start_addr + ehdr->e_phoff; |
|
Lei Zhang
2015/06/18 21:45:37
Can this or the addition to |phdr_addr| below over
simonb (inactive)
2015/06/19 12:19:27
To somewhat amplify Primiano's comment below... no
|
| + |
| + 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; |
| +} |
| + |
| +// Retrieve and check dynamic tags, and return true if tags for 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) { |
| + uintptr_t dyn_addr = load_bias + dyn_vaddr; |
|
Lei Zhang
2015/06/18 21:45:37
Can this or the addition to |dyn_addr| below overf
Primiano Tucci (use gerrit)
2015/06/18 21:56:13
but in that case CopyFromProcess will just fill u
|
| + 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, |
|
Lei Zhang
2015/06/18 21:45:37
min vaddr -> |min_vaddr|
simonb (inactive)
2015/06/19 12:19:28
Done.
|
| + // return the effective load_bias. |
| + if (min_vaddr != 0) { |
| + const uintptr_t load_bias = start_addr - min_vaddr; |
|
Lei Zhang
2015/06/18 21:45:37
Is |min_vaddr| guaranteeded to be less than |start
simonb (inactive)
2015/06/19 12:19:27
Done.
Lei Zhang
2015/06/19 18:59:28
Can I get a yes/no answer on this question?
simonb (inactive)
2015/06/22 16:52:42
Sorry, mis-clicked Done here.
What all of this co
|
| + 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 |
|
Lei Zhang
2015/06/18 21:45:38
|mappings_|
simonb (inactive)
2015/06/19 12:19:27
Done.
|
| +// 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[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); |
| + } |
| + } |
| + return true; |
|
Lei Zhang
2015/06/18 21:45:37
This function can't return anything but true as is
simonb (inactive)
2015/06/19 12:19:27
Done.
I have left LateInit() returning bool for n
|
| +} |
| + |
| +#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. |