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