From e4df5f5ab50939d4a36aa6c8076c7aa571fb56df Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 12 Feb 2018 13:24:18 -0800 Subject: [PATCH] Fix computation of pc. Fix the case where a non-zero load bias or a non-zero elf offset causes the pc to be set incorrectly. Add unit tests for these cases. Bug: 73172903 Test: Ran unit tests. Test: Ran the unit tests from the simpleperf CL that detected the failure. Change-Id: Id8802c00b34c66875edd4926a20c5fccd2bb7d72 --- libunwindstack/Unwinder.cpp | 2 +- libunwindstack/tests/UnwinderTest.cpp | 72 +++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index dfd7b185c..5e3293325 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -91,7 +91,7 @@ void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t adjusted_rel_pc return; } - frame->pc = map_info->start + adjusted_rel_pc; + frame->pc = map_info->start + adjusted_rel_pc - elf->GetLoadBias() - map_info->elf_offset; frame->map_name = map_info->name; frame->map_offset = map_info->offset; frame->map_start = map_info->start; diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index 7358ae607..7fbae4cf8 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -102,6 +102,22 @@ class UnwinderTest : public ::testing::Test { info->load_bias = 0; maps_.FakeAddMapInfo(info); + info = new MapInfo(0xa5000, 0xa6000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/fake/fake_load_bias.so"); + elf = new ElfFake(new MemoryFake); + info->elf.reset(elf); + elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + elf->FakeSetLoadBias(0x5000); + maps_.FakeAddMapInfo(info); + + info = new MapInfo(0xa7000, 0xa8000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, + "/fake/fake_offset.oat"); + elf = new ElfFake(new MemoryFake); + info->elf.reset(elf); + elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + info->elf_offset = 0x8000; + maps_.FakeAddMapInfo(info); + process_memory_.reset(new MemoryFake); } @@ -180,6 +196,62 @@ TEST_F(UnwinderTest, multiple_frames) { EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); } +TEST_F(UnwinderTest, non_zero_load_bias) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + + regs_.FakeSetPc(0xa5500); + regs_.FakeSetSp(0x10000); + ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); + + Unwinder unwinder(64, &maps_, ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + + ASSERT_EQ(1U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x5500U, frame->rel_pc); + EXPECT_EQ(0xa5500U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/fake/fake_load_bias.so", frame->map_name); + EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0xa5000U, frame->map_start); + EXPECT_EQ(0xa6000U, frame->map_end); + EXPECT_EQ(0x5000U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); +} + +TEST_F(UnwinderTest, non_zero_elf_offset) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + + regs_.FakeSetPc(0xa7500); + regs_.FakeSetSp(0x10000); + ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); + + Unwinder unwinder(64, &maps_, ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + + ASSERT_EQ(1U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x8500U, frame->rel_pc); + EXPECT_EQ(0xa7500U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/fake/fake_offset.oat", frame->map_name); + EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0xa7000U, frame->map_start); + EXPECT_EQ(0xa8000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); +} + TEST_F(UnwinderTest, non_zero_map_offset) { ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0));