Merge "Fix incorrect usage of relative pcs."

This commit is contained in:
Christopher Ferris 2017-11-30 03:11:41 +00:00 committed by Gerrit Code Review
commit 96b5268405
22 changed files with 238 additions and 64 deletions

View File

@ -130,6 +130,7 @@ cc_test {
"tests/RegsStepIfSignalHandlerTest.cpp",
"tests/RegsTest.cpp",
"tests/SymbolsTest.cpp",
"tests/UnwindOfflineTest.cpp",
"tests/UnwindTest.cpp",
"tests/UnwinderTest.cpp",
],
@ -153,6 +154,8 @@ cc_test {
data: [
"tests/files/elf32.xz",
"tests/files/elf64.xz",
"tests/files/offline/straddle_arm32/*",
"tests/files/offline/straddle_arm64/*",
],
}

View File

@ -40,7 +40,7 @@ class DwarfEhFrame : public DwarfSectionImpl<AddressType> {
uint64_t AdjustPcFromFde(uint64_t pc) override {
// The eh_frame uses relative pcs.
return pc + this->memory_.cur_offset();
return pc + this->memory_.cur_offset() - 4;
}
};

View File

@ -104,8 +104,8 @@ bool Elf::GetFunctionName(uint64_t addr, std::string* name, uint64_t* func_offse
}
// The relative pc is always relative to the start of the map from which it comes.
bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
bool* finished) {
bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
Memory* process_memory, bool* finished) {
if (!valid_) {
return false;
}
@ -117,16 +117,16 @@ bool Elf::Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process
}
// Adjust the load bias to get the real relative pc.
if (rel_pc < load_bias_) {
if (adjusted_rel_pc < load_bias_) {
return false;
}
rel_pc -= load_bias_;
adjusted_rel_pc -= load_bias_;
// Lock during the step which can update information in the object.
std::lock_guard<std::mutex> guard(lock_);
return interface_->Step(rel_pc, regs, process_memory, finished) ||
return interface_->Step(adjusted_rel_pc, regs, process_memory, finished) ||
(gnu_debugdata_interface_ &&
gnu_debugdata_interface_->Step(rel_pc, regs, process_memory, finished));
gnu_debugdata_interface_->Step(adjusted_rel_pc, regs, process_memory, finished));
}
bool Elf::IsValidElf(Memory* memory) {

View File

@ -64,13 +64,13 @@ static MapInfo* InternalParseLine(const char* line) {
// 6f000000-6f01e000 rwxp 00000000 00:0c 16389419 /system/lib/libcomposer.so
char* str;
const char* old_str = line;
uint64_t start = strtoul(old_str, &str, 16);
uint64_t start = strtoull(old_str, &str, 16);
if (old_str == str || *str++ != '-') {
return nullptr;
}
old_str = str;
uint64_t end = strtoul(old_str, &str, 16);
uint64_t end = strtoull(old_str, &str, 16);
if (old_str == str || !std::isspace(*str++)) {
return nullptr;
}
@ -112,14 +112,14 @@ static MapInfo* InternalParseLine(const char* line) {
}
old_str = str;
uint64_t offset = strtoul(old_str, &str, 16);
uint64_t offset = strtoull(old_str, &str, 16);
if (old_str == str || !std::isspace(*str)) {
return nullptr;
}
// Ignore the 00:00 values.
old_str = str;
(void)strtoul(old_str, &str, 16);
(void)strtoull(old_str, &str, 16);
if (old_str == str || *str++ != ':') {
return nullptr;
}
@ -129,14 +129,14 @@ static MapInfo* InternalParseLine(const char* line) {
// Skip the inode.
old_str = str;
(void)strtoul(str, &str, 16);
(void)strtoull(str, &str, 16);
if (old_str == str || !std::isspace(*str++)) {
return nullptr;
}
// Skip decimal digit.
old_str = str;
(void)strtoul(old_str, &str, 10);
(void)strtoull(old_str, &str, 10);
if (old_str == str || (!std::isspace(*str) && *str != '\0')) {
return nullptr;
}

View File

@ -32,27 +32,20 @@
namespace unwindstack {
void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc) {
void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc) {
size_t frame_num = frames_.size();
frames_.resize(frame_num + 1);
FrameData* frame = &frames_.at(frame_num);
frame->num = frame_num;
frame->pc = regs_->pc();
frame->sp = regs_->sp();
frame->rel_pc = rel_pc;
frame->rel_pc = adjusted_rel_pc;
if (map_info == nullptr) {
frame->pc = regs_->pc();
return;
}
if (adjust_pc) {
// Don't adjust the first frame pc.
frame->rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
// Adjust the original pc.
frame->pc -= rel_pc - frame->rel_pc;
}
frame->pc = map_info->start + adjusted_rel_pc;
frame->map_name = map_info->name;
frame->map_offset = map_info->offset;
frame->map_start = map_info->start;
@ -92,21 +85,29 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
MapInfo* map_info = maps_->Find(regs_->pc());
uint64_t rel_pc;
uint64_t adjusted_rel_pc;
Elf* elf;
if (map_info == nullptr) {
rel_pc = regs_->pc();
adjusted_rel_pc = rel_pc;
} else {
if (ShouldStop(map_suffixes_to_ignore, map_info->name)) {
break;
}
elf = map_info->GetElf(process_memory_, true);
rel_pc = elf->GetRelPc(regs_->pc(), map_info);
if (adjust_pc) {
adjusted_rel_pc = regs_->GetAdjustedPc(rel_pc, elf);
} else {
adjusted_rel_pc = rel_pc;
}
}
if (map_info == nullptr || initial_map_names_to_skip == nullptr ||
std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(),
basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) {
FillInFrame(map_info, elf, rel_pc, adjust_pc);
FillInFrame(map_info, elf, adjusted_rel_pc);
// Once a frame is added, stop skipping frames.
initial_map_names_to_skip = nullptr;
}
@ -133,7 +134,8 @@ void Unwinder::Unwind(const std::vector<std::string>* initial_map_names_to_skip,
in_device_map = true;
} else {
bool finished;
stepped = elf->Step(rel_pc, map_info->elf_offset, regs_, process_memory_.get(), &finished);
stepped = elf->Step(rel_pc, adjusted_rel_pc, map_info->elf_offset, regs_,
process_memory_.get(), &finished);
if (stepped && finished) {
break;
}

View File

@ -51,8 +51,8 @@ class Elf {
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
bool Step(uint64_t rel_pc, uint64_t elf_offset, Regs* regs, Memory* process_memory,
bool* finished);
bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
Memory* process_memory, bool* finished);
ElfInterface* CreateInterfaceFromMemory(Memory* memory);

View File

@ -70,7 +70,7 @@ class Unwinder {
static std::string FormatFrame(const FrameData& frame, bool bits32);
private:
void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, bool adjust_pc);
void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc);
size_t max_frames_;
Maps* maps_;

View File

@ -109,23 +109,23 @@ TYPED_TEST_P(DwarfEhFrameTest, Init32) {
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
EXPECT_EQ(0x660cU, info.start);
EXPECT_EQ(0x680cU, info.end);
EXPECT_EQ(0x6608U, info.start);
EXPECT_EQ(0x6808U, info.end);
this->eh_frame_->TestGetFdeInfo(1, &info);
EXPECT_EQ(0x5200U, info.offset);
EXPECT_EQ(0x770cU, info.start);
EXPECT_EQ(0x7a0cU, info.end);
EXPECT_EQ(0x7708U, info.start);
EXPECT_EQ(0x7a08U, info.end);
this->eh_frame_->TestGetFdeInfo(2, &info);
EXPECT_EQ(0x5400U, info.offset);
EXPECT_EQ(0x890cU, info.start);
EXPECT_EQ(0x8d0cU, info.end);
EXPECT_EQ(0x8908U, info.start);
EXPECT_EQ(0x8d08U, info.end);
this->eh_frame_->TestGetFdeInfo(3, &info);
EXPECT_EQ(0x5500U, info.offset);
EXPECT_EQ(0x9a0cU, info.start);
EXPECT_EQ(0x9f0cU, info.end);
EXPECT_EQ(0x9a08U, info.start);
EXPECT_EQ(0x9f08U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init32_fde_not_following_cie) {
@ -193,23 +193,23 @@ TYPED_TEST_P(DwarfEhFrameTest, Init64) {
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
EXPECT_EQ(0x661cU, info.start);
EXPECT_EQ(0x681cU, info.end);
EXPECT_EQ(0x6618U, info.start);
EXPECT_EQ(0x6818U, info.end);
this->eh_frame_->TestGetFdeInfo(1, &info);
EXPECT_EQ(0x5200U, info.offset);
EXPECT_EQ(0x771cU, info.start);
EXPECT_EQ(0x7a1cU, info.end);
EXPECT_EQ(0x7718U, info.start);
EXPECT_EQ(0x7a18U, info.end);
this->eh_frame_->TestGetFdeInfo(2, &info);
EXPECT_EQ(0x5400U, info.offset);
EXPECT_EQ(0x891cU, info.start);
EXPECT_EQ(0x8d1cU, info.end);
EXPECT_EQ(0x8918U, info.start);
EXPECT_EQ(0x8d18U, info.end);
this->eh_frame_->TestGetFdeInfo(3, &info);
EXPECT_EQ(0x5500U, info.offset);
EXPECT_EQ(0x9a1cU, info.start);
EXPECT_EQ(0x9f1cU, info.end);
EXPECT_EQ(0x9a18U, info.start);
EXPECT_EQ(0x9f18U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init64_fde_not_following_cie) {
@ -261,8 +261,8 @@ TYPED_TEST_P(DwarfEhFrameTest, Init_version1) {
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
EXPECT_EQ(0x660aU, info.start);
EXPECT_EQ(0x680aU, info.end);
EXPECT_EQ(0x6606U, info.start);
EXPECT_EQ(0x6806U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
@ -304,8 +304,8 @@ TYPED_TEST_P(DwarfEhFrameTest, Init_version4) {
typename DwarfEhFrame<TypeParam>::FdeInfo info(0, 0, 0);
this->eh_frame_->TestGetFdeInfo(0, &info);
EXPECT_EQ(0x5100U, info.offset);
EXPECT_EQ(0x660aU, info.start);
EXPECT_EQ(0x680aU, info.end);
EXPECT_EQ(0x6606U, info.start);
EXPECT_EQ(0x6806U, info.end);
}
TYPED_TEST_P(DwarfEhFrameTest, GetFdeOffsetFromPc) {
@ -384,8 +384,8 @@ TYPED_TEST_P(DwarfEhFrameTest, GetCieFde32) {
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
EXPECT_EQ(0x1d00cU, fde->pc_start);
EXPECT_EQ(0x1d10cU, fde->pc_end);
EXPECT_EQ(0x1d008U, fde->pc_start);
EXPECT_EQ(0x1d108U, fde->pc_end);
EXPECT_EQ(0xf000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);
@ -428,8 +428,8 @@ TYPED_TEST_P(DwarfEhFrameTest, GetCieFde64) {
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
EXPECT_EQ(0xd01cU, fde->pc_start);
EXPECT_EQ(0xd31cU, fde->pc_end);
EXPECT_EQ(0xd018U, fde->pc_start);
EXPECT_EQ(0xd318U, fde->pc_end);
EXPECT_EQ(0x6000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);

View File

@ -345,8 +345,8 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde32) {
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x14010U, fde->cfa_instructions_offset);
EXPECT_EQ(0x14024U, fde->cfa_instructions_end);
EXPECT_EQ(0x1d00cU, fde->pc_start);
EXPECT_EQ(0x1d10cU, fde->pc_end);
EXPECT_EQ(0x1d008U, fde->pc_start);
EXPECT_EQ(0x1d108U, fde->pc_end);
EXPECT_EQ(0xf000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);
@ -387,8 +387,8 @@ TYPED_TEST_P(DwarfEhFrameWithHdrTest, GetCieFde64) {
ASSERT_TRUE(fde != nullptr);
EXPECT_EQ(0x8024U, fde->cfa_instructions_offset);
EXPECT_EQ(0x820cU, fde->cfa_instructions_end);
EXPECT_EQ(0xd01cU, fde->pc_start);
EXPECT_EQ(0xd31cU, fde->pc_end);
EXPECT_EQ(0xd018U, fde->pc_start);
EXPECT_EQ(0xd318U, fde->pc_end);
EXPECT_EQ(0x6000U, fde->cie_offset);
EXPECT_EQ(0U, fde->lsda_address);

View File

@ -132,7 +132,7 @@ TEST_F(ElfTest, elf_invalid) {
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
bool finished;
ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
ASSERT_FALSE(elf.Step(0, 0, 0, nullptr, nullptr, &finished));
}
TEST_F(ElfTest, elf32_invalid_machine) {
@ -306,7 +306,7 @@ TEST_F(ElfTest, step_in_signal_map) {
elf.FakeSetValid(true);
elf.FakeSetLoadBias(0);
bool finished;
ASSERT_TRUE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
ASSERT_TRUE(elf.Step(0x1000, 0x1000, 0x2000, &regs, &process_memory, &finished));
EXPECT_FALSE(finished);
EXPECT_EQ(15U, regs.pc());
EXPECT_EQ(13U, regs.sp());
@ -339,7 +339,7 @@ TEST_F(ElfTest, step_in_interface) {
EXPECT_CALL(*interface, Step(0x1000, &regs, &process_memory, &finished))
.WillOnce(::testing::Return(true));
ASSERT_TRUE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
ASSERT_TRUE(elf.Step(0x1004, 0x1000, 0x2000, &regs, &process_memory, &finished));
}
TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
@ -355,12 +355,12 @@ TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
// Invalid relative pc given load_bias.
bool finished;
ASSERT_FALSE(elf.Step(0x1000, 0x2000, &regs, &process_memory, &finished));
ASSERT_FALSE(elf.Step(0x1004, 0x1000, 0x2000, &regs, &process_memory, &finished));
EXPECT_CALL(*interface, Step(0x3300, &regs, &process_memory, &finished))
.WillOnce(::testing::Return(true));
ASSERT_TRUE(elf.Step(0x7300, 0x2000, &regs, &process_memory, &finished));
ASSERT_TRUE(elf.Step(0x7304, 0x7300, 0x2000, &regs, &process_memory, &finished));
}
} // namespace unwindstack

View File

@ -47,7 +47,7 @@ void TestInitEhdr(Ehdr* ehdr, uint32_t elf_class, uint32_t machine_type) {
ehdr->e_ehsize = sizeof(Ehdr);
}
static std::string GetTestFileDirectory() {
std::string TestGetFileDirectory() {
std::string exec(testing::internal::GetArgvs()[0]);
auto const value = exec.find_last_of('/');
if (value == std::string::npos) {
@ -102,7 +102,7 @@ void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine, bool init_gnu_de
offset = symtab_offset + 0x100;
if (init_gnu_debugdata) {
// Read in the compressed elf data and copy it in.
name = GetTestFileDirectory();
name = TestGetFileDirectory();
if (elf_class == ELFCLASS32) {
name += "elf32.xz";
} else {

View File

@ -18,6 +18,7 @@
#define _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H
#include <functional>
#include <string>
namespace unwindstack {
@ -30,6 +31,8 @@ template <typename Ehdr, typename Shdr>
void TestInitGnuDebugdata(uint32_t elf_class, uint32_t machine_type, bool init_gnu_debudata,
TestCopyFuncType copy_func);
std::string TestGetFileDirectory();
} // namespace unwindstack
#endif // _LIBUNWINDSTACK_TESTS_ELF_TEST_UTILS_H

View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2017 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 <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <gtest/gtest.h>
#include <string>
#include <vector>
#include <unwindstack/Maps.h>
#include <unwindstack/Memory.h>
#include <unwindstack/Regs.h>
#include <unwindstack/Unwinder.h>
#include "Machine.h"
#include "ElfTestUtils.h"
namespace unwindstack {
static std::string DumpFrames(Unwinder& unwinder) {
std::string str;
for (size_t i = 0; i < unwinder.NumFrames(); i++) {
str += unwinder.FormatFrame(i) + "\n";
}
return str;
}
TEST(UnwindOfflineTest, pc_straddle_arm32) {
std::string dir(TestGetFileDirectory() + "offline/straddle_arm32/");
MemoryOffline* memory = new MemoryOffline;
ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
ASSERT_TRUE(fp != nullptr);
RegsArm regs;
uint64_t reg_value;
ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_PC] = reg_value;
ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_SP] = reg_value;
ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
regs[ARM_REG_LR] = reg_value;
regs.SetFromRaw();
fclose(fp);
fp = fopen((dir + "maps.txt").c_str(), "r");
ASSERT_TRUE(fp != nullptr);
// The file is guaranteed to be less than 4096 bytes.
std::vector<char> buffer(4096);
ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
fclose(fp);
BufferMaps maps(buffer.data());
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(static_cast<uint32_t>(EM_ARM), regs.MachineType());
std::shared_ptr<Memory> process_memory(memory);
char* cwd = getcwd(nullptr, 0);
ASSERT_EQ(0, chdir(dir.c_str()));
Unwinder unwinder(128, &maps, &regs, process_memory);
unwinder.Unwind();
ASSERT_EQ(0, chdir(cwd));
free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 0001a9f8 libc.so (abort+63)\n"
" #01 pc 00006a1b libbase.so (_ZN7android4base14DefaultAborterEPKc+6)\n"
" #02 pc 00007441 libbase.so (_ZN7android4base10LogMessageD2Ev+748)\n"
" #03 pc 00015149 /does/not/exist/libhidlbase.so\n",
frame_info);
}
TEST(UnwindOfflineTest, pc_straddle_arm64) {
std::string dir(TestGetFileDirectory() + "offline/straddle_arm64/");
MemoryOffline* memory = new MemoryOffline;
ASSERT_TRUE(memory->Init((dir + "stack.data").c_str(), 0));
FILE* fp = fopen((dir + "regs.txt").c_str(), "r");
ASSERT_TRUE(fp != nullptr);
RegsArm64 regs;
uint64_t reg_value;
ASSERT_EQ(1, fscanf(fp, "pc: %" SCNx64 "\n", &reg_value));
regs[ARM64_REG_PC] = reg_value;
ASSERT_EQ(1, fscanf(fp, "sp: %" SCNx64 "\n", &reg_value));
regs[ARM64_REG_SP] = reg_value;
ASSERT_EQ(1, fscanf(fp, "lr: %" SCNx64 "\n", &reg_value));
regs[ARM64_REG_LR] = reg_value;
ASSERT_EQ(1, fscanf(fp, "x29: %" SCNx64 "\n", &reg_value));
regs[ARM64_REG_R29] = reg_value;
regs.SetFromRaw();
fclose(fp);
fp = fopen((dir + "maps.txt").c_str(), "r");
ASSERT_TRUE(fp != nullptr);
// The file is guaranteed to be less than 4096 bytes.
std::vector<char> buffer(4096);
ASSERT_NE(0U, fread(buffer.data(), 1, buffer.size(), fp));
fclose(fp);
BufferMaps maps(buffer.data());
ASSERT_TRUE(maps.Parse());
ASSERT_EQ(static_cast<uint32_t>(EM_AARCH64), regs.MachineType());
std::shared_ptr<Memory> process_memory(memory);
char* cwd = getcwd(nullptr, 0);
ASSERT_EQ(0, chdir(dir.c_str()));
Unwinder unwinder(128, &maps, &regs, process_memory);
unwinder.Unwind();
ASSERT_EQ(0, chdir(cwd));
free(cwd);
std::string frame_info(DumpFrames(unwinder));
ASSERT_EQ(6U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
EXPECT_EQ(
" #00 pc 0000000000429fd8 libunwindstack_test (SignalInnerFunction+24)\n"
" #01 pc 000000000042a078 libunwindstack_test (SignalMiddleFunction+8)\n"
" #02 pc 000000000042a08c libunwindstack_test (SignalOuterFunction+8)\n"
" #03 pc 000000000042d8fc libunwindstack_test "
"(_ZN11unwindstackL19RemoteThroughSignalEij+20)\n"
" #04 pc 000000000042d8d8 libunwindstack_test "
"(_ZN11unwindstack37UnwindTest_remote_through_signal_Test8TestBodyEv+32)\n"
" #05 pc 0000000000455d70 libunwindstack_test (_ZN7testing4Test3RunEv+392)\n",
frame_info);
}
} // namespace unwindstack

View File

@ -0,0 +1,4 @@
f2d9a000-f2da7fff r-xp 00000000 00:00 0 libbase.so
f3002000-f3005fff rw-p 00000000 00:00 0 [stack:25941]
f31d0000-f326bfff r-xp 00000000 00:00 0 libc.so
f3352000-f336bfff r-xp 00000000 00:00 0 /does/not/exist/libhidlbase.so

View File

@ -0,0 +1,3 @@
pc: f31ea9f8
sp: e9c866f8
lr: f31f179f

View File

@ -0,0 +1,2 @@
00000064d05ab000-00000064d0a6cfff r-xp 00000000 00:00 0 libunwindstack_test
0000007fe0d64000-0000007fe0d84fff rw-p 00000000 00:00 0 [stack]

View File

@ -0,0 +1,4 @@
pc: 00000064d09d4fd8
sp: 0000007fe0d84040
lr: 00000064d09d507c
x29: 0000007fe0d84070