1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include <stdint.h> 18 19#include <gmock/gmock.h> 20#include <gtest/gtest.h> 21 22#include <unwindstack/DwarfSection.h> 23 24#include "MemoryFake.h" 25 26namespace unwindstack { 27 28class MockDwarfSection : public DwarfSection { 29 public: 30 MockDwarfSection(Memory* memory) : DwarfSection(memory) {} 31 virtual ~MockDwarfSection() = default; 32 33 MOCK_METHOD4(Log, bool(uint8_t, uint64_t, uint64_t, const DwarfFde*)); 34 35 MOCK_METHOD5(Eval, bool(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*)); 36 37 MOCK_METHOD3(GetCfaLocationInfo, bool(uint64_t, const DwarfFde*, dwarf_loc_regs_t*)); 38 39 MOCK_METHOD2(Init, bool(uint64_t, uint64_t)); 40 41 MOCK_METHOD2(GetFdeOffsetFromPc, bool(uint64_t, uint64_t*)); 42 43 MOCK_METHOD1(GetFdeFromOffset, const DwarfFde*(uint64_t)); 44 45 MOCK_METHOD1(GetFdeFromIndex, const DwarfFde*(size_t)); 46 47 MOCK_METHOD1(IsCie32, bool(uint32_t)); 48 49 MOCK_METHOD1(IsCie64, bool(uint64_t)); 50 51 MOCK_METHOD1(GetCieOffsetFromFde32, uint64_t(uint32_t)); 52 53 MOCK_METHOD1(GetCieOffsetFromFde64, uint64_t(uint64_t)); 54 55 MOCK_METHOD1(AdjustPcFromFde, uint64_t(uint64_t)); 56}; 57 58class DwarfSectionTest : public ::testing::Test { 59 protected: 60 MemoryFake memory_; 61}; 62 63TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_from_pc) { 64 MockDwarfSection mock_section(&memory_); 65 66 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 67 .WillOnce(::testing::Return(false)); 68 69 // Verify nullptr when GetFdeOffsetFromPc fails. 70 ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr); 71} 72 73TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_fail_fde_pc_end) { 74 MockDwarfSection mock_section(&memory_); 75 76 DwarfFde fde{}; 77 fde.pc_end = 0x500; 78 79 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 80 .WillOnce(::testing::Return(true)); 81 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); 82 83 // Verify nullptr when GetFdeOffsetFromPc fails. 84 ASSERT_TRUE(mock_section.GetFdeFromPc(0x1000) == nullptr); 85} 86 87TEST_F(DwarfSectionTest, GetFdeOffsetFromPc_pass) { 88 MockDwarfSection mock_section(&memory_); 89 90 DwarfFde fde{}; 91 fde.pc_end = 0x2000; 92 93 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 94 .WillOnce(::testing::Return(true)); 95 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); 96 97 // Verify nullptr when GetFdeOffsetFromPc fails. 98 ASSERT_EQ(&fde, mock_section.GetFdeFromPc(0x1000)); 99} 100 101TEST_F(DwarfSectionTest, Step_fail_fde) { 102 MockDwarfSection mock_section(&memory_); 103 104 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 105 .WillOnce(::testing::Return(false)); 106 107 bool finished; 108 ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished)); 109} 110 111TEST_F(DwarfSectionTest, Step_fail_cie_null) { 112 MockDwarfSection mock_section(&memory_); 113 114 DwarfFde fde{}; 115 fde.pc_end = 0x2000; 116 fde.cie = nullptr; 117 118 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 119 .WillOnce(::testing::Return(true)); 120 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); 121 122 bool finished; 123 ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished)); 124} 125 126TEST_F(DwarfSectionTest, Step_fail_cfa_location) { 127 MockDwarfSection mock_section(&memory_); 128 129 DwarfCie cie{}; 130 DwarfFde fde{}; 131 fde.pc_end = 0x2000; 132 fde.cie = &cie; 133 134 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 135 .WillOnce(::testing::Return(true)); 136 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); 137 138 EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) 139 .WillOnce(::testing::Return(false)); 140 141 bool finished; 142 ASSERT_FALSE(mock_section.Step(0x1000, nullptr, nullptr, &finished)); 143} 144 145TEST_F(DwarfSectionTest, Step_pass) { 146 MockDwarfSection mock_section(&memory_); 147 148 DwarfCie cie{}; 149 DwarfFde fde{}; 150 fde.pc_end = 0x2000; 151 fde.cie = &cie; 152 153 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 154 .WillOnce(::testing::Return(true)); 155 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); 156 157 EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) 158 .WillOnce(::testing::Return(true)); 159 160 MemoryFake process; 161 EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) 162 .WillOnce(::testing::Return(true)); 163 164 bool finished; 165 ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished)); 166} 167 168static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde, 169 dwarf_loc_regs_t* loc_regs) { 170 loc_regs->pc_start = fde->pc_start; 171 loc_regs->pc_end = fde->pc_end; 172 return true; 173} 174 175TEST_F(DwarfSectionTest, Step_cache) { 176 MockDwarfSection mock_section(&memory_); 177 178 DwarfCie cie{}; 179 DwarfFde fde{}; 180 fde.pc_start = 0x500; 181 fde.pc_end = 0x2000; 182 fde.cie = &cie; 183 184 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 185 .WillOnce(::testing::Return(true)); 186 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde)); 187 188 EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) 189 .WillOnce(::testing::Invoke(MockGetCfaLocationInfo)); 190 191 MemoryFake process; 192 EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) 193 .WillRepeatedly(::testing::Return(true)); 194 195 bool finished; 196 ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished)); 197 ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished)); 198 ASSERT_TRUE(mock_section.Step(0x1500, nullptr, &process, &finished)); 199} 200 201TEST_F(DwarfSectionTest, Step_cache_not_in_pc) { 202 MockDwarfSection mock_section(&memory_); 203 204 DwarfCie cie{}; 205 DwarfFde fde0{}; 206 fde0.pc_start = 0x1000; 207 fde0.pc_end = 0x2000; 208 fde0.cie = &cie; 209 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x1000, ::testing::_)) 210 .WillOnce(::testing::Return(true)); 211 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde0)); 212 EXPECT_CALL(mock_section, GetCfaLocationInfo(0x1000, &fde0, ::testing::_)) 213 .WillOnce(::testing::Invoke(MockGetCfaLocationInfo)); 214 215 MemoryFake process; 216 EXPECT_CALL(mock_section, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) 217 .WillRepeatedly(::testing::Return(true)); 218 219 bool finished; 220 ASSERT_TRUE(mock_section.Step(0x1000, nullptr, &process, &finished)); 221 222 DwarfFde fde1{}; 223 fde1.pc_start = 0x500; 224 fde1.pc_end = 0x800; 225 fde1.cie = &cie; 226 EXPECT_CALL(mock_section, GetFdeOffsetFromPc(0x600, ::testing::_)) 227 .WillOnce(::testing::Return(true)); 228 EXPECT_CALL(mock_section, GetFdeFromOffset(::testing::_)).WillOnce(::testing::Return(&fde1)); 229 EXPECT_CALL(mock_section, GetCfaLocationInfo(0x600, &fde1, ::testing::_)) 230 .WillOnce(::testing::Invoke(MockGetCfaLocationInfo)); 231 232 ASSERT_TRUE(mock_section.Step(0x600, nullptr, &process, &finished)); 233 ASSERT_TRUE(mock_section.Step(0x700, nullptr, &process, &finished)); 234} 235 236} // namespace unwindstack 237