Merge "Internalize subclasses of Memory" am: 5fb660930c
am: 7ad4c6b7f8
Change-Id: Ic0ba267a0bdb081158ae4cc81ec025cc3dba0947
diff --git a/libbacktrace/Android.bp b/libbacktrace/Android.bp
index e171155..9ece847 100644
--- a/libbacktrace/Android.bp
+++ b/libbacktrace/Android.bp
@@ -135,7 +135,6 @@
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 36640cd..a128623 100644
--- a/libbacktrace/UnwindStack.cpp
+++ b/libbacktrace/UnwindStack.cpp
@@ -129,22 +129,6 @@
return true;
}
-bool Backtrace::UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map,
- const backtrace_stackinfo_t& stack,
- std::vector<backtrace_frame_data_t>* frames,
- BacktraceUnwindError* error) {
- UnwindStackOfflineMap* offline_map = reinterpret_cast<UnwindStackOfflineMap*>(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 @@
}
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 @@
}
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<unwindstack::Regs> 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<backtrace_map_t>& maps,
- const backtrace_stackinfo_t& stack) {
- std::unique_ptr<UnwindStackOfflineMap> map(
- reinterpret_cast<UnwindStackOfflineMap*>(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 4ec591d..47f6757 100644
--- a/libbacktrace/UnwindStack.h
+++ b/libbacktrace/UnwindStack.h
@@ -19,6 +19,7 @@
#include <stdint.h>
+#include <memory>
#include <string>
#include <backtrace/BacktraceMap.h>
@@ -49,23 +50,7 @@
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<unwindstack::Memory> memory_;
};
#endif // _LIBBACKTRACE_UNWIND_STACK_H
diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp
index 4518891..aa0b17c 100644
--- a/libbacktrace/UnwindStackMap.cpp
+++ b/libbacktrace/UnwindStackMap.cpp
@@ -132,43 +132,6 @@
return process_memory_;
}
-UnwindStackOfflineMap::UnwindStackOfflineMap(pid_t pid) : UnwindStackMap(pid) {}
-
-bool UnwindStackOfflineMap::Build() {
- return false;
-}
-
-bool UnwindStackOfflineMap::Build(const std::vector<backtrace_map_t>& 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 @@
}
return map;
}
-
-//-------------------------------------------------------------------------
-// BacktraceMap create offline function.
-//-------------------------------------------------------------------------
-BacktraceMap* BacktraceMap::CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& 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 e19b605..f0e7d8b 100644
--- a/libbacktrace/UnwindStackMap.h
+++ b/libbacktrace/UnwindStackMap.h
@@ -33,6 +33,7 @@
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
+#include <unwindstack/Memory.h>
// Forward declarations.
class UnwindDexFile;
@@ -74,19 +75,4 @@
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<backtrace_map_t>& 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 662fb99..0000000
--- 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 <inttypes.h>
-#include <pthread.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <functional>
-#include <memory>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/macros.h>
-#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
-#include <android-base/threads.h>
-#include <backtrace/Backtrace.h>
-#include <backtrace/BacktraceMap.h>
-
-#include <gtest/gtest.h>
-
-#include "BacktraceTest.h"
-
-struct FunctionSymbol {
- std::string name;
- uint64_t start;
- uint64_t end;
-};
-
-static std::vector<FunctionSymbol> GetFunctionSymbols() {
- std::vector<FunctionSymbol> symbols = {
- {"unknown_start", 0, 0},
- {"test_level_one", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_one_), 0},
- {"test_level_two", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_two_), 0},
- {"test_level_three", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_three_), 0},
- {"test_level_four", reinterpret_cast<uint64_t>(&BacktraceTest::test_level_four_), 0},
- {"test_recursive_call", reinterpret_cast<uint64_t>(&BacktraceTest::test_recursive_call_), 0},
- {"test_get_context_and_wait",
- reinterpret_cast<uint64_t>(&BacktraceTest::test_get_context_and_wait_), 0},
- {"unknown_end", static_cast<uint64_t>(-1), static_cast<uint64_t>(-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<const uint8_t*>(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<uint8_t>* 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<uint8_t> ucontext;
- pid_t tid;
- volatile int exit_flag;
-};
-
-static void* OfflineThreadFunc(void* arg) {
- OfflineThreadArg* fn_arg = reinterpret_cast<OfflineThreadArg*>(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<uint64_t>(stack);
- pthread_attr_t attr;
- ASSERT_EQ(0, pthread_attr_init(&attr));
- ASSERT_EQ(0, pthread_attr_setstack(&attr, reinterpret_cast<void*>(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<uint8_t> stack_data(reinterpret_cast<uint8_t*>(stack),
- reinterpret_cast<uint8_t*>(stack) + stack_size);
- arg.exit_flag = 1;
- ASSERT_EQ(0, pthread_join(thread, nullptr));
- ASSERT_EQ(0, munmap(stack, stack_size));
-
- std::unique_ptr<BacktraceMap> 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<FunctionSymbol> 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<FunctionSymbol>& symbols) {
- for (auto& symbol : symbols) {
- if (addr >= symbol.start && addr < symbol.end) {
- return symbol.name;
- }
- }
- return "";
-}
-
-struct OfflineTestData {
- int pid;
- int tid;
- std::vector<backtrace_map_t> maps;
- std::vector<uint8_t> ucontext;
- backtrace_stackinfo_t stack_info;
- std::vector<uint8_t> stack;
- std::vector<FunctionSymbol> 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<std::string> 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(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<uint64_t> 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(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 404e7e8..664b531 100644
--- a/libbacktrace/include/backtrace/Backtrace.h
+++ b/libbacktrace/include/backtrace/Backtrace.h
@@ -126,24 +126,6 @@
// 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<backtrace_map_t>& 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 @@
std::vector<backtrace_frame_data_t>* frames, size_t num_ignore_frames,
std::vector<std::string>* skip_names, BacktraceUnwindError* error = nullptr);
- static bool UnwindOffline(unwindstack::Regs* regs, BacktraceMap* back_map,
- const backtrace_stackinfo_t& stack_info,
- std::vector<backtrace_frame_data_t>* 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 c564271..f8d5058 100644
--- a/libbacktrace/include/backtrace/BacktraceMap.h
+++ b/libbacktrace/include/backtrace/BacktraceMap.h
@@ -69,8 +69,6 @@
// is unsupported.
static BacktraceMap* Create(pid_t pid, bool uncached = false);
- static BacktraceMap* CreateOffline(pid_t pid, const std::vector<backtrace_map_t>& maps);
-
virtual ~BacktraceMap();
class iterator : public std::iterator<std::bidirectional_iterator_tag, backtrace_map_t*> {
diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp
index dee8eb3..f0e4138 100644
--- a/libunwindstack/ElfInterface.cpp
+++ b/libunwindstack/ElfInterface.cpp
@@ -29,12 +29,12 @@
#include <unwindstack/DwarfSection.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Log.h>
-#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#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 20bc4b9..8a85607 100644
--- a/libunwindstack/JitDebug.cpp
+++ b/libunwindstack/JitDebug.cpp
@@ -23,7 +23,8 @@
#include <unwindstack/Elf.h>
#include <unwindstack/JitDebug.h>
#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
+
+#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 d3cec06..1c0f1e6 100644
--- a/libunwindstack/MapInfo.cpp
+++ b/libunwindstack/MapInfo.cpp
@@ -27,7 +27,9 @@
#include <unwindstack/Elf.h>
#include <unwindstack/MapInfo.h>
#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
+
+#include "MemoryFileAtOffset.h"
+#include "MemoryRange.h"
namespace unwindstack {
diff --git a/libunwindstack/Memory.cpp b/libunwindstack/Memory.cpp
index 9904fef..a66cd5b 100644
--- a/libunwindstack/Memory.cpp
+++ b/libunwindstack/Memory.cpp
@@ -32,6 +32,14 @@
#include <unwindstack/Memory.h>
#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 @@
return false;
}
+std::unique_ptr<Memory> Memory::CreateFileMemory(const std::string& path, uint64_t offset) {
+ auto memory = std::make_unique<MemoryFileAtOffset>();
+
+ if (memory->Init(path, offset)) {
+ return memory;
+ }
+
+ return nullptr;
+}
+
std::shared_ptr<Memory> Memory::CreateProcessMemory(pid_t pid) {
if (pid == getpid()) {
return std::shared_ptr<Memory>(new MemoryLocal());
@@ -182,6 +200,11 @@
return std::shared_ptr<Memory>(new MemoryCache(new MemoryRemote(pid)));
}
+std::shared_ptr<Memory> Memory::CreateOfflineMemory(const uint8_t* data, uint64_t start,
+ uint64_t end) {
+ return std::shared_ptr<Memory>(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 0000000..3fe4bbb
--- /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 <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include <unwindstack/Memory.h>
+
+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<uint8_t> raw_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_BUFFER_H
diff --git a/libunwindstack/MemoryCache.h b/libunwindstack/MemoryCache.h
new file mode 100644
index 0000000..769d907
--- /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 <stdint.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include <unwindstack/Memory.h>
+
+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<uint64_t, uint8_t[kCacheSize]> cache_;
+
+ std::unique_ptr<Memory> impl_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_CACHE_H
diff --git a/libunwindstack/MemoryFileAtOffset.h b/libunwindstack/MemoryFileAtOffset.h
new file mode 100644
index 0000000..d136eb4
--- /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 <stdint.h>
+
+#include <unwindstack/Memory.h>
+
+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 0000000..29aaf12
--- /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 <stdint.h>
+
+#include <unwindstack/Memory.h>
+
+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 0000000..789f1a2
--- /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 <stdint.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <unwindstack/Memory.h>
+
+#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<MemoryRange> 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<MemoryOffline*> memories_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_OFFLINE_H
diff --git a/libunwindstack/MemoryOfflineBuffer.h b/libunwindstack/MemoryOfflineBuffer.h
new file mode 100644
index 0000000..64c49a1
--- /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 <stdint.h>
+
+#include <unwindstack/Memory.h>
+
+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 0000000..3b4ab5c
--- /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 <stdint.h>
+
+#include <map>
+#include <memory>
+#include <string>
+
+#include <unwindstack/Memory.h>
+
+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>& 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> 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<uint64_t, std::unique_ptr<MemoryRange>> maps_;
+};
+
+} // namespace unwindstack
+
+#endif // _LIBUNWINDSTACK_MEMORY_RANGE_H
diff --git a/libunwindstack/MemoryRemote.h b/libunwindstack/MemoryRemote.h
new file mode 100644
index 0000000..db367d6
--- /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 <stdint.h>
+#include <sys/types.h>
+
+#include <atomic>
+
+#include <unwindstack/Memory.h>
+
+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 025fd98..13ce10f 100644
--- a/libunwindstack/include/unwindstack/MapInfo.h
+++ b/libunwindstack/include/unwindstack/MapInfo.h
@@ -25,10 +25,11 @@
#include <string>
#include <unwindstack/Elf.h>
-#include <unwindstack/Memory.h>
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 b3beb6e..3106564 100644
--- a/libunwindstack/include/unwindstack/Memory.h
+++ b/libunwindstack/include/unwindstack/Memory.h
@@ -21,12 +21,8 @@
#include <sys/types.h>
#include <unistd.h>
-#include <atomic>
-#include <map>
#include <memory>
#include <string>
-#include <unordered_map>
-#include <vector>
namespace unwindstack {
@@ -37,6 +33,9 @@
static std::shared_ptr<Memory> CreateProcessMemory(pid_t pid);
static std::shared_ptr<Memory> CreateProcessMemoryCached(pid_t pid);
+ static std::shared_ptr<Memory> CreateOfflineMemory(const uint8_t* data, uint64_t start,
+ uint64_t end);
+ static std::unique_ptr<Memory> 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 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<uint64_t, uint8_t[kCacheSize]> cache_;
-
- std::unique_ptr<Memory> 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<uint8_t> 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>& 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> 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<uint64_t, std::unique_ptr<MemoryRange>> 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<MemoryRange> 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<MemoryOffline*> memories_;
-};
-
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_MEMORY_H
diff --git a/libunwindstack/tests/MemoryBufferTest.cpp b/libunwindstack/tests/MemoryBufferTest.cpp
index 28e0e76..a6c12aa 100644
--- a/libunwindstack/tests/MemoryBufferTest.cpp
+++ b/libunwindstack/tests/MemoryBufferTest.cpp
@@ -18,9 +18,8 @@
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
-
#include "LogFake.h"
+#include "MemoryBuffer.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryCacheTest.cpp b/libunwindstack/tests/MemoryCacheTest.cpp
index a3def20..3bd3e4d 100644
--- a/libunwindstack/tests/MemoryCacheTest.cpp
+++ b/libunwindstack/tests/MemoryCacheTest.cpp
@@ -20,8 +20,7 @@
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
-
+#include "MemoryCache.h"
#include "MemoryFake.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryFileTest.cpp b/libunwindstack/tests/MemoryFileTest.cpp
index d7d1ace..4124a49 100644
--- a/libunwindstack/tests/MemoryFileTest.cpp
+++ b/libunwindstack/tests/MemoryFileTest.cpp
@@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
+#include "MemoryFileAtOffset.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryLocalTest.cpp b/libunwindstack/tests/MemoryLocalTest.cpp
index 5a389d0..c9e5dc0 100644
--- a/libunwindstack/tests/MemoryLocalTest.cpp
+++ b/libunwindstack/tests/MemoryLocalTest.cpp
@@ -22,7 +22,7 @@
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
+#include "MemoryLocal.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryOfflineBufferTest.cpp b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
index f022884..c62c53d 100644
--- a/libunwindstack/tests/MemoryOfflineBufferTest.cpp
+++ b/libunwindstack/tests/MemoryOfflineBufferTest.cpp
@@ -18,9 +18,8 @@
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
-
#include "LogFake.h"
+#include "MemoryOfflineBuffer.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryOfflineTest.cpp b/libunwindstack/tests/MemoryOfflineTest.cpp
index ab9aa9d..d0c441b 100644
--- a/libunwindstack/tests/MemoryOfflineTest.cpp
+++ b/libunwindstack/tests/MemoryOfflineTest.cpp
@@ -19,7 +19,8 @@
#include <gtest/gtest.h>
#include <android-base/file.h>
-#include <unwindstack/Memory.h>
+
+#include "MemoryOffline.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryRangeTest.cpp b/libunwindstack/tests/MemoryRangeTest.cpp
index 2bac95b..2d4f141 100644
--- a/libunwindstack/tests/MemoryRangeTest.cpp
+++ b/libunwindstack/tests/MemoryRangeTest.cpp
@@ -21,9 +21,8 @@
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
-
#include "MemoryFake.h"
+#include "MemoryRange.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryRangesTest.cpp b/libunwindstack/tests/MemoryRangesTest.cpp
index d24fcd2..e4e9fc4 100644
--- a/libunwindstack/tests/MemoryRangesTest.cpp
+++ b/libunwindstack/tests/MemoryRangesTest.cpp
@@ -20,9 +20,8 @@
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
-
#include "MemoryFake.h"
+#include "MemoryRange.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/MemoryRemoteTest.cpp b/libunwindstack/tests/MemoryRemoteTest.cpp
index fb56e8a..c90dedc 100644
--- a/libunwindstack/tests/MemoryRemoteTest.cpp
+++ b/libunwindstack/tests/MemoryRemoteTest.cpp
@@ -30,7 +30,7 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
-#include <unwindstack/Memory.h>
+#include "MemoryRemote.h"
#include "MemoryFake.h"
#include "TestUtils.h"
diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp
index 553b344..baada82 100644
--- a/libunwindstack/tests/UnwindOfflineTest.cpp
+++ b/libunwindstack/tests/UnwindOfflineTest.cpp
@@ -35,7 +35,6 @@
#include <unwindstack/MachineX86.h>
#include <unwindstack/MachineX86_64.h>
#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
#include <unwindstack/RegsArm.h>
#include <unwindstack/RegsArm64.h>
#include <unwindstack/RegsX86.h>
@@ -43,6 +42,7 @@
#include <unwindstack/Unwinder.h>
#include "ElfTestUtils.h"
+#include "MemoryOffline.h"
#include "TestUtils.h"
namespace unwindstack {
diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp
index 4e38015..f76a101 100644
--- a/libunwindstack/tests/UnwindTest.cpp
+++ b/libunwindstack/tests/UnwindTest.cpp
@@ -35,11 +35,11 @@
#include <android-base/threads.h>
#include <unwindstack/Maps.h>
-#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/RegsGetLocal.h>
#include <unwindstack/Unwinder.h>
+#include "MemoryRemote.h"
#include "TestUtils.h"
namespace unwindstack {
diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp
index 92e5c0a..7a6d8ba 100644
--- a/libunwindstack/tools/unwind_info.cpp
+++ b/libunwindstack/tools/unwind_info.cpp
@@ -31,6 +31,7 @@
#include <unwindstack/Elf.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
#include "ArmExidx.h"
#include "ElfInterfaceArm.h"
@@ -105,14 +106,7 @@
// 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 b77a86b..d0562d9 100644
--- a/libunwindstack/tools/unwind_reg_info.cpp
+++ b/libunwindstack/tools/unwind_reg_info.cpp
@@ -33,6 +33,7 @@
#include <unwindstack/Elf.h>
#include <unwindstack/ElfInterface.h>
#include <unwindstack/Log.h>
+#include <unwindstack/Memory.h>
#include "ArmExidx.h"
#include "DwarfOp.h"
@@ -165,14 +166,7 @@
}
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 @@
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 @@
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 b0a4dd0..8df2284 100644
--- a/libunwindstack/tools/unwind_symbols.cpp
+++ b/libunwindstack/tools/unwind_symbols.cpp
@@ -59,13 +59,7 @@
// 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;