From 6b95a0e9993ac6563476b0489c1ef982f8412f21 Mon Sep 17 00:00:00 2001 From: Casey Dahlin Date: Tue, 12 Mar 2019 17:50:52 -0700 Subject: [PATCH] Internalize subclasses of Memory There are many subclasses of the Memory class and the overwhelming majority of them don't need to be exposed externally. We move all of them to internal headers except MemoryOfflineBuffer, which moves to a separate header. This dramatically reduces the exposed API surface and makes the code more modular. Also, remove the Offline code from libbacktrace. It's not used any where. Test: Unit tests pass, clean tree still builds Change-Id: I55dacdf080daba0bfe65c1ad53a4b326bb482e83 --- libbacktrace/Android.bp | 1 - libbacktrace/UnwindStack.cpp | 88 +--- libbacktrace/UnwindStack.h | 19 +- libbacktrace/UnwindStackMap.cpp | 49 --- libbacktrace/UnwindStackMap.h | 16 +- libbacktrace/backtrace_offline_test.cpp | 397 ------------------ libbacktrace/include/backtrace/Backtrace.h | 23 - libbacktrace/include/backtrace/BacktraceMap.h | 2 - libunwindstack/ElfInterface.cpp | 2 +- libunwindstack/JitDebug.cpp | 3 +- libunwindstack/MapInfo.cpp | 4 +- libunwindstack/Memory.cpp | 23 + libunwindstack/MemoryBuffer.h | 48 +++ libunwindstack/MemoryCache.h | 50 +++ libunwindstack/MemoryFileAtOffset.h | 47 +++ libunwindstack/MemoryLocal.h | 36 ++ libunwindstack/MemoryOffline.h | 60 +++ libunwindstack/MemoryOfflineBuffer.h | 43 ++ libunwindstack/MemoryRange.h | 66 +++ libunwindstack/MemoryRemote.h | 45 ++ libunwindstack/include/unwindstack/MapInfo.h | 3 +- libunwindstack/include/unwindstack/Memory.h | 158 +------ libunwindstack/tests/MemoryBufferTest.cpp | 3 +- libunwindstack/tests/MemoryCacheTest.cpp | 3 +- libunwindstack/tests/MemoryFileTest.cpp | 2 +- libunwindstack/tests/MemoryLocalTest.cpp | 2 +- .../tests/MemoryOfflineBufferTest.cpp | 3 +- libunwindstack/tests/MemoryOfflineTest.cpp | 3 +- libunwindstack/tests/MemoryRangeTest.cpp | 3 +- libunwindstack/tests/MemoryRangesTest.cpp | 3 +- libunwindstack/tests/MemoryRemoteTest.cpp | 2 +- libunwindstack/tests/UnwindOfflineTest.cpp | 2 +- libunwindstack/tests/UnwindTest.cpp | 2 +- libunwindstack/tools/unwind_info.cpp | 10 +- libunwindstack/tools/unwind_reg_info.cpp | 14 +- libunwindstack/tools/unwind_symbols.cpp | 8 +- 36 files changed, 453 insertions(+), 790 deletions(-) delete mode 100644 libbacktrace/backtrace_offline_test.cpp create mode 100644 libunwindstack/MemoryBuffer.h create mode 100644 libunwindstack/MemoryCache.h create mode 100644 libunwindstack/MemoryFileAtOffset.h create mode 100644 libunwindstack/MemoryLocal.h create mode 100644 libunwindstack/MemoryOffline.h create mode 100644 libunwindstack/MemoryOfflineBuffer.h create mode 100644 libunwindstack/MemoryRange.h create mode 100644 libunwindstack/MemoryRemote.h diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp index e171155b9..9ece8479c 100644 --- a/libbacktrace/Android.bp +++ b/libbacktrace/Android.bp @@ -135,7 +135,6 @@ cc_test { defaults: ["libbacktrace_common"], host_supported: true, srcs: [ - "backtrace_offline_test.cpp", "backtrace_test.cpp", ], diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index 36640cdfa..a12862398 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -129,22 +129,6 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, return true; } -bool Backtrace::UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map, - const backtrace_stackinfo_t& stack, - std::vector* frames, - BacktraceUnwindError* error) { - UnwindStackOfflineMap* offline_map = reinterpret_cast(back_map); - // Create the process memory from the stack data since this will almost - // always be different each unwind. - if (!offline_map->CreateProcessMemory(stack)) { - if (error != nullptr) { - error->error_code = BACKTRACE_UNWIND_ERROR_SETUP_FAILED; - } - return false; - } - return Backtrace::Unwind(regs, back_map, frames, 0U, nullptr, error); -} - UnwindStackCurrent::UnwindStackCurrent(pid_t pid, pid_t tid, BacktraceMap* map) : BacktraceCurrent(pid, tid, map) {} @@ -171,7 +155,7 @@ bool UnwindStackCurrent::UnwindFromContext(size_t num_ignore_frames, void* ucont } UnwindStackPtrace::UnwindStackPtrace(pid_t pid, pid_t tid, BacktraceMap* map) - : BacktracePtrace(pid, tid, map), memory_(pid) {} + : BacktracePtrace(pid, tid, map), memory_(unwindstack::Memory::CreateProcessMemory(pid)) {} std::string UnwindStackPtrace::GetFunctionNameRaw(uint64_t pc, uint64_t* offset) { return GetMap()->GetFunctionName(pc, offset); @@ -189,73 +173,5 @@ bool UnwindStackPtrace::Unwind(size_t num_ignore_frames, void* context) { } size_t UnwindStackPtrace::Read(uint64_t addr, uint8_t* buffer, size_t bytes) { - return memory_.Read(addr, buffer, bytes); -} - -UnwindStackOffline::UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map, - bool map_shared) - : Backtrace(pid, tid, map), arch_(arch) { - map_shared_ = map_shared; -} - -bool UnwindStackOffline::Unwind(size_t num_ignore_frames, void* ucontext) { - if (ucontext == nullptr) { - return false; - } - - unwindstack::ArchEnum arch; - switch (arch_) { - case ARCH_ARM: - arch = unwindstack::ARCH_ARM; - break; - case ARCH_ARM64: - arch = unwindstack::ARCH_ARM64; - break; - case ARCH_X86: - arch = unwindstack::ARCH_X86; - break; - case ARCH_X86_64: - arch = unwindstack::ARCH_X86_64; - break; - default: - return false; - } - - std::unique_ptr regs(unwindstack::Regs::CreateFromUcontext(arch, ucontext)); - - return Backtrace::Unwind(regs.get(), GetMap(), &frames_, num_ignore_frames, nullptr, &error_); -} - -std::string UnwindStackOffline::GetFunctionNameRaw(uint64_t, uint64_t*) { - return ""; -} - -size_t UnwindStackOffline::Read(uint64_t, uint8_t*, size_t) { - return 0; -} - -bool UnwindStackOffline::ReadWord(uint64_t, word_t*) { - return false; -} - -Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, - const std::vector& maps, - const backtrace_stackinfo_t& stack) { - std::unique_ptr map( - reinterpret_cast(BacktraceMap::CreateOffline(pid, maps))); - if (map.get() == nullptr || !map->CreateProcessMemory(stack)) { - return nullptr; - } - return new UnwindStackOffline(arch, pid, tid, map.release(), false); -} - -Backtrace* Backtrace::CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map) { - if (map == nullptr) { - return nullptr; - } - return new UnwindStackOffline(arch, pid, tid, map, true); -} - -void Backtrace::SetGlobalElfCache(bool enable) { - unwindstack::Elf::SetCachingEnabled(enable); + return memory_->Read(addr, buffer, bytes); } diff --git a/libbacktrace/UnwindStack.h b/libbacktrace/UnwindStack.h index 4ec591d2f..47f6757d8 100644 --- a/libbacktrace/UnwindStack.h +++ b/libbacktrace/UnwindStack.h @@ -19,6 +19,7 @@ #include +#include #include #include @@ -49,23 +50,7 @@ class UnwindStackPtrace : public BacktracePtrace { size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override; private: - unwindstack::MemoryRemote memory_; -}; - -class UnwindStackOffline : public Backtrace { - public: - UnwindStackOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map, bool map_shared); - - bool Unwind(size_t num_ignore_frames, void* context) override; - - std::string GetFunctionNameRaw(uint64_t pc, uint64_t* offset) override; - - size_t Read(uint64_t addr, uint8_t* buffer, size_t bytes) override; - - bool ReadWord(uint64_t ptr, word_t* out_value) override; - - private: - ArchEnum arch_; + std::shared_ptr memory_; }; #endif // _LIBBACKTRACE_UNWIND_STACK_H diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp index 4518891c3..aa0b17c99 100644 --- a/libbacktrace/UnwindStackMap.cpp +++ b/libbacktrace/UnwindStackMap.cpp @@ -132,43 +132,6 @@ std::shared_ptr UnwindStackMap::GetProcessMemory() { return process_memory_; } -UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {} - -bool UnwindStackOfflineMap::Build() { - return false; -} - -bool UnwindStackOfflineMap::Build(const std::vector& backtrace_maps) { - for (const backtrace_map_t& map : backtrace_maps) { - maps_.push_back(map); - } - - std::sort(maps_.begin(), maps_.end(), - [](const backtrace_map_t& a, const backtrace_map_t& b) { return a.start < b.start; }); - - unwindstack::Maps* maps = new unwindstack::Maps; - stack_maps_.reset(maps); - for (const backtrace_map_t& map : maps_) { - maps->Add(map.start, map.end, map.offset, map.flags, map.name, map.load_bias); - } - return true; -} - -bool UnwindStackOfflineMap::CreateProcessMemory(const backtrace_stackinfo_t& stack) { - if (stack.start >= stack.end) { - return false; - } - - // Create the process memory from the stack data. - if (memory_ == nullptr) { - memory_ = new unwindstack::MemoryOfflineBuffer(stack.data, stack.start, stack.end); - process_memory_.reset(memory_); - } else { - memory_->Reset(stack.data, stack.start, stack.end); - } - return true; -} - //------------------------------------------------------------------------- // BacktraceMap create function. //------------------------------------------------------------------------- @@ -189,15 +152,3 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) { } return map; } - -//------------------------------------------------------------------------- -// BacktraceMap create offline function. -//------------------------------------------------------------------------- -BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector& maps) { - UnwindStackOfflineMap* map = new UnwindStackOfflineMap(pid); - if (!map->Build(maps)) { - delete map; - return nullptr; - } - return map; -} diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h index e19b60565..f0e7d8b78 100644 --- a/libbacktrace/UnwindStackMap.h +++ b/libbacktrace/UnwindStackMap.h @@ -33,6 +33,7 @@ #include #include #include +#include // Forward declarations. class UnwindDexFile; @@ -74,19 +75,4 @@ class UnwindStackMap : public BacktraceMap { unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN; }; -class UnwindStackOfflineMap : public UnwindStackMap { - public: - UnwindStackOfflineMap(pid_t pid); - ~UnwindStackOfflineMap() = default; - - bool Build() override; - - bool Build(const std::vector& maps); - - bool CreateProcessMemory(const backtrace_stackinfo_t& stack); - - private: - unwindstack::MemoryOfflineBuffer* memory_ = nullptr; -}; - #endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H diff --git a/libbacktrace/backtrace_offline_test.cpp b/libbacktrace/backtrace_offline_test.cpp deleted file mode 100644 index 662fb9977..000000000 --- a/libbacktrace/backtrace_offline_test.cpp +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (C) 2015 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 -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "BacktraceTest.h" - -struct FunctionSymbol { - std::string name; - uint64_t start; - uint64_t end; -}; - -static std::vector GetFunctionSymbols() { - std::vector symbols = { - {"unknown_start", 0, 0}, - {"test_level_one", reinterpret_cast(&BacktraceTest::test_level_one_), 0}, - {"test_level_two", reinterpret_cast(&BacktraceTest::test_level_two_), 0}, - {"test_level_three", reinterpret_cast(&BacktraceTest::test_level_three_), 0}, - {"test_level_four", reinterpret_cast(&BacktraceTest::test_level_four_), 0}, - {"test_recursive_call", reinterpret_cast(&BacktraceTest::test_recursive_call_), 0}, - {"test_get_context_and_wait", - reinterpret_cast(&BacktraceTest::test_get_context_and_wait_), 0}, - {"unknown_end", static_cast(-1), static_cast(-1)}, - }; - std::sort( - symbols.begin(), symbols.end(), - [](const FunctionSymbol& s1, const FunctionSymbol& s2) { return s1.start < s2.start; }); - for (size_t i = 0; i + 1 < symbols.size(); ++i) { - symbols[i].end = symbols[i + 1].start; - } - return symbols; -} - -static std::string RawDataToHexString(const void* data, size_t size) { - const uint8_t* p = static_cast(data); - std::string s; - for (size_t i = 0; i < size; ++i) { - s += android::base::StringPrintf("%02x", p[i]); - } - return s; -} - -static void HexStringToRawData(const char* s, std::vector* data, size_t size) { - for (size_t i = 0; i < size; ++i) { - int value; - sscanf(s, "%02x", &value); - data->push_back(value); - s += 2; - } -} - -struct OfflineThreadArg { - std::vector ucontext; - pid_t tid; - volatile int exit_flag; -}; - -static void* OfflineThreadFunc(void* arg) { - OfflineThreadArg* fn_arg = reinterpret_cast(arg); - fn_arg->tid = android::base::GetThreadId(); - BacktraceTest::test_get_context_and_wait_(&fn_arg->ucontext, &fn_arg->exit_flag); - return nullptr; -} - -std::string GetTestPath(const std::string& arch, const std::string& path) { - return android::base::GetExecutableDirectory() + "/testdata/" + arch + '/' + path; -} - -// This test is disable because it is for generating test data. -TEST_F(BacktraceTest, DISABLED_generate_offline_testdata) { - // Create a thread to generate the needed stack and registers information. - const size_t stack_size = 16 * 1024; - void* stack = mmap(NULL, stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); - ASSERT_NE(MAP_FAILED, stack); - uint64_t stack_addr = reinterpret_cast(stack); - pthread_attr_t attr; - ASSERT_EQ(0, pthread_attr_init(&attr)); - ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast(stack), stack_size)); - pthread_t thread; - OfflineThreadArg arg; - arg.exit_flag = 0; - ASSERT_EQ(0, pthread_create(&thread, &attr, OfflineThreadFunc, &arg)); - // Wait for the offline thread to generate the stack and context information. - sleep(1); - // Copy the stack information. - std::vector stack_data(reinterpret_cast(stack), - reinterpret_cast(stack) + stack_size); - arg.exit_flag = 1; - ASSERT_EQ(0, pthread_join(thread, nullptr)); - ASSERT_EQ(0, munmap(stack, stack_size)); - - std::unique_ptr map(BacktraceMap::Create(getpid())); - ASSERT_TRUE(map != nullptr); - - backtrace_stackinfo_t stack_info; - stack_info.start = stack_addr; - stack_info.end = stack_addr + stack_size; - stack_info.data = stack_data.data(); - - // Generate offline testdata. - std::string testdata; - // 1. Dump pid, tid - testdata += android::base::StringPrintf("pid: %d tid: %d\n", getpid(), arg.tid); - // 2. Dump maps - for (auto it = map->begin(); it != map->end(); ++it) { - const backtrace_map_t* entry = *it; - testdata += - android::base::StringPrintf("map: start: %" PRIx64 " end: %" PRIx64 " offset: %" PRIx64 - " load_bias: %" PRIx64 " flags: %d name: %s\n", - entry->start, entry->end, entry->offset, entry->load_bias, - entry->flags, entry->name.c_str()); - } - // 3. Dump ucontext - testdata += android::base::StringPrintf("ucontext: %zu ", arg.ucontext.size()); - testdata += RawDataToHexString(arg.ucontext.data(), arg.ucontext.size()); - testdata.push_back('\n'); - - // 4. Dump stack - testdata += android::base::StringPrintf( - "stack: start: %" PRIx64 " end: %" PRIx64 " size: %zu ", - stack_info.start, stack_info.end, stack_data.size()); - testdata += RawDataToHexString(stack_data.data(), stack_data.size()); - testdata.push_back('\n'); - - // 5. Dump function symbols - std::vector function_symbols = GetFunctionSymbols(); - for (const auto& symbol : function_symbols) { - testdata += - android::base::StringPrintf("function: start: %" PRIx64 " end: %" PRIx64 " name: %s\n", - symbol.start, symbol.end, symbol.name.c_str()); - } - - ASSERT_TRUE(android::base::WriteStringToFile(testdata, "offline_testdata")); -} - -// Return the name of the function which matches the address. Although we don't know the -// exact end of each function, it is accurate enough for the tests. -static std::string FunctionNameForAddress(uint64_t addr, - const std::vector& symbols) { - for (auto& symbol : symbols) { - if (addr >= symbol.start && addr < symbol.end) { - return symbol.name; - } - } - return ""; -} - -struct OfflineTestData { - int pid; - int tid; - std::vector maps; - std::vector ucontext; - backtrace_stackinfo_t stack_info; - std::vector stack; - std::vector symbols; -}; - -bool ReadOfflineTestData(const std::string offline_testdata_path, OfflineTestData* testdata) { - std::string s; - if (!android::base::ReadFileToString(offline_testdata_path, &s)) { - return false; - } - // Parse offline_testdata. - std::vector lines = android::base::Split(s, "\n"); - for (const auto& line : lines) { - if (android::base::StartsWith(line, "pid:")) { - sscanf(line.c_str(), "pid: %d tid: %d", &testdata->pid, &testdata->tid); - } else if (android::base::StartsWith(line, "map:")) { - testdata->maps.resize(testdata->maps.size() + 1); - backtrace_map_t& map = testdata->maps.back(); - int pos; - sscanf(line.c_str(), - "map: start: %" SCNx64 " end: %" SCNx64 " offset: %" SCNx64 " load_bias: %" SCNx64 - " flags: %d name: %n", - &map.start, &map.end, &map.offset, &map.load_bias, &map.flags, &pos); - map.name = android::base::Trim(line.substr(pos)); - } else if (android::base::StartsWith(line, "ucontext:")) { - size_t size; - int pos; - testdata->ucontext.clear(); - sscanf(line.c_str(), "ucontext: %zu %n", &size, &pos); - HexStringToRawData(&line[pos], &testdata->ucontext, size); - } else if (android::base::StartsWith(line, "stack:")) { - size_t size; - int pos; - sscanf(line.c_str(), - "stack: start: %" SCNx64 " end: %" SCNx64 " size: %zu %n", - &testdata->stack_info.start, &testdata->stack_info.end, &size, &pos); - CHECK_EQ(testdata->stack_info.end - testdata->stack_info.start, size); - testdata->stack.clear(); - HexStringToRawData(&line[pos], &testdata->stack, size); - testdata->stack_info.data = testdata->stack.data(); - } else if (android::base::StartsWith(line, "function:")) { - testdata->symbols.resize(testdata->symbols.size() + 1); - FunctionSymbol& symbol = testdata->symbols.back(); - int pos; - sscanf(line.c_str(), "function: start: %" SCNx64 " end: %" SCNx64 " name: %n", &symbol.start, - &symbol.end, &pos); - symbol.name = line.substr(pos); - } - } - return true; -} - -static void BacktraceOfflineTest(std::string arch_str, const std::string& testlib_name) { - const std::string testlib_path(GetTestPath(arch_str, testlib_name)); - const std::string offline_testdata_path(GetTestPath(arch_str, "offline_testdata")); - OfflineTestData testdata; - ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata)) << "Failed " << arch_str; - - // Fix path of libbacktrace_testlib.so. - for (auto& map : testdata.maps) { - if (map.name.find("libbacktrace_test.so") != std::string::npos) { - map.name = testlib_path; - } - } - - Backtrace::ArchEnum arch; - if (arch_str == "arm") { - arch = Backtrace::ARCH_ARM; - } else if (arch_str == "arm64") { - arch = Backtrace::ARCH_ARM64; - } else if (arch_str == "x86") { - arch = Backtrace::ARCH_X86; - } else if (arch_str == "x86_64") { - arch = Backtrace::ARCH_X86_64; - } else { - abort(); - } - - std::unique_ptr backtrace(Backtrace::CreateOffline( - arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info)); - ASSERT_TRUE(backtrace != nullptr) << "Failed " << arch_str; - - ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data())) << "Failed " << arch_str; - - // Collect pc values of the call stack frames. - std::vector pc_values; - for (size_t i = 0; i < backtrace->NumFrames(); ++i) { - pc_values.push_back(backtrace->GetFrame(i)->pc); - } - - size_t test_one_index = 0; - for (size_t i = 0; i < pc_values.size(); ++i) { - if (FunctionNameForAddress(pc_values[i], testdata.symbols) == "test_level_one") { - test_one_index = i; - break; - } - } - - ASSERT_GE(test_one_index, 3u) << "Failed " << arch_str; - ASSERT_EQ("test_level_one", FunctionNameForAddress(pc_values[test_one_index], testdata.symbols)) - << "Failed " << arch_str; - ASSERT_EQ("test_level_two", FunctionNameForAddress(pc_values[test_one_index - 1], testdata.symbols)) - << "Failed " << arch_str; - ASSERT_EQ("test_level_three", - FunctionNameForAddress(pc_values[test_one_index - 2], testdata.symbols)) - << "Failed " << arch_str; - ASSERT_EQ("test_level_four", - FunctionNameForAddress(pc_values[test_one_index - 3], testdata.symbols)) - << "Failed " << arch_str; -} - -// For now, these tests can only run on the given architectures. -TEST_F(BacktraceTest, offline_eh_frame) { - BacktraceOfflineTest("arm64", "libbacktrace_test_eh_frame.so"); - BacktraceOfflineTest("x86_64", "libbacktrace_test_eh_frame.so"); -} - -TEST_F(BacktraceTest, offline_debug_frame) { - BacktraceOfflineTest("arm", "libbacktrace_test_debug_frame.so"); - BacktraceOfflineTest("x86", "libbacktrace_test_debug_frame.so"); -} - -TEST_F(BacktraceTest, offline_gnu_debugdata) { - BacktraceOfflineTest("arm", "libbacktrace_test_gnu_debugdata.so"); - BacktraceOfflineTest("x86", "libbacktrace_test_gnu_debugdata.so"); -} - -TEST_F(BacktraceTest, offline_arm_exidx) { - BacktraceOfflineTest("arm", "libbacktrace_test_arm_exidx.so"); -} - -static void LibUnwindingTest(const std::string& arch_str, const std::string& testdata_name, - const std::string& testlib_name) { - const std::string testlib_path(GetTestPath(arch_str, testlib_name)); - struct stat st; - ASSERT_EQ(0, stat(testlib_path.c_str(), &st)) << "can't find testlib " << testlib_path; - - const std::string offline_testdata_path(GetTestPath(arch_str, testdata_name)); - OfflineTestData testdata; - ASSERT_TRUE(ReadOfflineTestData(offline_testdata_path, &testdata)); - - // Fix path of the testlib. - for (auto& map : testdata.maps) { - if (map.name.find(testlib_name) != std::string::npos) { - map.name = testlib_path; - } - } - - Backtrace::ArchEnum arch; - if (arch_str == "arm") { - arch = Backtrace::ARCH_ARM; - } else if (arch_str == "arm64") { - arch = Backtrace::ARCH_ARM64; - } else if (arch_str == "x86") { - arch = Backtrace::ARCH_X86; - } else if (arch_str == "x86_64") { - arch = Backtrace::ARCH_X86_64; - } else { - ASSERT_TRUE(false) << "Unsupported arch " << arch_str; - abort(); - } - - // Do offline backtrace. - std::unique_ptr backtrace(Backtrace::CreateOffline( - arch, testdata.pid, testdata.tid, testdata.maps, testdata.stack_info)); - ASSERT_TRUE(backtrace != nullptr); - - ASSERT_TRUE(backtrace->Unwind(0, testdata.ucontext.data())); - - ASSERT_EQ(testdata.symbols.size(), backtrace->NumFrames()); - for (size_t i = 0; i < backtrace->NumFrames(); ++i) { - std::string name = FunctionNameForAddress(backtrace->GetFrame(i)->rel_pc, testdata.symbols); - ASSERT_EQ(name, testdata.symbols[i].name); - } - ASSERT_TRUE(backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_ACCESS_MEM_FAILED || - backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_MAP_MISSING || - backtrace->GetError().error_code == BACKTRACE_UNWIND_ERROR_REPEATED_FRAME); -} - -// This test tests the situation that ranges of functions covered by .eh_frame and .ARM.exidx -// overlap with each other, which appears in /system/lib/libart.so. -TEST_F(BacktraceTest, offline_unwind_mix_eh_frame_and_arm_exidx) { - LibUnwindingTest("arm", "offline_testdata_for_libart", "libart.so"); -} - -TEST_F(BacktraceTest, offline_debug_frame_with_load_bias) { - LibUnwindingTest("arm", "offline_testdata_for_libandroid_runtime", "libandroid_runtime.so"); -} - -TEST_F(BacktraceTest, offline_try_armexidx_after_debug_frame) { - LibUnwindingTest("arm", "offline_testdata_for_libGLESv2_adreno", "libGLESv2_adreno.so"); -} - -TEST_F(BacktraceTest, offline_cie_with_P_augmentation) { - // Make sure we can unwind through functions with CIE entry containing P augmentation, which - // makes unwinding library reading personality handler from memory. One example is - // /system/lib64/libskia.so. - LibUnwindingTest("arm64", "offline_testdata_for_libskia", "libskia.so"); -} - -TEST_F(BacktraceTest, offline_empty_eh_frame_hdr) { - // Make sure we can unwind through libraries with empty .eh_frame_hdr section. One example is - // /vendor/lib64/egl/eglSubDriverAndroid.so. - LibUnwindingTest("arm64", "offline_testdata_for_eglSubDriverAndroid", "eglSubDriverAndroid.so"); -} - -TEST_F(BacktraceTest, offline_max_frames_limit) { - // The length of callchain can reach 256 when recording an application. - ASSERT_GE(MAX_BACKTRACE_FRAMES, 256); -} diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h index 404e7e8ab..664b531fb 100644 --- a/libbacktrace/include/backtrace/Backtrace.h +++ b/libbacktrace/include/backtrace/Backtrace.h @@ -126,24 +126,6 @@ class Backtrace { // If map is not NULL, the map is still owned by the caller. static Backtrace* Create(pid_t pid, pid_t tid, BacktraceMap* map = nullptr); - // Create an offline Backtrace object that can be used to do an unwind without a process - // that is still running. By default, information is only cached in the map - // file. If the calling code creates the map, data can be cached between - // unwinds. If not, all cached data will be destroyed when the Backtrace - // object is destroyed. - static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, - const std::vector& maps, - const backtrace_stackinfo_t& stack); - static Backtrace* CreateOffline(ArchEnum arch, pid_t pid, pid_t tid, BacktraceMap* map); - - // Create an offline Backtrace object that can be used to do an unwind without a process - // that is still running. If cache_file is set to true, then elf information will be cached - // for this call. The cached information survives until the calling process ends. This means - // that subsequent calls to create offline Backtrace objects will continue to use the same - // cache. It also assumes that the elf files used for each offline unwind are the same. - static Backtrace* CreateOffline(pid_t pid, pid_t tid, BacktraceMap* map, - const backtrace_stackinfo_t& stack, bool cache_file = false); - virtual ~Backtrace(); // Get the current stack trace and store in the backtrace_ structure. @@ -153,11 +135,6 @@ class Backtrace { std::vector* frames, size_t num_ignore_frames, std::vector* skip_names, BacktraceUnwindError* error = nullptr); - static bool UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map, - const backtrace_stackinfo_t& stack_info, - std::vector* frames, - BacktraceUnwindError* error = nullptr); - // Get the function name and offset into the function given the pc. // If the string is empty, then no valid function name was found, // or the pc is not in any valid map. diff --git a/libbacktrace/include/backtrace/BacktraceMap.h b/libbacktrace/include/backtrace/BacktraceMap.h index c564271b6..f8d5058c7 100644 --- a/libbacktrace/include/backtrace/BacktraceMap.h +++ b/libbacktrace/include/backtrace/BacktraceMap.h @@ -69,8 +69,6 @@ public: // is unsupported. static BacktraceMap* Create(pid_t pid, bool uncached = false); - static BacktraceMap* CreateOffline(pid_t pid, const std::vector& maps); - virtual ~BacktraceMap(); class iterator : public std::iterator { diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index dee8eb36a..f0e413805 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -29,12 +29,12 @@ #include #include #include -#include #include #include "DwarfDebugFrame.h" #include "DwarfEhFrame.h" #include "DwarfEhFrameWithHdr.h" +#include "MemoryBuffer.h" #include "Symbols.h" namespace unwindstack { diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp index 20bc4b902..8a85607cb 100644 --- a/libunwindstack/JitDebug.cpp +++ b/libunwindstack/JitDebug.cpp @@ -23,7 +23,8 @@ #include #include #include -#include + +#include "MemoryRange.h" // This implements the JIT Compilation Interface. // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index d3cec069a..1c0f1e611 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -27,7 +27,9 @@ #include #include #include -#include + +#include "MemoryFileAtOffset.h" +#include "MemoryRange.h" namespace unwindstack { diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp index 9904feff1..a66cd5b54 100644 --- a/libunwindstack/Memory.cpp +++ b/libunwindstack/Memory.cpp @@ -32,6 +32,14 @@ #include #include "Check.h" +#include "MemoryBuffer.h" +#include "MemoryCache.h" +#include "MemoryFileAtOffset.h" +#include "MemoryLocal.h" +#include "MemoryOffline.h" +#include "MemoryOfflineBuffer.h" +#include "MemoryRange.h" +#include "MemoryRemote.h" namespace unwindstack { @@ -168,6 +176,16 @@ bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) { return false; } +std::unique_ptr Memory::CreateFileMemory(const std::string& path, uint64_t offset) { + auto memory = std::make_unique(); + + if (memory->Init(path, offset)) { + return memory; + } + + return nullptr; +} + std::shared_ptr Memory::CreateProcessMemory(pid_t pid) { if (pid == getpid()) { return std::shared_ptr(new MemoryLocal()); @@ -182,6 +200,11 @@ std::shared_ptr Memory::CreateProcessMemoryCached(pid_t pid) { return std::shared_ptr(new MemoryCache(new MemoryRemote(pid))); } +std::shared_ptr Memory::CreateOfflineMemory(const uint8_t* data, uint64_t start, + uint64_t end) { + return std::shared_ptr(new MemoryOfflineBuffer(data, start, end)); +} + size_t MemoryBuffer::Read(uint64_t addr, void* dst, size_t size) { if (addr >= raw_.size()) { return 0; diff --git a/libunwindstack/MemoryBuffer.h b/libunwindstack/MemoryBuffer.h new file mode 100644 index 000000000..3fe4bbbda --- /dev/null +++ b/libunwindstack/MemoryBuffer.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_BUFFER_H +#define _LIBUNWINDSTACK_MEMORY_BUFFER_H + +#include + +#include +#include + +#include + +namespace unwindstack { + +class MemoryBuffer : public Memory { + public: + MemoryBuffer() = default; + virtual ~MemoryBuffer() = default; + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + uint8_t* GetPtr(size_t offset); + + void Resize(size_t size) { raw_.resize(size); } + + uint64_t Size() { return raw_.size(); } + + private: + std::vector raw_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_BUFFER_H diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h new file mode 100644 index 000000000..769d90746 --- /dev/null +++ b/libunwindstack/MemoryCache.h @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_CACHE_H +#define _LIBUNWINDSTACK_MEMORY_CACHE_H + +#include + +#include +#include +#include + +#include + +namespace unwindstack { + +class MemoryCache : public Memory { + public: + MemoryCache(Memory* memory) : impl_(memory) {} + virtual ~MemoryCache() = default; + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + void Clear() override { cache_.clear(); } + + private: + constexpr static size_t kCacheBits = 12; + constexpr static size_t kCacheMask = (1 << kCacheBits) - 1; + constexpr static size_t kCacheSize = 1 << kCacheBits; + std::unordered_map cache_; + + std::unique_ptr impl_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_CACHE_H diff --git a/libunwindstack/MemoryFileAtOffset.h b/libunwindstack/MemoryFileAtOffset.h new file mode 100644 index 000000000..d136eb44a --- /dev/null +++ b/libunwindstack/MemoryFileAtOffset.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H +#define _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H + +#include + +#include + +namespace unwindstack { + +class MemoryFileAtOffset : public Memory { + public: + MemoryFileAtOffset() = default; + virtual ~MemoryFileAtOffset(); + + bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX); + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + size_t Size() { return size_; } + + void Clear() override; + + protected: + size_t size_ = 0; + size_t offset_ = 0; + uint8_t* data_ = nullptr; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_FILE_AT_OFFSET_H diff --git a/libunwindstack/MemoryLocal.h b/libunwindstack/MemoryLocal.h new file mode 100644 index 000000000..29aaf128b --- /dev/null +++ b/libunwindstack/MemoryLocal.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_LOCAL_H +#define _LIBUNWINDSTACK_MEMORY_LOCAL_H + +#include + +#include + +namespace unwindstack { + +class MemoryLocal : public Memory { + public: + MemoryLocal() = default; + virtual ~MemoryLocal() = default; + + size_t Read(uint64_t addr, void* dst, size_t size) override; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_LOCAL_H diff --git a/libunwindstack/MemoryOffline.h b/libunwindstack/MemoryOffline.h new file mode 100644 index 000000000..789f1a268 --- /dev/null +++ b/libunwindstack/MemoryOffline.h @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_OFFLINE_H +#define _LIBUNWINDSTACK_MEMORY_OFFLINE_H + +#include + +#include +#include +#include + +#include + +#include "MemoryRange.h" + +namespace unwindstack { + +class MemoryOffline : public Memory { + public: + MemoryOffline() = default; + virtual ~MemoryOffline() = default; + + bool Init(const std::string& file, uint64_t offset); + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + private: + std::unique_ptr memory_; +}; + +class MemoryOfflineParts : public Memory { + public: + MemoryOfflineParts() = default; + virtual ~MemoryOfflineParts(); + + void Add(MemoryOffline* memory) { memories_.push_back(memory); } + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + private: + std::vector memories_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_H diff --git a/libunwindstack/MemoryOfflineBuffer.h b/libunwindstack/MemoryOfflineBuffer.h new file mode 100644 index 000000000..64c49a1ca --- /dev/null +++ b/libunwindstack/MemoryOfflineBuffer.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H +#define _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H + +#include + +#include + +namespace unwindstack { + +class MemoryOfflineBuffer : public Memory { + public: + MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end); + virtual ~MemoryOfflineBuffer() = default; + + void Reset(const uint8_t* data, uint64_t start, uint64_t end); + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + private: + const uint8_t* data_; + uint64_t start_; + uint64_t end_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_BUFFER_H diff --git a/libunwindstack/MemoryRange.h b/libunwindstack/MemoryRange.h new file mode 100644 index 000000000..3b4ab5c91 --- /dev/null +++ b/libunwindstack/MemoryRange.h @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_RANGE_H +#define _LIBUNWINDSTACK_MEMORY_RANGE_H + +#include + +#include +#include +#include + +#include + +namespace unwindstack { + +// MemoryRange maps one address range onto another. +// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset, +// such that range.read(offset) is equivalent to underlying.read(src_begin). +class MemoryRange : public Memory { + public: + MemoryRange(const std::shared_ptr& memory, uint64_t begin, uint64_t length, + uint64_t offset); + virtual ~MemoryRange() = default; + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + uint64_t offset() { return offset_; } + uint64_t length() { return length_; } + + private: + std::shared_ptr memory_; + uint64_t begin_; + uint64_t length_; + uint64_t offset_; +}; + +class MemoryRanges : public Memory { + public: + MemoryRanges() = default; + virtual ~MemoryRanges() = default; + + void Insert(MemoryRange* memory); + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + private: + std::map> maps_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_RANGE_H diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h new file mode 100644 index 000000000..db367d649 --- /dev/null +++ b/libunwindstack/MemoryRemote.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 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 _LIBUNWINDSTACK_MEMORY_REMOTE_H +#define _LIBUNWINDSTACK_MEMORY_REMOTE_H + +#include +#include + +#include + +#include + +namespace unwindstack { + +class MemoryRemote : public Memory { + public: + MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {} + virtual ~MemoryRemote() = default; + + size_t Read(uint64_t addr, void* dst, size_t size) override; + + pid_t pid() { return pid_; } + + private: + pid_t pid_; + std::atomic_uintptr_t read_redirect_func_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_MEMORY_REMOTE_H diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index 025fd98da..13ce10f00 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h @@ -25,10 +25,11 @@ #include #include -#include namespace unwindstack { +class MemoryFileAtOffset; + struct MapInfo { MapInfo(MapInfo* map_info, uint64_t start, uint64_t end, uint64_t offset, uint64_t flags, const char* name) diff --git a/libunwindstack/include/unwindstack/Memory.h b/libunwindstack/include/unwindstack/Memory.h index b3beb6eae..310656497 100644 --- a/libunwindstack/include/unwindstack/Memory.h +++ b/libunwindstack/include/unwindstack/Memory.h @@ -21,12 +21,8 @@ #include #include -#include -#include #include #include -#include -#include namespace unwindstack { @@ -37,6 +33,9 @@ class Memory { static std::shared_ptr CreateProcessMemory(pid_t pid); static std::shared_ptr CreateProcessMemoryCached(pid_t pid); + static std::shared_ptr CreateOfflineMemory(const uint8_t* data, uint64_t start, + uint64_t end); + static std::unique_ptr CreateFileMemory(const std::string& path, uint64_t offset); virtual bool ReadString(uint64_t addr, std::string* string, uint64_t max_read = UINT64_MAX); @@ -55,157 +54,6 @@ class Memory { } }; -class MemoryCache : public Memory { - public: - MemoryCache(Memory* memory) : impl_(memory) {} - virtual ~MemoryCache() = default; - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - void Clear() override { cache_.clear(); } - - private: - constexpr static size_t kCacheBits = 12; - constexpr static size_t kCacheMask = (1 << kCacheBits) - 1; - constexpr static size_t kCacheSize = 1 << kCacheBits; - std::unordered_map cache_; - - std::unique_ptr impl_; -}; - -class MemoryBuffer : public Memory { - public: - MemoryBuffer() = default; - virtual ~MemoryBuffer() = default; - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - uint8_t* GetPtr(size_t offset); - - void Resize(size_t size) { raw_.resize(size); } - - uint64_t Size() { return raw_.size(); } - - private: - std::vector raw_; -}; - -class MemoryFileAtOffset : public Memory { - public: - MemoryFileAtOffset() = default; - virtual ~MemoryFileAtOffset(); - - bool Init(const std::string& file, uint64_t offset, uint64_t size = UINT64_MAX); - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - size_t Size() { return size_; } - - void Clear() override; - - protected: - size_t size_ = 0; - size_t offset_ = 0; - uint8_t* data_ = nullptr; -}; - -class MemoryRemote : public Memory { - public: - MemoryRemote(pid_t pid) : pid_(pid), read_redirect_func_(0) {} - virtual ~MemoryRemote() = default; - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - pid_t pid() { return pid_; } - - private: - pid_t pid_; - std::atomic_uintptr_t read_redirect_func_; -}; - -class MemoryLocal : public Memory { - public: - MemoryLocal() = default; - virtual ~MemoryLocal() = default; - - size_t Read(uint64_t addr, void* dst, size_t size) override; -}; - -// MemoryRange maps one address range onto another. -// The range [src_begin, src_begin + length) in the underlying Memory is mapped onto offset, -// such that range.read(offset) is equivalent to underlying.read(src_begin). -class MemoryRange : public Memory { - public: - MemoryRange(const std::shared_ptr& memory, uint64_t begin, uint64_t length, - uint64_t offset); - virtual ~MemoryRange() = default; - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - uint64_t offset() { return offset_; } - uint64_t length() { return length_; } - - private: - std::shared_ptr memory_; - uint64_t begin_; - uint64_t length_; - uint64_t offset_; -}; - -class MemoryRanges : public Memory { - public: - MemoryRanges() = default; - virtual ~MemoryRanges() = default; - - void Insert(MemoryRange* memory); - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - private: - std::map> maps_; -}; - -class MemoryOffline : public Memory { - public: - MemoryOffline() = default; - virtual ~MemoryOffline() = default; - - bool Init(const std::string& file, uint64_t offset); - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - private: - std::unique_ptr memory_; -}; - -class MemoryOfflineBuffer : public Memory { - public: - MemoryOfflineBuffer(const uint8_t* data, uint64_t start, uint64_t end); - virtual ~MemoryOfflineBuffer() = default; - - void Reset(const uint8_t* data, uint64_t start, uint64_t end); - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - private: - const uint8_t* data_; - uint64_t start_; - uint64_t end_; -}; - -class MemoryOfflineParts : public Memory { - public: - MemoryOfflineParts() = default; - virtual ~MemoryOfflineParts(); - - void Add(MemoryOffline* memory) { memories_.push_back(memory); } - - size_t Read(uint64_t addr, void* dst, size_t size) override; - - private: - std::vector memories_; -}; - } // namespace unwindstack #endif // _LIBUNWINDSTACK_MEMORY_H diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp index 28e0e76b9..a6c12aab0 100644 --- a/libunwindstack/tests/MemoryBufferTest.cpp +++ b/libunwindstack/tests/MemoryBufferTest.cpp @@ -18,9 +18,8 @@ #include -#include - #include "LogFake.h" +#include "MemoryBuffer.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp index a3def206f..3bd3e4dbe 100644 --- a/libunwindstack/tests/MemoryCacheTest.cpp +++ b/libunwindstack/tests/MemoryCacheTest.cpp @@ -20,8 +20,7 @@ #include -#include - +#include "MemoryCache.h" #include "MemoryFake.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp index d7d1ace64..4124a491c 100644 --- a/libunwindstack/tests/MemoryFileTest.cpp +++ b/libunwindstack/tests/MemoryFileTest.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include "MemoryFileAtOffset.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp index 5a389d0a9..c9e5dc0fd 100644 --- a/libunwindstack/tests/MemoryLocalTest.cpp +++ b/libunwindstack/tests/MemoryLocalTest.cpp @@ -22,7 +22,7 @@ #include -#include +#include "MemoryLocal.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryOfflineBufferTest.cpp b/libunwindstack/tests/MemoryOfflineBufferTest.cpp index f022884cb..c62c53dae 100644 --- a/libunwindstack/tests/MemoryOfflineBufferTest.cpp +++ b/libunwindstack/tests/MemoryOfflineBufferTest.cpp @@ -18,9 +18,8 @@ #include -#include - #include "LogFake.h" +#include "MemoryOfflineBuffer.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryOfflineTest.cpp b/libunwindstack/tests/MemoryOfflineTest.cpp index ab9aa9dc9..d0c441ba5 100644 --- a/libunwindstack/tests/MemoryOfflineTest.cpp +++ b/libunwindstack/tests/MemoryOfflineTest.cpp @@ -19,7 +19,8 @@ #include #include -#include + +#include "MemoryOffline.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp index 2bac95b61..2d4f141ab 100644 --- a/libunwindstack/tests/MemoryRangeTest.cpp +++ b/libunwindstack/tests/MemoryRangeTest.cpp @@ -21,9 +21,8 @@ #include -#include - #include "MemoryFake.h" +#include "MemoryRange.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp index d24fcd23f..e4e9fc4e9 100644 --- a/libunwindstack/tests/MemoryRangesTest.cpp +++ b/libunwindstack/tests/MemoryRangesTest.cpp @@ -20,9 +20,8 @@ #include -#include - #include "MemoryFake.h" +#include "MemoryRange.h" namespace unwindstack { diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp index fb56e8afb..c90dedcec 100644 --- a/libunwindstack/tests/MemoryRemoteTest.cpp +++ b/libunwindstack/tests/MemoryRemoteTest.cpp @@ -30,7 +30,7 @@ #include #include -#include +#include "MemoryRemote.h" #include "MemoryFake.h" #include "TestUtils.h" diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 553b34406..baada8281 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -43,6 +42,7 @@ #include #include "ElfTestUtils.h" +#include "MemoryOffline.h" #include "TestUtils.h" namespace unwindstack { diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp index 4e3801511..f76a101df 100644 --- a/libunwindstack/tests/UnwindTest.cpp +++ b/libunwindstack/tests/UnwindTest.cpp @@ -35,11 +35,11 @@ #include #include -#include #include #include #include +#include "MemoryRemote.h" #include "TestUtils.h" namespace unwindstack { diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp index 92e5c0af3..7a6d8ba46 100644 --- a/libunwindstack/tools/unwind_info.cpp +++ b/libunwindstack/tools/unwind_info.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include "ArmExidx.h" #include "ElfInterfaceArm.h" @@ -105,14 +106,7 @@ int GetElfInfo(const char* file, uint64_t offset) { // Send all log messages to stdout. log_to_stdout(true); - MemoryFileAtOffset* memory = new MemoryFileAtOffset; - if (!memory->Init(file, offset)) { - // Initializatation failed. - printf("Failed to init\n"); - return 1; - } - - Elf elf(memory); + Elf elf(Memory::CreateFileMemory(file, offset).release()); if (!elf.Init() || !elf.valid()) { printf("%s is not a valid elf file.\n", file); return 1; diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp index b77a86bbf..d0562d9cf 100644 --- a/libunwindstack/tools/unwind_reg_info.cpp +++ b/libunwindstack/tools/unwind_reg_info.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "ArmExidx.h" #include "DwarfOp.h" @@ -165,14 +166,7 @@ void PrintArmRegInformation(ElfInterfaceArm* interface, uint64_t pc) { } int GetInfo(const char* file, uint64_t pc) { - MemoryFileAtOffset* memory = new MemoryFileAtOffset; - if (!memory->Init(file, 0)) { - // Initializatation failed. - printf("Failed to init\n"); - return 1; - } - - Elf elf(memory); + Elf elf(Memory::CreateFileMemory(file, pc).release()); if (!elf.Init() || !elf.valid()) { printf("%s is not a valid elf file.\n", file); return 1; @@ -205,7 +199,7 @@ int GetInfo(const char* file, uint64_t pc) { DwarfSection* section = interface->eh_frame(); if (section != nullptr) { printf("\neh_frame:\n"); - PrintRegInformation(section, memory, pc, elf.class_type()); + PrintRegInformation(section, elf.memory(), pc, elf.class_type()); } else { printf("\nno eh_frame information\n"); } @@ -213,7 +207,7 @@ int GetInfo(const char* file, uint64_t pc) { section = interface->debug_frame(); if (section != nullptr) { printf("\ndebug_frame:\n"); - PrintRegInformation(section, memory, pc, elf.class_type()); + PrintRegInformation(section, elf.memory(), pc, elf.class_type()); printf("\n"); } else { printf("\nno debug_frame information\n"); diff --git a/libunwindstack/tools/unwind_symbols.cpp b/libunwindstack/tools/unwind_symbols.cpp index b0a4dd07a..8df228412 100644 --- a/libunwindstack/tools/unwind_symbols.cpp +++ b/libunwindstack/tools/unwind_symbols.cpp @@ -59,13 +59,7 @@ int main(int argc, char** argv) { // Send all log messages to stdout. unwindstack::log_to_stdout(true); - unwindstack::MemoryFileAtOffset* memory = new unwindstack::MemoryFileAtOffset; - if (!memory->Init(argv[1], 0)) { - printf("Failed to init\n"); - return 1; - } - - unwindstack::Elf elf(memory); + unwindstack::Elf elf(unwindstack::Memory::CreateFileMemory(argv[1], 0).release()); if (!elf.Init() || !elf.valid()) { printf("%s is not a valid elf file.\n", argv[1]); return 1;