1 /*
2 * Copyright (C) 2021 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 <memory>
23 #include <string>
24 #include <vector>
25
26 #include <unwindstack/Elf.h>
27 #include <unwindstack/Global.h>
28 #include <unwindstack/MapInfo.h>
29 #include <unwindstack/Maps.h>
30
31 #include "ElfFake.h"
32
33 using ::testing::_;
34 using ::testing::DoAll;
35 using ::testing::Return;
36 using ::testing::SetArgPointee;
37
38 namespace unwindstack {
39
40 class GlobalMock : public Global {
41 public:
GlobalMock(std::shared_ptr<Memory> & memory)42 explicit GlobalMock(std::shared_ptr<Memory>& memory) : Global(memory) {}
GlobalMock(std::shared_ptr<Memory> & memory,std::vector<std::string> & search_libs)43 GlobalMock(std::shared_ptr<Memory>& memory, std::vector<std::string>& search_libs)
44 : Global(memory, search_libs) {}
45
46 MOCK_METHOD(bool, ReadVariableData, (uint64_t), (override));
47
48 MOCK_METHOD(void, ProcessArch, (), (override));
49
TestFindAndReadVariable(Maps * maps,const char * var_str)50 void TestFindAndReadVariable(Maps* maps, const char* var_str) {
51 FindAndReadVariable(maps, var_str);
52 }
53 };
54
55 class GlobalTest : public ::testing::Test {
56 protected:
SetUp()57 void SetUp() override {
58 maps_.reset(
59 new BufferMaps("10000-11000 r--p 0000 00:00 0 first.so\n"
60 "11000-12000 r-xp 1000 00:00 0 first.so\n"
61 "12000-13000 rw-p 2000 00:00 0 first.so\n"
62
63 "20000-22000 r--p 0000 00:00 0 second.so\n"
64 "22000-23000 rw-p 2000 00:00 0 second.so\n"
65
66 "30000-31000 r--p 0000 00:00 0 third.so\n"
67 "31000-32000 ---p 0000 00:00 0\n"
68 "32000-33000 r-xp 1000 00:00 0 third.so\n"
69 "33000-34000 rw-p 2000 00:00 0 third.so\n"
70
71 "40000-42000 r--p 0000 00:00 0 fourth.so\n"
72 "42000-43000 rw-p 0000 00:00 0 fourth.so\n"));
73 ASSERT_TRUE(maps_->Parse());
74 ASSERT_EQ(11U, maps_->Total());
75
76 std::shared_ptr<Memory> empty;
77 elf_fakes_.push_back(new ElfInterfaceFake(empty));
78 elf_fakes_.push_back(new ElfInterfaceFake(empty));
79 elf_fakes_.push_back(new ElfInterfaceFake(empty));
80 elf_fakes_.push_back(new ElfInterfaceFake(empty));
81
82 ElfFake* elf_fake = new ElfFake(empty);
83 elf_fake->FakeSetValid(true);
84 elf_fake->FakeSetInterface(elf_fakes_[0]);
85 elf_fakes_[0]->FakeSetDataVaddrStart(0x2000);
86 elf_fakes_[0]->FakeSetDataVaddrEnd(0x3000);
87 elf_fakes_[0]->FakeSetDataOffset(0x2000);
88 auto map_info = maps_->Find(0x10000);
89 map_info->GetElfFields().elf_.reset(elf_fake);
90
91 elf_fake = new ElfFake(empty);
92 elf_fake->FakeSetValid(true);
93 elf_fake->FakeSetInterface(elf_fakes_[1]);
94 elf_fakes_[1]->FakeSetDataVaddrStart(0x2000);
95 elf_fakes_[1]->FakeSetDataVaddrEnd(0x3000);
96 elf_fakes_[1]->FakeSetDataOffset(0x2000);
97 map_info = maps_->Find(0x20000);
98 map_info->GetElfFields().elf_.reset(elf_fake);
99
100 elf_fake = new ElfFake(empty);
101 elf_fake->FakeSetValid(true);
102 elf_fake->FakeSetInterface(elf_fakes_[2]);
103 elf_fakes_[2]->FakeSetDataVaddrStart(0x2000);
104 elf_fakes_[2]->FakeSetDataVaddrEnd(0x3000);
105 elf_fakes_[2]->FakeSetDataOffset(0x2000);
106 map_info = maps_->Find(0x30000);
107 map_info->GetElfFields().elf_.reset(elf_fake);
108
109 elf_fake = new ElfFake(empty);
110 elf_fake->FakeSetValid(true);
111 elf_fake->FakeSetInterface(elf_fakes_[3]);
112 elf_fakes_[3]->FakeSetDataVaddrStart(00);
113 elf_fakes_[3]->FakeSetDataVaddrEnd(0x1000);
114 elf_fakes_[3]->FakeSetDataOffset(0);
115 map_info = maps_->Find(0x40000);
116 map_info->GetElfFields().elf_.reset(elf_fake);
117
118 global_.reset(new GlobalMock(empty_));
119 }
120
121 std::shared_ptr<Memory> empty_;
122 std::unique_ptr<BufferMaps> maps_;
123 std::unique_ptr<GlobalMock> global_;
124 std::vector<ElfInterfaceFake*> elf_fakes_;
125 };
126
TEST_F(GlobalTest,ro_rx_rw)127 TEST_F(GlobalTest, ro_rx_rw) {
128 std::string global_var("fake_global");
129 elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
130 EXPECT_CALL(*global_, ReadVariableData(0x12010)).WillOnce(Return(true));
131
132 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
133 }
134
TEST_F(GlobalTest,ro_rx_rw_searchable)135 TEST_F(GlobalTest, ro_rx_rw_searchable) {
136 std::vector<std::string> search_libs = {"first.so"};
137 global_.reset(new GlobalMock(empty_, search_libs));
138
139 std::string global_var("fake_global");
140 elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
141 EXPECT_CALL(*global_, ReadVariableData(0x12010)).WillOnce(Return(true));
142
143 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
144 }
145
TEST_F(GlobalTest,ro_rx_rw_not_searchable)146 TEST_F(GlobalTest, ro_rx_rw_not_searchable) {
147 std::vector<std::string> search_libs = {"second.so"};
148 global_.reset(new GlobalMock(empty_, search_libs));
149
150 std::string global_var("fake_global");
151 elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
152
153 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
154 }
155
TEST_F(GlobalTest,ro_rw)156 TEST_F(GlobalTest, ro_rw) {
157 std::string global_var("fake_global");
158 elf_fakes_[1]->FakeSetGlobalVariable(global_var, 0x2010);
159 EXPECT_CALL(*global_, ReadVariableData(0x22010)).WillOnce(Return(true));
160
161 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
162 }
163
TEST_F(GlobalTest,ro_blank_rx_rw)164 TEST_F(GlobalTest, ro_blank_rx_rw) {
165 std::string global_var("fake_global");
166 elf_fakes_[2]->FakeSetGlobalVariable(global_var, 0x2010);
167 EXPECT_CALL(*global_, ReadVariableData(0x33010)).WillOnce(Return(true));
168
169 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
170 }
171
TEST_F(GlobalTest,ro_rw_with_zero_offset)172 TEST_F(GlobalTest, ro_rw_with_zero_offset) {
173 std::string global_var("fake_global");
174 elf_fakes_[3]->FakeSetGlobalVariable(global_var, 0x10);
175 EXPECT_CALL(*global_, ReadVariableData(0x42010)).WillOnce(Return(true));
176
177 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
178 }
179
180 } // namespace unwindstack
181