mirror of
https://github.com/chromium/crashpad.git
synced 2025-03-09 14:06:33 +00:00
android: handle modules loaded from zipfiles
Modules mapped from zipfiles will have mappings named for the zipfile rather than the module name and an offset into that zipfile instead of 0. Bug: crashpad:253, crashpad:254 Change-Id: I0503d13e7b80ba7bd1cc2d241633d9c68c98f1cd Reviewed-on: https://chromium-review.googlesource.com/1232294 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
9ae453628f
commit
688dcfa22e
@ -467,6 +467,20 @@ uint16_t ElfImageReader::FileType() const {
|
||||
return memory_.Is64Bit() ? header_64_.e_type : header_32_.e_type;
|
||||
}
|
||||
|
||||
bool ElfImageReader::SoName(std::string* name) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
if (!InitializeDynamicArray()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
VMSize offset;
|
||||
if (!dynamic_array_->GetValue(DT_SONAME, true, &offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ReadDynamicStringTableAtOffset(offset, name);
|
||||
}
|
||||
|
||||
bool ElfImageReader::GetDynamicSymbol(const std::string& name,
|
||||
VMAddress* address,
|
||||
VMSize* size) {
|
||||
|
@ -149,6 +149,13 @@ class ElfImageReader {
|
||||
//! The load bias is the actual load address minus the preferred load address.
|
||||
VMOffset GetLoadBias() const { return load_bias_; }
|
||||
|
||||
//! \brief Determines the name of this object using `DT_SONAME`, if present.
|
||||
//!
|
||||
//! \param[out] name The name of this object, only valid if this method
|
||||
//! returns `true`.
|
||||
//! \return `true` if a name was found for this object.
|
||||
bool SoName(std::string* name);
|
||||
|
||||
//! \brief Reads information from the dynamic symbol table about the symbol
|
||||
//! identified by \a name.
|
||||
//!
|
||||
|
@ -433,7 +433,12 @@ void ProcessReaderLinux::InitializeModules() {
|
||||
}
|
||||
|
||||
Module module = {};
|
||||
module.name = !entry.name.empty() ? entry.name : module_mapping->name;
|
||||
std::string soname;
|
||||
if (elf_reader->SoName(&soname) && !soname.empty()) {
|
||||
module.name = soname;
|
||||
} else {
|
||||
module.name = !entry.name.empty() ? entry.name : module_mapping->name;
|
||||
}
|
||||
module.elf_reader = elf_reader.get();
|
||||
module.type = loader_base && elf_reader->Address() == loader_base
|
||||
? ModuleSnapshot::kModuleTypeDynamicLoader
|
||||
|
@ -349,8 +349,13 @@ std::vector<const MemoryMap::Mapping*> MemoryMap::FindFilePossibleMmapStarts(
|
||||
|
||||
for (const auto& candidate : mappings_) {
|
||||
if (candidate.device == mapping.device &&
|
||||
candidate.inode == mapping.inode &&
|
||||
candidate.offset == 0) {
|
||||
candidate.inode == mapping.inode
|
||||
#if !defined(OS_ANDROID)
|
||||
// Libraries on Android may be mapped from zipfiles (APKs), in which
|
||||
// case the offset is not 0.
|
||||
&& candidate.offset == 0
|
||||
#endif // !defined(OS_ANDROID)
|
||||
) {
|
||||
possible_starts.push_back(&candidate);
|
||||
}
|
||||
if (mapping.Equals(candidate)) {
|
||||
|
@ -76,14 +76,19 @@ class MemoryMap {
|
||||
//! it was obtained from.
|
||||
const Mapping* FindMappingWithName(const std::string& name) const;
|
||||
|
||||
//! \brief Find Mappings that share a Mapping's file, mapped from offset 0.
|
||||
//! \brief Find possible initial mappings of files mapped over several
|
||||
//! segments.
|
||||
//!
|
||||
//! Executables and libaries are typically loaded into several mappings with
|
||||
//! varying permissions for different segments. Portions of an ELF file may
|
||||
//! be mapped multiple times as part of loading the file, for example, when
|
||||
//! initializing GNU_RELRO segments. This method searches for mappings at or
|
||||
//! below \a mapping in memory that are mapped from the same file as \a
|
||||
//! mapping from offset 0.
|
||||
//! initializing GNU_RELRO segments.
|
||||
//!
|
||||
//! This method searches for mappings at or below \a mapping in memory that
|
||||
//! are mapped from the same file as \a mapping from offset 0.
|
||||
//!
|
||||
//! On Android, ELF modules may be loaded from within a zipfile, so this
|
||||
//! method may return mappings whose offset is not 0.
|
||||
//!
|
||||
//! This method is intended to help identify the possible base address for
|
||||
//! loaded modules, but it is the caller's responsibility to determine which
|
||||
|
@ -384,8 +384,12 @@ void ExpectFindFilePossibleMmapStarts(LinuxVMAddress mapping_start,
|
||||
EXPECT_EQ(mappings[0], mapping2);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(mappings.size(), 2u);
|
||||
#else
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
||||
@ -430,6 +434,16 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
||||
|
||||
std::vector<const MemoryMap::Mapping*> mappings;
|
||||
|
||||
#if defined(OS_ANDROID)
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
EXPECT_EQ(mappings.size(), 1u);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping2);
|
||||
EXPECT_EQ(mappings.size(), 2u);
|
||||
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||
EXPECT_EQ(mappings.size(), 3u);
|
||||
#else
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping1);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
@ -441,6 +455,7 @@ TEST(MemoryMap, FindFilePossibleMmapStarts) {
|
||||
mappings = map.FindFilePossibleMmapStarts(*mapping3);
|
||||
ASSERT_EQ(mappings.size(), 1u);
|
||||
EXPECT_EQ(mappings[0], mapping1);
|
||||
#endif
|
||||
|
||||
#if defined(ARCH_CPU_64_BITS)
|
||||
constexpr bool is_64_bit = true;
|
||||
@ -562,27 +577,47 @@ TEST(MemoryMap, FindFilePossibleMmapStarts_MultipleStarts) {
|
||||
auto mapping = map.FindMapping(file_mapping0.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
auto possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 1u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 0u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping1.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 2u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 1u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping2.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 3u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 2u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping3.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 4u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 3u);
|
||||
#endif
|
||||
|
||||
mapping = map.FindMapping(file_mapping4.addr_as<VMAddress>());
|
||||
ASSERT_TRUE(mapping);
|
||||
possible_starts = map.FindFilePossibleMmapStarts(*mapping);
|
||||
#if defined(OS_ANDROID)
|
||||
EXPECT_EQ(possible_starts.size(), 5u);
|
||||
#else
|
||||
EXPECT_EQ(possible_starts.size(), 4u);
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
Loading…
x
Reference in New Issue
Block a user