Merge "Internalize subclasses of Memory"

am: 5fb660930c

Change-Id: I1fc6df9d1c6a195e78e62a6361ad1c9df0e28a8c
This commit is contained in:
Christopher Ferris 2019-06-12 09:23:19 -07:00 committed by android-build-merger
commit 7ad4c6b7f8
36 changed files with 453 additions and 790 deletions

View File

@ -135,7 +135,6 @@ cc_test {
defaults: ["libbacktrace_common"],
host_supported: true,
srcs: [
"backtrace_offline_test.cpp",
"backtrace_test.cpp",
],

View File

@ -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<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 @@ 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<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);
}

View File

@ -19,6 +19,7 @@
#include <stdint.h>
#include <memory>
#include <string>
#include <backtrace/BacktraceMap.h>
@ -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<unwindstack::Memory> memory_;
};
#endif // _LIBBACKTRACE_UNWIND_STACK_H

View File

@ -132,43 +132,6 @@ std::shared_ptr<unwindstack::Memory> UnwindStackMap::GetProcessMemory() {
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 @@ BacktraceMap* BacktraceMap::Create(pid_t pid, bool uncached) {
}
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;
}

View File

@ -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 @@ 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<backtrace_map_t>& maps);
bool CreateProcessMemory(const backtrace_stackinfo_t& stack);
private:
unwindstack::MemoryOfflineBuffer* memory_ = nullptr;
};
#endif // _LIBBACKTRACE_UNWINDSTACK_MAP_H

View File

@ -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);
}

View File

@ -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<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 @@ class Backtrace {
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.

View File

@ -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<backtrace_map_t>& maps);
virtual ~BacktraceMap();
class iterator : public std::iterator<std::bidirectional_iterator_tag, backtrace_map_t*> {

View File

@ -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 {

View File

@ -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

View File

@ -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 {

View File

@ -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 @@ bool Memory::ReadString(uint64_t addr, std::string* string, uint64_t max_read) {
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 @@ std::shared_ptr<Memory> Memory::CreateProcessMemoryCached(pid_t pid) {
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;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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 @@ class Memory {
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 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<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

View File

@ -18,9 +18,8 @@
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "LogFake.h"
#include "MemoryBuffer.h"
namespace unwindstack {

View File

@ -20,8 +20,7 @@
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "MemoryCache.h"
#include "MemoryFake.h"
namespace unwindstack {

View File

@ -21,7 +21,7 @@
#include <android-base/file.h>
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "MemoryFileAtOffset.h"
namespace unwindstack {

View File

@ -22,7 +22,7 @@
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "MemoryLocal.h"
namespace unwindstack {

View File

@ -18,9 +18,8 @@
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "LogFake.h"
#include "MemoryOfflineBuffer.h"
namespace unwindstack {

View File

@ -19,7 +19,8 @@
#include <gtest/gtest.h>
#include <android-base/file.h>
#include <unwindstack/Memory.h>
#include "MemoryOffline.h"
namespace unwindstack {

View File

@ -21,9 +21,8 @@
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "MemoryFake.h"
#include "MemoryRange.h"
namespace unwindstack {

View File

@ -20,9 +20,8 @@
#include <gtest/gtest.h>
#include <unwindstack/Memory.h>
#include "MemoryFake.h"
#include "MemoryRange.h"
namespace unwindstack {

View File

@ -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"

View File

@ -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 {

View File

@ -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 {

View File

@ -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 @@ 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;

View File

@ -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 @@ 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");

View File

@ -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;