From e762f1f193bbaff746bcbe4e4efdad9b3ebfeb26 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Tue, 6 Feb 2018 14:51:48 -0800 Subject: [PATCH] Check that dex pc is in a valid map. Add new unit tests for dex pc being non-zero. Bug: 73004673 Test: Ran unit tests. Test: Ran art 137-cfi test on host for interpreter. Change-Id: I09bbf96d0ed65fc1e5896e4ab2bc67867e3b7fdb --- libunwindstack/Unwinder.cpp | 19 ++-- libunwindstack/include/unwindstack/Unwinder.h | 12 +-- libunwindstack/tests/RegsFake.h | 1 + libunwindstack/tests/UnwinderTest.cpp | 86 +++++++++++++++++++ 4 files changed, 105 insertions(+), 13 deletions(-) diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 6119ee0fc..644bfa8d2 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -54,13 +54,18 @@ void Unwinder::FillInDexFrame() { frame->sp = regs_->sp(); MapInfo* info = maps_->Find(dex_pc); - frame->map_start = info->start; - frame->map_end = info->end; - frame->map_offset = info->offset; - frame->map_load_bias = info->load_bias; - frame->map_flags = info->flags; - frame->map_name = info->name; - frame->rel_pc = dex_pc - info->start; + if (info != nullptr) { + frame->map_start = info->start; + frame->map_end = info->end; + frame->map_offset = info->offset; + frame->map_load_bias = info->load_bias; + frame->map_flags = info->flags; + frame->map_name = info->name; + frame->rel_pc = dex_pc - info->start; + } else { + frame->rel_pc = dex_pc; + return; + } #if !defined(NO_LIBDEXFILE_SUPPORT) if (dex_files_ == nullptr) { diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index e8af8b437..ebe7b0a5d 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -45,14 +45,14 @@ struct FrameData { uint64_t sp; std::string function_name; - uint64_t function_offset; + uint64_t function_offset = 0; std::string map_name; - uint64_t map_offset; - uint64_t map_start; - uint64_t map_end; - uint64_t map_load_bias; - int map_flags; + uint64_t map_offset = 0; + uint64_t map_start = 0; + uint64_t map_end = 0; + uint64_t map_load_bias = 0; + int map_flags = 0; }; class Unwinder { diff --git a/libunwindstack/tests/RegsFake.h b/libunwindstack/tests/RegsFake.h index 8f7d91349..cd7f2ff2b 100644 --- a/libunwindstack/tests/RegsFake.h +++ b/libunwindstack/tests/RegsFake.h @@ -56,6 +56,7 @@ class RegsFake : public Regs { void FakeSetArch(ArchEnum arch) { fake_arch_ = arch; } void FakeSetPc(uint64_t pc) { fake_pc_ = pc; } void FakeSetSp(uint64_t sp) { fake_sp_ = sp; } + void FakeSetDexPc(uint64_t dex_pc) { dex_pc_ = dex_pc; } void FakeSetReturnAddress(uint64_t return_address) { fake_return_address_ = return_address; } void FakeSetReturnAddressValid(bool valid) { fake_return_address_valid_ = valid; } diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index 45cf9074d..09c6e047d 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -98,6 +98,10 @@ class UnwinderTest : public ::testing::Test { info = new MapInfo(0x53000, 0x54000, 0, PROT_READ | PROT_WRITE, "/fake/fake.oat"); maps_.FakeAddMapInfo(info); + info = new MapInfo(0xa3000, 0xa4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/fake.vdex"); + info->load_bias = 0; + maps_.FakeAddMapInfo(info); + process_memory_.reset(new MemoryFake); } @@ -666,6 +670,88 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); } +TEST_F(UnwinderTest, dex_pc_in_map) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + regs_.FakeSetPc(0x1000); + regs_.FakeSetSp(0x10000); + regs_.FakeSetDexPc(0xa3400); + + Unwinder unwinder(64, &maps_, ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + + ASSERT_EQ(2U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x400U, frame->rel_pc); + EXPECT_EQ(0xa3400U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/fake/fake.vdex", frame->map_name); + EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0xa3000U, frame->map_start); + EXPECT_EQ(0xa4000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); + + frame = &unwinder.frames()[1]; + EXPECT_EQ(1U, frame->num); + EXPECT_EQ(0U, frame->rel_pc); + EXPECT_EQ(0x1000U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/system/fake/libc.so", frame->map_name); + EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0x1000U, frame->map_start); + EXPECT_EQ(0x8000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); +} + +TEST_F(UnwinderTest, dex_pc_not_in_map) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + regs_.FakeSetPc(0x1000); + regs_.FakeSetSp(0x10000); + regs_.FakeSetDexPc(0x50000); + + Unwinder unwinder(64, &maps_, ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + + ASSERT_EQ(2U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x50000U, frame->rel_pc); + EXPECT_EQ(0x50000U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("", frame->map_name); + EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0U, frame->map_start); + EXPECT_EQ(0U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(0, frame->map_flags); + + frame = &unwinder.frames()[1]; + EXPECT_EQ(1U, frame->num); + EXPECT_EQ(0U, frame->rel_pc); + EXPECT_EQ(0x1000U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/system/fake/libc.so", frame->map_name); + EXPECT_EQ(0U, frame->map_offset); + EXPECT_EQ(0x1000U, frame->map_start); + EXPECT_EQ(0x8000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE, frame->map_flags); +} + // Verify format frame code. TEST_F(UnwinderTest, format_frame_static) { FrameData frame;