diff options
author | Christopher Ferris <cferris@google.com> | 2018-01-30 19:47:24 -0800 |
---|---|---|
committer | Christopher Ferris <cferris@google.com> | 2018-01-31 14:19:42 -0800 |
commit | d70ea5ea8511ae9b9ae57b17390e4027d20e3390 (patch) | |
tree | 958dc628f9a4d173076a54bc7d012d85ecc2473e /libbacktrace | |
parent | 01ba1157325a5e6572122f5d46cfd0376b75aa98 (diff) | |
download | system_core-d70ea5ea8511ae9b9ae57b17390e4027d20e3390.tar.gz system_core-d70ea5ea8511ae9b9ae57b17390e4027d20e3390.tar.bz2 system_core-d70ea5ea8511ae9b9ae57b17390e4027d20e3390.zip |
Move dex pc frame creation into libunwindstack.
Test: Compiles, all unit tests pass.
Test: Ran 137-cfi art test in interpreter and verified interpreter
Test: frames still show up.
Change-Id: Icea90194986faa733a873e8cf467fc2513eb5573
Diffstat (limited to 'libbacktrace')
-rw-r--r-- | libbacktrace/Android.bp | 8 | ||||
-rw-r--r-- | libbacktrace/UnwindDexFile.cpp | 162 | ||||
-rw-r--r-- | libbacktrace/UnwindDexFile.h | 70 | ||||
-rw-r--r-- | libbacktrace/UnwindStack.cpp | 93 | ||||
-rw-r--r-- | libbacktrace/UnwindStackMap.cpp | 32 | ||||
-rw-r--r-- | libbacktrace/UnwindStackMap.h | 14 | ||||
-rw-r--r-- | libbacktrace/unwind_dex_test.cpp | 273 |
7 files changed, 23 insertions, 629 deletions
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp index 14ae44564..10a4e4634 100644 --- a/libbacktrace/Android.bp +++ b/libbacktrace/Android.bp @@ -50,7 +50,6 @@ libbacktrace_sources = [ "BacktracePtrace.cpp", "thread_utils.c", "ThreadEntry.cpp", - "UnwindDexFile.cpp", "UnwindStack.cpp", "UnwindStackMap.cpp", ] @@ -110,10 +109,9 @@ cc_library { static_libs: ["libasync_safe"], }, vendor: { - cflags: ["-DNO_LIBDEXFILE"], - exclude_srcs: ["UnwindDexFile.cpp"], + cflags: ["-DNO_LIBDEXFILE_SUPPORT"], exclude_shared_libs: ["libdexfile"], - }, + } }, whole_static_libs: ["libdemangle"], } @@ -145,8 +143,6 @@ cc_test { "backtrace_test.cpp", "GetPss.cpp", "thread_utils.c", - - "unwind_dex_test.cpp", ], cflags: [ diff --git a/libbacktrace/UnwindDexFile.cpp b/libbacktrace/UnwindDexFile.cpp deleted file mode 100644 index 5780fbb9c..000000000 --- a/libbacktrace/UnwindDexFile.cpp +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdint.h> -#include <sys/mman.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include <memory> - -#include <android-base/unique_fd.h> - -#include <dex/code_item_accessors-no_art-inl.h> -#include <dex/compact_dex_file.h> -#include <dex/dex_file-inl.h> -#include <dex/dex_file_loader.h> -#include <dex/standard_dex_file.h> - -#include <unwindstack/MapInfo.h> -#include <unwindstack/Memory.h> - -#include "UnwindDexFile.h" - -UnwindDexFile* UnwindDexFile::Create(uint64_t dex_file_offset_in_memory, - unwindstack::Memory* memory, unwindstack::MapInfo* info) { - if (!info->name.empty()) { - std::unique_ptr<UnwindDexFileFromFile> dex_file(new UnwindDexFileFromFile); - if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) { - return dex_file.release(); - } - } - - std::unique_ptr<UnwindDexFileFromMemory> dex_file(new UnwindDexFileFromMemory); - if (dex_file->Open(dex_file_offset_in_memory, memory)) { - return dex_file.release(); - } - return nullptr; -} - -void UnwindDexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, - uint64_t* method_offset) { - if (dex_file_ == nullptr) { - return; - } - - for (uint32_t i = 0; i < dex_file_->NumClassDefs(); ++i) { - const art::DexFile::ClassDef& class_def = dex_file_->GetClassDef(i); - const uint8_t* class_data = dex_file_->GetClassData(class_def); - if (class_data == nullptr) { - continue; - } - for (art::ClassDataItemIterator it(*dex_file_.get(), class_data); it.HasNext(); it.Next()) { - if (!it.IsAtMethod()) { - continue; - } - const art::DexFile::CodeItem* code_item = it.GetMethodCodeItem(); - if (code_item == nullptr) { - continue; - } - art::CodeItemInstructionAccessor code(*dex_file_.get(), code_item); - if (!code.HasCodeItem()) { - continue; - } - - uint64_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin(); - size_t size = code.InsnsSizeInCodeUnits() * sizeof(uint16_t); - if (offset <= dex_offset && dex_offset < offset + size) { - *method_name = dex_file_->PrettyMethod(it.GetMemberIndex(), false); - *method_offset = dex_offset - offset; - return; - } - } - } -} - -UnwindDexFileFromFile::~UnwindDexFileFromFile() { - if (size_ != 0) { - munmap(mapped_memory_, size_); - } -} - -bool UnwindDexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) { - android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC))); - if (fd == -1) { - return false; - } - struct stat buf; - if (fstat(fd, &buf) == -1) { - return false; - } - uint64_t length; - if (buf.st_size < 0 || - __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) || - static_cast<uint64_t>(buf.st_size) < length) { - return false; - } - - mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); - if (mapped_memory_ == MAP_FAILED) { - return false; - } - size_ = buf.st_size; - - uint8_t* memory = reinterpret_cast<uint8_t*>(mapped_memory_); - - art::DexFile::Header* header = - reinterpret_cast<art::DexFile::Header*>(&memory[dex_file_offset_in_file]); - if (!art::StandardDexFile::IsMagicValid(header->magic_) && - !art::CompactDexFile::IsMagicValid(header->magic_)) { - return false; - } - - if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) || - static_cast<uint64_t>(buf.st_size) < length) { - return false; - } - - art::DexFileLoader loader; - std::string error_msg; - auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr, - false, false, &error_msg); - dex_file_.reset(dex.release()); - return dex_file_ != nullptr; -} - -bool UnwindDexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory) { - art::DexFile::Header header; - if (!memory->ReadFully(dex_file_offset_in_memory, &header, sizeof(header))) { - return false; - } - - if (!art::StandardDexFile::IsMagicValid(header.magic_) && - !art::CompactDexFile::IsMagicValid(header.magic_)) { - return false; - } - - memory_.resize(header.file_size_); - if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), header.file_size_)) { - return false; - } - - art::DexFileLoader loader; - std::string error_msg; - auto dex = - loader.Open(memory_.data(), header.file_size_, "", 0, nullptr, false, false, &error_msg); - dex_file_.reset(dex.release()); - return dex_file_ != nullptr; -} diff --git a/libbacktrace/UnwindDexFile.h b/libbacktrace/UnwindDexFile.h deleted file mode 100644 index dd70abafd..000000000 --- a/libbacktrace/UnwindDexFile.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef _LIBBACKTRACE_UNWIND_DEX_FILE_H -#define _LIBBACKTRACE_UNWIND_DEX_FILE_H - -#include <stdint.h> - -#include <memory> -#include <string> -#include <vector> - -#include <dex/dex_file-inl.h> - -namespace unwindstack { -class Memory; -struct MapInfo; -} // namespace unwindstack - -class UnwindDexFile { - public: - UnwindDexFile() = default; - virtual ~UnwindDexFile() = default; - - void GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); - - static UnwindDexFile* Create(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory, - unwindstack::MapInfo* info); - - protected: - std::unique_ptr<const art::DexFile> dex_file_; -}; - -class UnwindDexFileFromFile : public UnwindDexFile { - public: - UnwindDexFileFromFile() = default; - virtual ~UnwindDexFileFromFile(); - - bool Open(uint64_t dex_file_offset_in_file, const std::string& name); - - private: - void* mapped_memory_ = nullptr; - size_t size_ = 0; -}; - -class UnwindDexFileFromMemory : public UnwindDexFile { - public: - UnwindDexFileFromMemory() = default; - virtual ~UnwindDexFileFromMemory() = default; - - bool Open(uint64_t dex_file_offset_in_memory, unwindstack::Memory* memory); - - private: - std::vector<uint8_t> memory_; -}; - -#endif // _LIBBACKTRACE_UNWIND_DEX_FILE_H diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 158467ec2..7e2e6d05e 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -36,70 +36,15 @@ #include <unwindstack/Regs.h> #include <unwindstack/RegsGetLocal.h> +#if !defined(NO_LIBDEXFILE_SUPPORT) +#include <unwindstack/DexFiles.h> +#endif #include <unwindstack/Unwinder.h> #include "BacktraceLog.h" -#ifndef NO_LIBDEXFILE -#include "UnwindDexFile.h" -#endif #include "UnwindStack.h" #include "UnwindStackMap.h" -static void FillInDexFrame(UnwindStackMap* stack_map, uint64_t dex_pc, - backtrace_frame_data_t* frame) { - // The DEX PC points into the .dex section within an ELF file. - // However, this is a BBS section manually mmaped to a .vdex file, - // so we need to get the following map to find the ELF data. - unwindstack::Maps* maps = stack_map->stack_maps(); - auto it = maps->begin(); - uint64_t rel_dex_pc; - unwindstack::MapInfo* info; - for (; it != maps->end(); ++it) { - auto entry = *it; - if (dex_pc >= entry->start && dex_pc < entry->end) { - info = entry; - rel_dex_pc = dex_pc - entry->start; - frame->map.start = entry->start; - frame->map.end = entry->end; - frame->map.offset = entry->offset; - frame->map.load_bias = entry->load_bias; - frame->map.flags = entry->flags; - frame->map.name = entry->name; - frame->rel_pc = rel_dex_pc; - break; - } - } - if (it == maps->end() || ++it == maps->end()) { - return; - } - - auto entry = *it; - auto process_memory = stack_map->process_memory(); - unwindstack::Elf* elf = entry->GetElf(process_memory, true); - if (!elf->valid()) { - return; - } - - // Adjust the relative dex by the offset. - rel_dex_pc += entry->elf_offset; - - uint64_t dex_offset; - if (!elf->GetFunctionName(rel_dex_pc, &frame->func_name, &dex_offset)) { - return; - } - frame->func_offset = dex_offset; - if (frame->func_name != "$dexfile") { - return; - } - -#ifndef NO_LIBDEXFILE - UnwindDexFile* dex_file = stack_map->GetDexFile(dex_pc - dex_offset, info); - if (dex_file != nullptr) { - dex_file->GetMethodInformation(dex_offset, &frame->func_name, &frame->func_offset); - } -#endif -} - bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames, std::vector<std::string>* skip_names, BacktraceUnwindError* error) { @@ -110,6 +55,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, if (stack_map->GetJitDebug() != nullptr) { unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch()); } +#if !defined(NO_LIBDEXFILE_SUPPORT) + if (stack_map->GetDexFiles() != nullptr) { + unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch()); + } +#endif unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore()); if (error != nullptr) { switch (unwinder.LastErrorCode()) { @@ -150,36 +100,11 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, } auto unwinder_frames = unwinder.frames(); - // Get the real number of frames we'll need. - size_t total_frames = 0; - for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++, total_frames++) { - if (unwinder_frames[i].dex_pc != 0) { - total_frames++; - } - } - frames->resize(total_frames); + frames->resize(unwinder.NumFrames() - num_ignore_frames); size_t cur_frame = 0; for (size_t i = num_ignore_frames; i < unwinder.NumFrames(); i++) { auto frame = &unwinder_frames[i]; - // Inject extra 'virtual' frame that represents the dex pc data. - // The dex pc is magic register defined in the Mterp interpreter, - // and thus it will be restored/observed in the frame after it. - // Adding the dex frame first here will create something like: - // #7 pc 006b1ba1 libartd.so ExecuteMterpImpl+14625 - // #8 pc 0015fa20 core.vdex java.util.Arrays.binarySearch+8 - // #9 pc 0039a1ef libartd.so art::interpreter::Execute+719 - if (frame->dex_pc != 0) { - backtrace_frame_data_t* dex_frame = &frames->at(cur_frame); - dex_frame->num = cur_frame++; - dex_frame->pc = frame->dex_pc; - dex_frame->rel_pc = frame->dex_pc; - dex_frame->sp = frame->sp; - dex_frame->stack_size = 0; - dex_frame->func_offset = 0; - FillInDexFrame(stack_map, frame->dex_pc, dex_frame); - } - backtrace_frame_data_t* back_frame = &frames->at(cur_frame); back_frame->num = cur_frame++; diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp index 97f8d782d..1622e30d4 100644 --- a/libbacktrace/UnwindStackMap.cpp +++ b/libbacktrace/UnwindStackMap.cpp @@ -26,20 +26,11 @@ #include <unwindstack/MapInfo.h> #include <unwindstack/Maps.h> -#include "UnwindDexFile.h" #include "UnwindStackMap.h" //------------------------------------------------------------------------- UnwindStackMap::UnwindStackMap(pid_t pid) : BacktraceMap(pid) {} -UnwindStackMap::~UnwindStackMap() { -#ifndef NO_LIBDEXFILE - for (auto& entry : dex_files_) { - delete entry.second; - } -#endif -} - bool UnwindStackMap::Build() { if (pid_ == 0) { pid_ = getpid(); @@ -54,6 +45,9 @@ bool UnwindStackMap::Build() { // Create a JitDebug object for getting jit unwind information. 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_)); +#endif if (!stack_maps_->Parse()) { return false; @@ -127,26 +121,6 @@ std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() { return process_memory_; } -#ifdef NO_LIBDEXFILE -UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t, unwindstack::MapInfo*) { - return nullptr; -} -#else -UnwindDexFile* UnwindStackMap::GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info) { - // Lock while we get the data. - std::lock_guard<std::mutex> guard(dex_lock_); - UnwindDexFile* dex_file; - auto entry = dex_files_.find(dex_file_offset); - if (entry == dex_files_.end()) { - dex_file = UnwindDexFile::Create(dex_file_offset, process_memory_.get(), info); - dex_files_[dex_file_offset] = dex_file; - } else { - dex_file = entry->second; - } - return dex_file; -} -#endif - UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {} bool UnwindStackOfflineMap::Build() { diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h index be5c59e74..94cbfb2a0 100644 --- a/libbacktrace/UnwindStackMap.h +++ b/libbacktrace/UnwindStackMap.h @@ -27,6 +27,9 @@ #include <backtrace/Backtrace.h> #include <backtrace/BacktraceMap.h> +#if !defined(NO_LIBDEXFILE_SUPPORT) +#include <unwindstack/DexFiles.h> +#endif #include <unwindstack/JitDebug.h> #include <unwindstack/Maps.h> @@ -36,7 +39,7 @@ class UnwindDexFile; class UnwindStackMap : public BacktraceMap { public: explicit UnwindStackMap(pid_t pid); - ~UnwindStackMap(); + ~UnwindStackMap() = default; bool Build() override; @@ -51,7 +54,9 @@ class UnwindStackMap : public BacktraceMap { unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); } - UnwindDexFile* GetDexFile(uint64_t dex_file_offset, unwindstack::MapInfo* info); +#if !defined(NO_LIBDEXFILE_SUPPORT) + unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); } +#endif protected: uint64_t GetLoadBias(size_t index) override; @@ -59,9 +64,8 @@ class UnwindStackMap : public BacktraceMap { std::unique_ptr<unwindstack::Maps> stack_maps_; std::shared_ptr<unwindstack::Memory> process_memory_; std::unique_ptr<unwindstack::JitDebug> jit_debug_; -#ifndef NO_LIBDEXFILE - std::mutex dex_lock_; - std::unordered_map<uint64_t, UnwindDexFile*> dex_files_; +#if !defined(NO_LIBDEXFILE_SUPPORT) + std::unique_ptr<unwindstack::DexFiles> dex_files_; #endif }; diff --git a/libbacktrace/unwind_dex_test.cpp b/libbacktrace/unwind_dex_test.cpp deleted file mode 100644 index 449e66296..000000000 --- a/libbacktrace/unwind_dex_test.cpp +++ /dev/null @@ -1,273 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <stdint.h> -#include <sys/types.h> -#include <unistd.h> - -#include <unordered_map> - -#include <android-base/test_utils.h> - -#include <unwindstack/MapInfo.h> -#include <unwindstack/Memory.h> - -#include <dex/code_item_accessors-no_art-inl.h> -#include <dex/standard_dex_file.h> - -#include <gtest/gtest.h> - -#include "UnwindDexFile.h" - -class MemoryFake : public unwindstack::Memory { - public: - MemoryFake() = default; - virtual ~MemoryFake() = default; - - size_t Read(uint64_t addr, void* buffer, size_t size) override; - - void SetMemory(uint64_t addr, const void* memory, size_t length); - - void Clear() { data_.clear(); } - - private: - std::unordered_map<uint64_t, uint8_t> data_; -}; - -void MemoryFake::SetMemory(uint64_t addr, const void* memory, size_t length) { - const uint8_t* src = reinterpret_cast<const uint8_t*>(memory); - for (size_t i = 0; i < length; i++, addr++) { - auto value = data_.find(addr); - if (value != data_.end()) { - value->second = src[i]; - } else { - data_.insert({addr, src[i]}); - } - } -} - -size_t MemoryFake::Read(uint64_t addr, void* memory, size_t size) { - uint8_t* dst = reinterpret_cast<uint8_t*>(memory); - for (size_t i = 0; i < size; i++, addr++) { - auto value = data_.find(addr); - if (value == data_.end()) { - return i; - } - dst[i] = value->second; - } - return size; -} - -// Borrowed from art/dex/dex_file_test.cc. -static constexpr uint32_t kDexData[] = { - 0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab, - 0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070, - 0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8, - 0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146, - 0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006, - 0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000, - 0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000, - 0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004, - 0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001, - 0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67, - 0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661, - 0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e, - 0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001, - 0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0, - 0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002, - 0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003, - 0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c, -}; - -TEST(UnwindDexTest, from_file_open_non_exist) { - UnwindDexFileFromFile dex_file; - ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist")); -} - -TEST(UnwindDexTest, from_file_open_too_small) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(sizeof(art::DexFile::Header) - 2, - static_cast<size_t>( - TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2))); - - // Header too small. - UnwindDexFileFromFile dex_file; - ASSERT_FALSE(dex_file.Open(0, tf.path)); - - // Header correct, file too small. - ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); - ASSERT_EQ(sizeof(art::DexFile::Header), static_cast<size_t>(TEMP_FAILURE_RETRY(write( - tf.fd, kDexData, sizeof(art::DexFile::Header))))); - ASSERT_FALSE(dex_file.Open(0, tf.path)); -} - -TEST(UnwindDexTest, from_file_open) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(sizeof(kDexData), - static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - - UnwindDexFileFromFile dex_file; - ASSERT_TRUE(dex_file.Open(0, tf.path)); -} - -TEST(UnwindDexTest, from_file_open_non_zero_offset) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET)); - ASSERT_EQ(sizeof(kDexData), - static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - - UnwindDexFileFromFile dex_file; - ASSERT_TRUE(dex_file.Open(0x100, tf.path)); -} - -TEST(UnwindDexTest, from_memory_fail_too_small_for_header) { - MemoryFake memory; - - memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1); - UnwindDexFileFromMemory dex_file; - - ASSERT_FALSE(dex_file.Open(0x1000, &memory)); -} - -TEST(UnwindDexTest, from_memory_fail_too_small_for_data) { - MemoryFake memory; - - memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2); - UnwindDexFileFromMemory dex_file; - - ASSERT_FALSE(dex_file.Open(0x1000, &memory)); -} - -TEST(UnwindDexTest, from_memory_open) { - MemoryFake memory; - - memory.SetMemory(0x1000, kDexData, sizeof(kDexData)); - UnwindDexFileFromMemory dex_file; - - ASSERT_TRUE(dex_file.Open(0x1000, &memory)); -} - -TEST(UnwindDexTest, create_using_file) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET)); - ASSERT_EQ(sizeof(kDexData), - static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - - MemoryFake memory; - unwindstack::MapInfo info(0, 0x10000, 0, 0x5, tf.path); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x500, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); -} - -TEST(UnwindDexTest, create_using_file_non_zero_start) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET)); - ASSERT_EQ(sizeof(kDexData), - static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - - MemoryFake memory; - unwindstack::MapInfo info(0x100, 0x10000, 0, 0x5, tf.path); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x600, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); -} - -TEST(UnwindDexTest, create_using_file_non_zero_offset) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(0x500, lseek(tf.fd, 0x500, SEEK_SET)); - ASSERT_EQ(sizeof(kDexData), - static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - - MemoryFake memory; - unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, tf.path); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x400, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); -} - -TEST(UnwindDexTest, create_using_memory_empty_file) { - MemoryFake memory; - memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, ""); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); -} - -TEST(UnwindDexTest, create_using_memory_file_does_not_exist) { - MemoryFake memory; - memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); -} - -TEST(UnwindDexTest, create_using_memory_file_is_malformed) { - TemporaryFile tf; - ASSERT_TRUE(tf.fd != -1); - - ASSERT_EQ(sizeof(kDexData) - 10, - static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData) - 10)))); - - MemoryFake memory; - memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - unwindstack::MapInfo info(0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); - - // Check it came from memory by clearing memory and verifying it fails. - memory.Clear(); - dex_file.reset(UnwindDexFile::Create(0x4000, &memory, &info)); - ASSERT_TRUE(dex_file == nullptr); -} - -TEST(UnwindDexTest, get_method_not_opened) { - std::string method("something"); - uint64_t method_offset = 100; - UnwindDexFile dex_file; - dex_file.GetMethodInformation(0x100, &method, &method_offset); - EXPECT_EQ("something", method); - EXPECT_EQ(100U, method_offset); -} - -TEST(UnwindDexTest, get_method) { - MemoryFake memory; - memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); - unwindstack::MapInfo info(0x100, 0x10000, 0x200, 0x5, ""); - std::unique_ptr<UnwindDexFile> dex_file(UnwindDexFile::Create(0x4000, &memory, &info)); - ASSERT_TRUE(dex_file != nullptr); - - std::string method; - uint64_t method_offset; - dex_file->GetMethodInformation(0x102, &method, &method_offset); - EXPECT_EQ("Main.<init>", method); - EXPECT_EQ(2U, method_offset); - - method = "not_in_a_method"; - method_offset = 0x123; - dex_file->GetMethodInformation(0x100000, &method, &method_offset); - EXPECT_EQ("not_in_a_method", method); - EXPECT_EQ(0x123U, method_offset); -} |