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 #include <unwindstack/Elf.h>
24 
25 #include "MemoryFake.h"
26 #include "RegsFake.h"
27 
28 namespace unwindstack {
29 
30 class MockDwarfSection : public DwarfSection {
31  public:
MockDwarfSection(Memory * memory)32   MockDwarfSection(Memory* memory) : DwarfSection(memory) {}
33   virtual ~MockDwarfSection() = default;
34 
35   MOCK_METHOD(bool, Init, (uint64_t, uint64_t, int64_t), (override));
36 
37   MOCK_METHOD(bool, Eval, (const DwarfCie*, Memory*, const DwarfLocations&, Regs*, bool*),
38               (override));
39 
40   MOCK_METHOD(bool, Log, (uint8_t, uint64_t, const DwarfFde*, ArchEnum arch), (override));
41 
42   MOCK_METHOD(void, GetFdes, (std::vector<const DwarfFde*>*), (override));
43 
44   MOCK_METHOD(const DwarfFde*, GetFdeFromPc, (uint64_t), (override));
45 
46   MOCK_METHOD(bool, GetCfaLocationInfo, (uint64_t, const DwarfFde*, DwarfLocations*, ArchEnum arch),
47               (override));
48 
49   MOCK_METHOD(uint64_t, GetCieOffsetFromFde32, (uint32_t), (override));
50 
51   MOCK_METHOD(uint64_t, GetCieOffsetFromFde64, (uint64_t), (override));
52 
53   MOCK_METHOD(uint64_t, AdjustPcFromFde, (uint64_t), (override));
54 };
55 
56 class DwarfSectionTest : public ::testing::Test {
57  protected:
SetUp()58   void SetUp() override { section_.reset(new MockDwarfSection(&memory_)); }
59 
60   MemoryFake memory_;
61   std::unique_ptr<MockDwarfSection> section_;
62   static RegsFake regs_;
63 };
64 
65 RegsFake DwarfSectionTest::regs_(10);
66 
TEST_F(DwarfSectionTest,Step_fail_fde)67 TEST_F(DwarfSectionTest, Step_fail_fde) {
68   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr));
69 
70   bool finished;
71   bool is_signal_frame;
72   ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished, &is_signal_frame));
73 }
74 
TEST_F(DwarfSectionTest,Step_fail_cie_null)75 TEST_F(DwarfSectionTest, Step_fail_cie_null) {
76   DwarfFde fde{};
77   fde.pc_end = 0x2000;
78   fde.cie = nullptr;
79 
80   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
81 
82   bool finished;
83   bool is_signal_frame;
84   ASSERT_FALSE(section_->Step(0x1000, &regs_, nullptr, &finished, &is_signal_frame));
85 }
86 
TEST_F(DwarfSectionTest,Step_fail_cfa_location)87 TEST_F(DwarfSectionTest, Step_fail_cfa_location) {
88   DwarfCie cie{};
89   DwarfFde fde{};
90   fde.pc_end = 0x2000;
91   fde.cie = &cie;
92 
93   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
94   EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
95       .WillOnce(::testing::Return(false));
96 
97   bool finished;
98   bool is_signal_frame;
99   ASSERT_FALSE(section_->Step(0x1000, &regs_, nullptr, &finished, &is_signal_frame));
100 }
101 
TEST_F(DwarfSectionTest,Step_pass)102 TEST_F(DwarfSectionTest, Step_pass) {
103   DwarfCie cie{};
104   DwarfFde fde{};
105   fde.pc_end = 0x2000;
106   fde.cie = &cie;
107 
108   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
109   EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
110       .WillOnce(::testing::Return(true));
111 
112   MemoryFake process;
113   EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, &regs_, ::testing::_))
114       .WillOnce(::testing::Return(true));
115 
116   bool finished;
117   bool is_signal_frame;
118   ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished, &is_signal_frame));
119 }
120 
MockGetCfaLocationInfo(::testing::Unused,const DwarfFde * fde,DwarfLocations * loc_regs,ArchEnum)121 static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde, DwarfLocations* loc_regs,
122                                    ArchEnum) {
123   loc_regs->pc_start = fde->pc_start;
124   loc_regs->pc_end = fde->pc_end;
125   return true;
126 }
127 
TEST_F(DwarfSectionTest,Step_cache)128 TEST_F(DwarfSectionTest, Step_cache) {
129   DwarfCie cie{};
130   DwarfFde fde{};
131   fde.pc_start = 0x500;
132   fde.pc_end = 0x2000;
133   fde.cie = &cie;
134 
135   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde));
136   EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_))
137       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
138 
139   MemoryFake process;
140   EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, &regs_, ::testing::_))
141       .WillRepeatedly(::testing::Return(true));
142 
143   bool finished;
144   bool is_signal_frame;
145   ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished, &is_signal_frame));
146   ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished, &is_signal_frame));
147   ASSERT_TRUE(section_->Step(0x1500, &regs_, &process, &finished, &is_signal_frame));
148 }
149 
TEST_F(DwarfSectionTest,Step_cache_not_in_pc)150 TEST_F(DwarfSectionTest, Step_cache_not_in_pc) {
151   DwarfCie cie{};
152   DwarfFde fde0{};
153   fde0.pc_start = 0x1000;
154   fde0.pc_end = 0x2000;
155   fde0.cie = &cie;
156   EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0));
157   EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_, ::testing::_))
158       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
159 
160   MemoryFake process;
161   EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, &regs_, ::testing::_))
162       .WillRepeatedly(::testing::Return(true));
163 
164   bool finished;
165   bool is_signal_frame;
166   ASSERT_TRUE(section_->Step(0x1000, &regs_, &process, &finished, &is_signal_frame));
167 
168   DwarfFde fde1{};
169   fde1.pc_start = 0x500;
170   fde1.pc_end = 0x800;
171   fde1.cie = &cie;
172   EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1));
173   EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_, ::testing::_))
174       .WillOnce(::testing::Invoke(MockGetCfaLocationInfo));
175 
176   ASSERT_TRUE(section_->Step(0x600, &regs_, &process, &finished, &is_signal_frame));
177   ASSERT_TRUE(section_->Step(0x700, &regs_, &process, &finished, &is_signal_frame));
178 }
179 
180 }  // namespace unwindstack
181