Fix bug when doing signal handler lookup.
The new lld linker uses all non-zero offset executable maps. There was a bug when trying to find if the stack is in a signal handler that caused the code to read the wrong place in the elf. Fixed by not adding the elf offset to the relative pc. Also fixed the unwind_for_offline tool to dump multiple stacks if necessary. Added new offline unit test that would have failed with the old code. Bug: 79936827 Test: Ran unit tests and libbacktrace unit tests. Test: Dumped backtraces of system pids. Test: Ran 137-cfi art test. Change-Id: Iaca8c18c2a314902e64c3f72831234297e8dcb1b
This commit is contained in:
parent
3464bc4b43
commit
239425b9fa
|
@ -202,6 +202,7 @@ cc_test {
|
|||
"tests/files/offline/jit_debug_x86/*",
|
||||
"tests/files/offline/jit_map_arm/*",
|
||||
"tests/files/offline/gnu_debugdata_arm/*",
|
||||
"tests/files/offline/offset_arm/*",
|
||||
"tests/files/offline/straddle_arm/*",
|
||||
"tests/files/offline/straddle_arm64/*",
|
||||
],
|
||||
|
|
|
@ -160,14 +160,14 @@ uint64_t Elf::GetLastErrorAddress() {
|
|||
}
|
||||
|
||||
// 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 adjusted_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, Regs* regs, Memory* process_memory,
|
||||
bool* finished) {
|
||||
if (!valid_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The relative pc expectd by StepIfSignalHandler is relative to the start of the elf.
|
||||
if (regs->StepIfSignalHandler(rel_pc + elf_offset, this, process_memory)) {
|
||||
if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) {
|
||||
*finished = false;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -220,8 +220,7 @@ 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, step_pc, map_info->elf_offset, regs_, process_memory_.get(),
|
||||
&finished);
|
||||
stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished);
|
||||
elf->GetLastError(&last_error_);
|
||||
if (stepped && finished) {
|
||||
break;
|
||||
|
|
|
@ -65,8 +65,8 @@ class Elf {
|
|||
|
||||
uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info);
|
||||
|
||||
bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, uint64_t elf_offset, Regs* regs,
|
||||
Memory* process_memory, bool* finished);
|
||||
bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory,
|
||||
bool* finished);
|
||||
|
||||
ElfInterface* CreateInterfaceFromMemory(Memory* memory);
|
||||
|
||||
|
|
|
@ -133,7 +133,7 @@ TEST_F(ElfTest, elf_invalid) {
|
|||
ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset));
|
||||
|
||||
bool finished;
|
||||
ASSERT_FALSE(elf.Step(0, 0, 0, nullptr, nullptr, &finished));
|
||||
ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, elf32_invalid_machine) {
|
||||
|
@ -330,7 +330,7 @@ TEST_F(ElfTest, step_in_signal_map) {
|
|||
elf.FakeSetValid(true);
|
||||
elf.FakeSetLoadBias(0);
|
||||
bool finished;
|
||||
ASSERT_TRUE(elf.Step(0x1000, 0x1000, 0x2000, ®s, &process_memory, &finished));
|
||||
ASSERT_TRUE(elf.Step(0x3000, 0x1000, ®s, &process_memory, &finished));
|
||||
EXPECT_FALSE(finished);
|
||||
EXPECT_EQ(15U, regs.pc());
|
||||
EXPECT_EQ(13U, regs.sp());
|
||||
|
@ -370,7 +370,7 @@ TEST_F(ElfTest, step_in_interface) {
|
|||
EXPECT_CALL(*interface, Step(0x1000, 0, ®s, &process_memory, &finished))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x1004, 0x1000, 0x2000, ®s, &process_memory, &finished));
|
||||
ASSERT_TRUE(elf.Step(0x1004, 0x1000, ®s, &process_memory, &finished));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
|
||||
|
@ -388,7 +388,7 @@ TEST_F(ElfTest, step_in_interface_non_zero_load_bias) {
|
|||
EXPECT_CALL(*interface, Step(0x7300, 0x4000, ®s, &process_memory, &finished))
|
||||
.WillOnce(::testing::Return(true));
|
||||
|
||||
ASSERT_TRUE(elf.Step(0x7304, 0x7300, 0x2000, ®s, &process_memory, &finished));
|
||||
ASSERT_TRUE(elf.Step(0x7304, 0x7300, ®s, &process_memory, &finished));
|
||||
}
|
||||
|
||||
TEST_F(ElfTest, get_global_invalid_elf) {
|
||||
|
|
|
@ -46,6 +46,12 @@
|
|||
|
||||
namespace unwindstack {
|
||||
|
||||
static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
|
||||
MemoryOffline* memory = new MemoryOffline;
|
||||
ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
|
||||
parts->Add(memory);
|
||||
}
|
||||
|
||||
class UnwindOfflineTest : public ::testing::Test {
|
||||
protected:
|
||||
void TearDown() override {
|
||||
|
@ -64,9 +70,24 @@ class UnwindOfflineTest : public ::testing::Test {
|
|||
maps_.reset(new BufferMaps(data.c_str()));
|
||||
ASSERT_TRUE(maps_->Parse());
|
||||
|
||||
std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
|
||||
ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
|
||||
process_memory_.reset(stack_memory.release());
|
||||
std::string stack_name(dir_ + "stack.data");
|
||||
struct stat st;
|
||||
if (stat(stack_name.c_str(), &st) == 0 && S_ISREG(st.st_mode)) {
|
||||
std::unique_ptr<MemoryOffline> stack_memory(new MemoryOffline);
|
||||
ASSERT_TRUE(stack_memory->Init((dir_ + "stack.data").c_str(), 0));
|
||||
process_memory_.reset(stack_memory.release());
|
||||
} else {
|
||||
std::unique_ptr<MemoryOfflineParts> stack_memory(new MemoryOfflineParts);
|
||||
for (size_t i = 0;; i++) {
|
||||
stack_name = dir_ + "stack" + std::to_string(i) + ".data";
|
||||
if (stat(stack_name.c_str(), &st) == -1 || !S_ISREG(st.st_mode)) {
|
||||
ASSERT_TRUE(i != 0) << "No stack data files found.";
|
||||
break;
|
||||
}
|
||||
AddMemory(stack_name, stack_memory.get());
|
||||
}
|
||||
process_memory_.reset(stack_memory.release());
|
||||
}
|
||||
|
||||
switch (arch) {
|
||||
case ARCH_ARM: {
|
||||
|
@ -180,7 +201,7 @@ static std::string DumpFrames(Unwinder& unwinder) {
|
|||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, pc_straddle_arm) {
|
||||
Init("straddle_arm/", ARCH_ARM);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
@ -204,7 +225,7 @@ TEST_F(UnwindOfflineTest, pc_straddle_arm) {
|
|||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
|
||||
Init("gnu_debugdata_arm/", ARCH_ARM);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("gnu_debugdata_arm/", ARCH_ARM));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
@ -224,7 +245,7 @@ TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) {
|
|||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
|
||||
Init("straddle_arm64/", ARCH_ARM64);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("straddle_arm64/", ARCH_ARM64));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
@ -255,14 +276,8 @@ TEST_F(UnwindOfflineTest, pc_straddle_arm64) {
|
|||
EXPECT_EQ(0x7fe0d84110U, unwinder.frames()[5].sp);
|
||||
}
|
||||
|
||||
static void AddMemory(std::string file_name, MemoryOfflineParts* parts) {
|
||||
MemoryOffline* memory = new MemoryOffline;
|
||||
ASSERT_TRUE(memory->Init(file_name.c_str(), 0));
|
||||
parts->Add(memory);
|
||||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, jit_debug_x86) {
|
||||
Init("jit_debug_x86/", ARCH_X86);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("jit_debug_x86/", ARCH_X86));
|
||||
|
||||
MemoryOfflineParts* memory = new MemoryOfflineParts;
|
||||
AddMemory(dir_ + "descriptor.data", memory);
|
||||
|
@ -555,7 +570,7 @@ TEST_F(UnwindOfflineTest, jit_debug_x86) {
|
|||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, jit_debug_arm) {
|
||||
Init("jit_debug_arm/", ARCH_ARM);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("jit_debug_arm/", ARCH_ARM));
|
||||
|
||||
MemoryOfflineParts* memory = new MemoryOfflineParts;
|
||||
AddMemory(dir_ + "descriptor.data", memory);
|
||||
|
@ -873,7 +888,7 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) {
|
|||
// fallback to iterating over the cies/fdes and ignore the eh_frame_hdr.
|
||||
// No .gnu_debugdata section in the elf file, so no symbols.
|
||||
TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
|
||||
Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("bad_eh_frame_hdr_arm64/", ARCH_ARM64));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
@ -902,7 +917,7 @@ TEST_F(UnwindOfflineTest, bad_eh_frame_hdr_arm64) {
|
|||
// The elf has bad eh_frame unwind information for the pcs. If eh_frame
|
||||
// is used first, the unwind will not match the expected output.
|
||||
TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
|
||||
Init("debug_frame_first_x86/", ARCH_X86);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("debug_frame_first_x86/", ARCH_X86));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
@ -930,7 +945,7 @@ TEST_F(UnwindOfflineTest, debug_frame_first_x86) {
|
|||
|
||||
// Make sure that a pc that is at the beginning of an fde unwinds correctly.
|
||||
TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
|
||||
Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("eh_frame_hdr_begin_x86_64/", ARCH_X86_64));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
@ -957,7 +972,7 @@ TEST_F(UnwindOfflineTest, eh_frame_hdr_begin_x86_64) {
|
|||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
|
||||
Init("art_quick_osr_stub_arm/", ARCH_ARM);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("art_quick_osr_stub_arm/", ARCH_ARM));
|
||||
|
||||
MemoryOfflineParts* memory = new MemoryOfflineParts;
|
||||
AddMemory(dir_ + "descriptor.data", memory);
|
||||
|
@ -1072,7 +1087,7 @@ TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) {
|
|||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, jit_map_arm) {
|
||||
Init("jit_map_arm/", ARCH_ARM);
|
||||
ASSERT_NO_FATAL_FAILURE(Init("jit_map_arm/", ARCH_ARM));
|
||||
|
||||
maps_->Add(0xd025c788, 0xd025c9f0, 0, PROT_READ | PROT_EXEC | MAPS_FLAGS_JIT_SYMFILE_MAP,
|
||||
"jit_map0.so", 0);
|
||||
|
@ -1111,4 +1126,78 @@ TEST_F(UnwindOfflineTest, jit_map_arm) {
|
|||
EXPECT_EQ(0xcd4ff960U, unwinder.frames()[5].sp);
|
||||
}
|
||||
|
||||
TEST_F(UnwindOfflineTest, offset_arm) {
|
||||
ASSERT_NO_FATAL_FAILURE(Init("offset_arm/", ARCH_ARM));
|
||||
|
||||
Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_);
|
||||
unwinder.Unwind();
|
||||
|
||||
std::string frame_info(DumpFrames(unwinder));
|
||||
ASSERT_EQ(19U, unwinder.NumFrames()) << "Unwind:\n" << frame_info;
|
||||
EXPECT_EQ(
|
||||
" #00 pc 0032bfa0 (offset 0x42000) libunwindstack_test (SignalInnerFunction+40)\n"
|
||||
" #01 pc 0032bfeb (offset 0x42000) libunwindstack_test (SignalMiddleFunction+2)\n"
|
||||
" #02 pc 0032bff3 (offset 0x42000) libunwindstack_test (SignalOuterFunction+2)\n"
|
||||
" #03 pc 0032fed3 (offset 0x42000) libunwindstack_test "
|
||||
"(_ZN11unwindstackL19SignalCallerHandlerEiP7siginfoPv+26)\n"
|
||||
" #04 pc 00026528 (offset 0x25000) libc.so\n"
|
||||
" #05 pc 00000000 <unknown>\n"
|
||||
" #06 pc 0032c2d9 (offset 0x42000) libunwindstack_test (InnerFunction+736)\n"
|
||||
" #07 pc 0032cc4f (offset 0x42000) libunwindstack_test (MiddleFunction+42)\n"
|
||||
" #08 pc 0032cc81 (offset 0x42000) libunwindstack_test (OuterFunction+42)\n"
|
||||
" #09 pc 0032e547 (offset 0x42000) libunwindstack_test "
|
||||
"(_ZN11unwindstackL19RemoteThroughSignalEij+270)\n"
|
||||
" #10 pc 0032ed99 (offset 0x42000) libunwindstack_test "
|
||||
"(_ZN11unwindstack55UnwindTest_remote_through_signal_with_invalid_func_Test8TestBodyEv+16)\n"
|
||||
" #11 pc 00354453 (offset 0x42000) libunwindstack_test (_ZN7testing4Test3RunEv+154)\n"
|
||||
" #12 pc 00354de7 (offset 0x42000) libunwindstack_test (_ZN7testing8TestInfo3RunEv+194)\n"
|
||||
" #13 pc 00355105 (offset 0x42000) libunwindstack_test (_ZN7testing8TestCase3RunEv+180)\n"
|
||||
" #14 pc 0035a215 (offset 0x42000) libunwindstack_test "
|
||||
"(_ZN7testing8internal12UnitTestImpl11RunAllTestsEv+664)\n"
|
||||
" #15 pc 00359f4f (offset 0x42000) libunwindstack_test (_ZN7testing8UnitTest3RunEv+110)\n"
|
||||
" #16 pc 0034d3db (offset 0x42000) libunwindstack_test (main+38)\n"
|
||||
" #17 pc 00092c0d (offset 0x25000) libc.so (__libc_init+48)\n"
|
||||
" #18 pc 0004202f (offset 0x42000) libunwindstack_test (_start_main+38)\n",
|
||||
frame_info);
|
||||
|
||||
EXPECT_EQ(0x2e55fa0U, unwinder.frames()[0].pc);
|
||||
EXPECT_EQ(0xf43d2cccU, unwinder.frames()[0].sp);
|
||||
EXPECT_EQ(0x2e55febU, unwinder.frames()[1].pc);
|
||||
EXPECT_EQ(0xf43d2ce0U, unwinder.frames()[1].sp);
|
||||
EXPECT_EQ(0x2e55ff3U, unwinder.frames()[2].pc);
|
||||
EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp);
|
||||
EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc);
|
||||
EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp);
|
||||
EXPECT_EQ(0xf4136528U, unwinder.frames()[4].pc);
|
||||
EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp);
|
||||
EXPECT_EQ(0U, unwinder.frames()[5].pc);
|
||||
EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp);
|
||||
EXPECT_EQ(0x2e562d9U, unwinder.frames()[6].pc);
|
||||
EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[6].sp);
|
||||
EXPECT_EQ(0x2e56c4fU, unwinder.frames()[7].pc);
|
||||
EXPECT_EQ(0xffcc1060U, unwinder.frames()[7].sp);
|
||||
EXPECT_EQ(0x2e56c81U, unwinder.frames()[8].pc);
|
||||
EXPECT_EQ(0xffcc1078U, unwinder.frames()[8].sp);
|
||||
EXPECT_EQ(0x2e58547U, unwinder.frames()[9].pc);
|
||||
EXPECT_EQ(0xffcc1090U, unwinder.frames()[9].sp);
|
||||
EXPECT_EQ(0x2e58d99U, unwinder.frames()[10].pc);
|
||||
EXPECT_EQ(0xffcc1438U, unwinder.frames()[10].sp);
|
||||
EXPECT_EQ(0x2e7e453U, unwinder.frames()[11].pc);
|
||||
EXPECT_EQ(0xffcc1448U, unwinder.frames()[11].sp);
|
||||
EXPECT_EQ(0x2e7ede7U, unwinder.frames()[12].pc);
|
||||
EXPECT_EQ(0xffcc1458U, unwinder.frames()[12].sp);
|
||||
EXPECT_EQ(0x2e7f105U, unwinder.frames()[13].pc);
|
||||
EXPECT_EQ(0xffcc1490U, unwinder.frames()[13].sp);
|
||||
EXPECT_EQ(0x2e84215U, unwinder.frames()[14].pc);
|
||||
EXPECT_EQ(0xffcc14c0U, unwinder.frames()[14].sp);
|
||||
EXPECT_EQ(0x2e83f4fU, unwinder.frames()[15].pc);
|
||||
EXPECT_EQ(0xffcc1510U, unwinder.frames()[15].sp);
|
||||
EXPECT_EQ(0x2e773dbU, unwinder.frames()[16].pc);
|
||||
EXPECT_EQ(0xffcc1528U, unwinder.frames()[16].sp);
|
||||
EXPECT_EQ(0xf41a2c0dU, unwinder.frames()[17].pc);
|
||||
EXPECT_EQ(0xffcc1540U, unwinder.frames()[17].sp);
|
||||
EXPECT_EQ(0x2b6c02fU, unwinder.frames()[18].pc);
|
||||
EXPECT_EQ(0xffcc1558U, unwinder.frames()[18].sp);
|
||||
}
|
||||
|
||||
} // namespace unwindstack
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,2 @@
|
|||
2b6c000-2e92000 r-xp 42000 00:00 0 libunwindstack_test
|
||||
f4135000-f41a9000 r-xp 25000 00:00 0 libc.so
|
|
@ -0,0 +1,16 @@
|
|||
r0: 5
|
||||
r1: 5
|
||||
r2: 4
|
||||
r3: 1
|
||||
r4: 73804b6b
|
||||
r5: f3c9c000
|
||||
r6: 2ea09ac
|
||||
r7: 10624dd3
|
||||
r8: f41b5d8c
|
||||
r9: f3c9c000
|
||||
r10: 6f17
|
||||
r11: f3c94048
|
||||
ip: 2ea0807
|
||||
sp: f43d2ccc
|
||||
lr: 2e55fef
|
||||
pc: 2e55fa0
|
Binary file not shown.
Binary file not shown.
|
@ -30,6 +30,7 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <unwindstack/Elf.h>
|
||||
|
@ -78,30 +79,44 @@ bool SaveRegs(unwindstack::Regs* regs) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool SaveStack(pid_t pid, uint64_t sp_start, uint64_t sp_end) {
|
||||
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen("stack.data", "w+"), &fclose);
|
||||
if (fp == nullptr) {
|
||||
printf("Failed to create stack.data.\n");
|
||||
return false;
|
||||
}
|
||||
bool SaveStack(pid_t pid, const std::vector<std::pair<uint64_t, uint64_t>>& stacks) {
|
||||
for (size_t i = 0; i < stacks.size(); i++) {
|
||||
std::string file_name;
|
||||
if (stacks.size() != 1) {
|
||||
file_name = "stack" + std::to_string(i) + ".data";
|
||||
} else {
|
||||
file_name = "stack.data";
|
||||
}
|
||||
|
||||
size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
|
||||
if (bytes != sizeof(sp_start)) {
|
||||
perror("Failed to write all data.");
|
||||
return false;
|
||||
}
|
||||
// Do this first, so if it fails, we don't create the file.
|
||||
uint64_t sp_start = stacks[i].first;
|
||||
uint64_t sp_end = stacks[i].second;
|
||||
std::vector<uint8_t> buffer(sp_end - sp_start);
|
||||
auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
|
||||
if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
|
||||
printf("Unable to read stack data.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> buffer(sp_end - sp_start);
|
||||
auto process_memory = unwindstack::Memory::CreateProcessMemory(pid);
|
||||
if (!process_memory->Read(sp_start, buffer.data(), buffer.size())) {
|
||||
printf("Unable to read stack data.\n");
|
||||
return false;
|
||||
}
|
||||
printf("Saving the stack 0x%" PRIx64 "-0x%" PRIx64 "\n", sp_start, sp_end);
|
||||
|
||||
bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
|
||||
if (bytes != buffer.size()) {
|
||||
printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
|
||||
return 1;
|
||||
std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(file_name.c_str(), "w+"), &fclose);
|
||||
if (fp == nullptr) {
|
||||
printf("Failed to create stack.data.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t bytes = fwrite(&sp_start, 1, sizeof(sp_start), fp.get());
|
||||
if (bytes != sizeof(sp_start)) {
|
||||
perror("Failed to write all data.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes = fwrite(buffer.data(), 1, buffer.size(), fp.get());
|
||||
if (bytes != buffer.size()) {
|
||||
printf("Failed to write all stack data: stack size %zu, written %zu\n", buffer.size(), bytes);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -110,17 +125,11 @@ bool SaveStack(pid_t pid, uint64_t sp_start, uint64_t sp_end) {
|
|||
bool CreateElfFromMemory(std::shared_ptr<unwindstack::Memory>& memory, map_info_t* info) {
|
||||
std::string cur_name;
|
||||
if (info->name.empty()) {
|
||||
cur_name = android::base::StringPrintf("anonymous:%" PRIx64, info->start);
|
||||
cur_name = android::base::StringPrintf("anonymous_%" PRIx64, info->start);
|
||||
} else {
|
||||
cur_name = basename(info->name.c_str());
|
||||
cur_name = android::base::StringPrintf("%s:%" PRIx64, basename(info->name.c_str()), info->start);
|
||||
cur_name = android::base::StringPrintf("%s_%" PRIx64, basename(info->name.c_str()), info->start);
|
||||
}
|
||||
|
||||
std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
|
||||
if (output == nullptr) {
|
||||
printf("Cannot create %s\n", cur_name.c_str());
|
||||
return false;
|
||||
}
|
||||
std::vector<uint8_t> buffer(info->end - info->start);
|
||||
// If this is a mapped in file, it might not be possible to read the entire
|
||||
// map, so read all that is readable.
|
||||
|
@ -129,6 +138,13 @@ bool CreateElfFromMemory(std::shared_ptr<unwindstack::Memory>& memory, map_info_
|
|||
printf("Cannot read data from address %" PRIx64 " length %zu\n", info->start, buffer.size());
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<FILE, decltype(&fclose)> output(fopen(cur_name.c_str(), "w+"), &fclose);
|
||||
if (output == nullptr) {
|
||||
printf("Cannot create %s\n", cur_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t bytes_written = fwrite(buffer.data(), 1, bytes, output.get());
|
||||
if (bytes_written != bytes) {
|
||||
printf("Failed to write all data to file: bytes read %zu, written %zu\n", bytes, bytes_written);
|
||||
|
@ -198,9 +214,21 @@ int SaveData(pid_t pid) {
|
|||
unwinder.Unwind();
|
||||
|
||||
std::unordered_map<uint64_t, map_info_t> maps_by_start;
|
||||
uint64_t last_sp;
|
||||
std::vector<std::pair<uint64_t, uint64_t>> stacks;
|
||||
uint64_t sp_map_start = 0;
|
||||
unwindstack::MapInfo* map_info = maps.Find(sp);
|
||||
if (map_info != nullptr) {
|
||||
stacks.emplace_back(std::make_pair(sp, map_info->end));
|
||||
sp_map_start = map_info->start;
|
||||
}
|
||||
|
||||
for (auto frame : unwinder.frames()) {
|
||||
last_sp = frame.sp;
|
||||
map_info = maps.Find(frame.sp);
|
||||
if (map_info != nullptr && sp_map_start != map_info->start) {
|
||||
stacks.emplace_back(std::make_pair(frame.sp, map_info->end));
|
||||
sp_map_start = map_info->start;
|
||||
}
|
||||
|
||||
if (maps_by_start.count(frame.map_start) == 0) {
|
||||
auto info = &maps_by_start[frame.map_start];
|
||||
info->start = frame.map_start;
|
||||
|
@ -211,7 +239,12 @@ int SaveData(pid_t pid) {
|
|||
// Try to create the elf from memory, this will handle cases where
|
||||
// the data only exists in memory such as vdso data on x86.
|
||||
if (!CreateElfFromMemory(process_memory, info)) {
|
||||
return 1;
|
||||
printf("Ignoring map ");
|
||||
if (!info->name.empty()) {
|
||||
printf("%s\n", info->name.c_str());
|
||||
} else {
|
||||
printf("anonymous:%" PRIx64 "\n", info->start);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -221,7 +254,7 @@ int SaveData(pid_t pid) {
|
|||
printf("%s\n", unwinder.FormatFrame(i).c_str());
|
||||
}
|
||||
|
||||
if (!SaveStack(pid, sp, last_sp)) {
|
||||
if (!SaveStack(pid, stacks)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue