Loading libbacktrace/UnwindStackMap.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ bool UnwindStackMap::Build() { std::vector<std::string> search_libs_{"libart.so", "libartd.so"}; jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_)); #if !defined(NO_LIBDEXFILE_SUPPORT) dex_files_.reset(new unwindstack::DexFiles(process_memory_)); dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_)); #endif if (!stack_maps_->Parse()) { Loading libunwindstack/Android.bp +11 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,12 @@ cc_library_static { "DexFile.cpp", "DexFiles.cpp", ], target: { // Always disable optimizations for host to make it easier to debug. host: { cflags: ["-O0", "-g"], }, }, shared_libs: [ "libbase", Loading @@ -151,8 +157,13 @@ cc_test_library { vendor_available: false, defaults: ["libunwindstack_flags"], shared: { enabled: false, }, srcs: [ "tests/DexFileTest.cpp", "tests/DexFilesTest.cpp", ], local_include_dirs: ["include"], allow_undefined_symbols: true, Loading libunwindstack/DexFile.cpp +37 −16 Original line number Diff line number Diff line Loading @@ -52,10 +52,20 @@ DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, Map return nullptr; } void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, DexFileFromFile::~DexFileFromFile() { if (size_ != 0) { munmap(mapped_memory_, size_); } } bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset) { if (dex_file_ == nullptr) { return; return false; } if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) { return false; // The DEX offset is not within the bytecode of this dex file. } for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) { Loading @@ -82,16 +92,11 @@ void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name if (offset <= dex_offset && dex_offset < offset + size) { *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false); *method_offset = dex_offset - offset; return; return true; } } } } DexFileFromFile::~DexFileFromFile() { if (size_ != 0) { munmap(mapped_memory_, size_); } return false; } bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) { Loading Loading @@ -139,25 +144,41 @@ bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& } bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) { art::DexFile::Header header; if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) { memory_.resize(sizeof(art::DexFile::Header)); if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { return false; } if (!art::StandardDexFile::IsMagicValid(header.magic_) && !art::CompactDexFile::IsMagicValid(header.magic_)) { art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data()); bool modify_data_off = false; uint32_t file_size = header->file_size_; if (art::CompactDexFile::IsMagicValid(header->magic_)) { uint32_t computed_file_size; if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) { return false; } if (computed_file_size > file_size) { file_size = computed_file_size; modify_data_off = true; } } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) { return false; } memory_.resize(header.file_size_); if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) { memory_.resize(file_size); if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { return false; } header = reinterpret_cast<art::DexFile::Header*>(memory_.data()); if (modify_data_off) { header->data_off_ = header->file_size_; } art::DexFileLoader loader; std::string error_msg; auto dex = loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg); loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg); dex_file_.reset(dex.release()); return dex_file_ != nullptr; } Loading libunwindstack/DexFile.h +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ class DexFile { DexFile() = default; virtual ~DexFile() = default; void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); Loading libunwindstack/DexFiles.cpp +146 −7 Original line number Diff line number Diff line Loading @@ -24,23 +24,138 @@ #include <unwindstack/DexFiles.h> #include <unwindstack/MapInfo.h> #include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include "DexFile.h" namespace unwindstack { struct DEXFileEntry32 { uint32_t next; uint32_t prev; uint32_t dex_file; }; struct DEXFileEntry64 { uint64_t next; uint64_t prev; uint64_t dex_file; }; DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {} DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) : memory_(memory), search_libs_(search_libs) {} DexFiles::~DexFiles() { for (auto& entry : files_) { delete entry.second; } } void DexFiles::SetArch(ArchEnum arch) { switch (arch) { case ARCH_ARM: case ARCH_MIPS: case ARCH_X86: read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32; read_entry_func_ = &DexFiles::ReadEntry32; break; case ARCH_ARM64: case ARCH_MIPS64: case ARCH_X86_64: read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64; read_entry_func_ = &DexFiles::ReadEntry64; break; case ARCH_UNKNOWN: abort(); } } uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) { uint32_t entry; if (!memory_->ReadFully(addr, &entry, sizeof(entry))) { return 0; } return entry; } uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) { uint64_t entry; if (!memory_->ReadFully(addr, &entry, sizeof(entry))) { return 0; } return entry; } bool DexFiles::ReadEntry32() { DEXFileEntry32 entry; if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { entry_addr_ = 0; return false; } addrs_.push_back(entry.dex_file); entry_addr_ = entry.next; return true; } bool DexFiles::ReadEntry64() { DEXFileEntry64 entry; if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { entry_addr_ = 0; return false; } addrs_.push_back(entry.dex_file); entry_addr_ = entry.next; return true; } void DexFiles::Init(Maps* maps) { if (initialized_) { return; } initialized_ = true; entry_addr_ = 0; const std::string dex_debug_name("__art_debug_dexfiles"); for (MapInfo* info : *maps) { if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) { continue; } if (!search_libs_.empty()) { bool found = false; const char* lib = basename(info->name.c_str()); for (const std::string& name : search_libs_) { if (name == lib) { found = true; break; } } if (!found) { continue; } } Elf* elf = info->GetElf(memory_, true); uint64_t ptr; // Find first non-empty list (libart might be loaded multiple times). if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) { entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start); if (entry_addr_ != 0) { break; } } } } DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { // Lock while processing the data. std::lock_guard<std::mutex> guard(files_lock_); DexFile* dex_file; auto entry = files_.find(dex_file_offset); if (entry == files_.end()) { Loading @@ -52,14 +167,38 @@ DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { return dex_file; } void DexFiles::GetMethodInformation(uint64_t dex_file_offset, uint64_t dex_offset, MapInfo* info, bool DexFiles::GetAddr(size_t index, uint64_t* addr) { if (index < addrs_.size()) { *addr = addrs_[index]; return true; } if (entry_addr_ != 0 && (this->*read_entry_func_)()) { *addr = addrs_.back(); return true; } return false; } void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) { DexFile* dex_file = GetDexFile(dex_file_offset, info); if (dex_file != nullptr) { dex_file->GetMethodInformation(dex_offset, method_name, method_offset); std::lock_guard<std::mutex> guard(lock_); if (!initialized_) { Init(maps); } size_t index = 0; uint64_t addr; while (GetAddr(index++, &addr)) { if (addr < info->start || addr >= info->end) { continue; } void DexFiles::SetArch(ArchEnum) {} DexFile* dex_file = GetDexFile(addr, info); if (dex_file != nullptr && dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) { break; } } } } // namespace unwindstack Loading
libbacktrace/UnwindStackMap.cpp +1 −1 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ bool UnwindStackMap::Build() { std::vector<std::string> search_libs_{"libart.so", "libartd.so"}; jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_)); #if !defined(NO_LIBDEXFILE_SUPPORT) dex_files_.reset(new unwindstack::DexFiles(process_memory_)); dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_)); #endif if (!stack_maps_->Parse()) { Loading
libunwindstack/Android.bp +11 −0 Original line number Diff line number Diff line Loading @@ -128,6 +128,12 @@ cc_library_static { "DexFile.cpp", "DexFiles.cpp", ], target: { // Always disable optimizations for host to make it easier to debug. host: { cflags: ["-O0", "-g"], }, }, shared_libs: [ "libbase", Loading @@ -151,8 +157,13 @@ cc_test_library { vendor_available: false, defaults: ["libunwindstack_flags"], shared: { enabled: false, }, srcs: [ "tests/DexFileTest.cpp", "tests/DexFilesTest.cpp", ], local_include_dirs: ["include"], allow_undefined_symbols: true, Loading
libunwindstack/DexFile.cpp +37 −16 Original line number Diff line number Diff line Loading @@ -52,10 +52,20 @@ DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, Map return nullptr; } void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, DexFileFromFile::~DexFileFromFile() { if (size_ != 0) { munmap(mapped_memory_, size_); } } bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset) { if (dex_file_ == nullptr) { return; return false; } if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) { return false; // The DEX offset is not within the bytecode of this dex file. } for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) { Loading @@ -82,16 +92,11 @@ void DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name if (offset <= dex_offset && dex_offset < offset + size) { *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false); *method_offset = dex_offset - offset; return; return true; } } } } DexFileFromFile::~DexFileFromFile() { if (size_ != 0) { munmap(mapped_memory_, size_); } return false; } bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) { Loading Loading @@ -139,25 +144,41 @@ bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& } bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) { art::DexFile::Header header; if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) { memory_.resize(sizeof(art::DexFile::Header)); if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { return false; } if (!art::StandardDexFile::IsMagicValid(header.magic_) && !art::CompactDexFile::IsMagicValid(header.magic_)) { art::DexFile::Header* header = reinterpret_cast<art::DexFile::Header*>(memory_.data()); bool modify_data_off = false; uint32_t file_size = header->file_size_; if (art::CompactDexFile::IsMagicValid(header->magic_)) { uint32_t computed_file_size; if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) { return false; } if (computed_file_size > file_size) { file_size = computed_file_size; modify_data_off = true; } } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) { return false; } memory_.resize(header.file_size_); if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) { memory_.resize(file_size); if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { return false; } header = reinterpret_cast<art::DexFile::Header*>(memory_.data()); if (modify_data_off) { header->data_off_ = header->file_size_; } art::DexFileLoader loader; std::string error_msg; auto dex = loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg); loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg); dex_file_.reset(dex.release()); return dex_file_ != nullptr; } Loading
libunwindstack/DexFile.h +1 −1 Original line number Diff line number Diff line Loading @@ -32,7 +32,7 @@ class DexFile { DexFile() = default; virtual ~DexFile() = default; void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); Loading
libunwindstack/DexFiles.cpp +146 −7 Original line number Diff line number Diff line Loading @@ -24,23 +24,138 @@ #include <unwindstack/DexFiles.h> #include <unwindstack/MapInfo.h> #include <unwindstack/Maps.h> #include <unwindstack/Memory.h> #include "DexFile.h" namespace unwindstack { struct DEXFileEntry32 { uint32_t next; uint32_t prev; uint32_t dex_file; }; struct DEXFileEntry64 { uint64_t next; uint64_t prev; uint64_t dex_file; }; DexFiles::DexFiles(std::shared_ptr<Memory>& memory) : memory_(memory) {} DexFiles::DexFiles(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs) : memory_(memory), search_libs_(search_libs) {} DexFiles::~DexFiles() { for (auto& entry : files_) { delete entry.second; } } void DexFiles::SetArch(ArchEnum arch) { switch (arch) { case ARCH_ARM: case ARCH_MIPS: case ARCH_X86: read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32; read_entry_func_ = &DexFiles::ReadEntry32; break; case ARCH_ARM64: case ARCH_MIPS64: case ARCH_X86_64: read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64; read_entry_func_ = &DexFiles::ReadEntry64; break; case ARCH_UNKNOWN: abort(); } } uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) { uint32_t entry; if (!memory_->ReadFully(addr, &entry, sizeof(entry))) { return 0; } return entry; } uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) { uint64_t entry; if (!memory_->ReadFully(addr, &entry, sizeof(entry))) { return 0; } return entry; } bool DexFiles::ReadEntry32() { DEXFileEntry32 entry; if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { entry_addr_ = 0; return false; } addrs_.push_back(entry.dex_file); entry_addr_ = entry.next; return true; } bool DexFiles::ReadEntry64() { DEXFileEntry64 entry; if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { entry_addr_ = 0; return false; } addrs_.push_back(entry.dex_file); entry_addr_ = entry.next; return true; } void DexFiles::Init(Maps* maps) { if (initialized_) { return; } initialized_ = true; entry_addr_ = 0; const std::string dex_debug_name("__art_debug_dexfiles"); for (MapInfo* info : *maps) { if (!(info->flags & PROT_EXEC) || !(info->flags & PROT_READ) || info->offset != 0) { continue; } if (!search_libs_.empty()) { bool found = false; const char* lib = basename(info->name.c_str()); for (const std::string& name : search_libs_) { if (name == lib) { found = true; break; } } if (!found) { continue; } } Elf* elf = info->GetElf(memory_, true); uint64_t ptr; // Find first non-empty list (libart might be loaded multiple times). if (elf->GetGlobalVariable(dex_debug_name, &ptr) && ptr != 0) { entry_addr_ = (this->*read_entry_ptr_func_)(ptr + info->start); if (entry_addr_ != 0) { break; } } } } DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { // Lock while processing the data. std::lock_guard<std::mutex> guard(files_lock_); DexFile* dex_file; auto entry = files_.find(dex_file_offset); if (entry == files_.end()) { Loading @@ -52,14 +167,38 @@ DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { return dex_file; } void DexFiles::GetMethodInformation(uint64_t dex_file_offset, uint64_t dex_offset, MapInfo* info, bool DexFiles::GetAddr(size_t index, uint64_t* addr) { if (index < addrs_.size()) { *addr = addrs_[index]; return true; } if (entry_addr_ != 0 && (this->*read_entry_func_)()) { *addr = addrs_.back(); return true; } return false; } void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) { DexFile* dex_file = GetDexFile(dex_file_offset, info); if (dex_file != nullptr) { dex_file->GetMethodInformation(dex_offset, method_name, method_offset); std::lock_guard<std::mutex> guard(lock_); if (!initialized_) { Init(maps); } size_t index = 0; uint64_t addr; while (GetAddr(index++, &addr)) { if (addr < info->start || addr >= info->end) { continue; } void DexFiles::SetArch(ArchEnum) {} DexFile* dex_file = GetDexFile(addr, info); if (dex_file != nullptr && dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) { break; } } } } // namespace unwindstack