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 elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
77 elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
78 elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
79 elf_fakes_.push_back(new ElfInterfaceFake(nullptr));
80
81 ElfFake* elf_fake = new ElfFake(nullptr);
82 elf_fake->FakeSetValid(true);
83 elf_fake->FakeSetInterface(elf_fakes_[0]);
84 elf_fakes_[0]->FakeSetDataVaddrStart(0x2000);
85 elf_fakes_[0]->FakeSetDataVaddrEnd(0x3000);
86 elf_fakes_[0]->FakeSetDataOffset(0x2000);
87 auto map_info = maps_->Find(0x10000);
88 map_info->GetElfFields().elf_.reset(elf_fake);
89
90 elf_fake = new ElfFake(nullptr);
91 elf_fake->FakeSetValid(true);
92 elf_fake->FakeSetInterface(elf_fakes_[1]);
93 elf_fakes_[1]->FakeSetDataVaddrStart(0x2000);
94 elf_fakes_[1]->FakeSetDataVaddrEnd(0x3000);
95 elf_fakes_[1]->FakeSetDataOffset(0x2000);
96 map_info = maps_->Find(0x20000);
97 map_info->GetElfFields().elf_.reset(elf_fake);
98
99 elf_fake = new ElfFake(nullptr);
100 elf_fake->FakeSetValid(true);
101 elf_fake->FakeSetInterface(elf_fakes_[2]);
102 elf_fakes_[2]->FakeSetDataVaddrStart(0x2000);
103 elf_fakes_[2]->FakeSetDataVaddrEnd(0x3000);
104 elf_fakes_[2]->FakeSetDataOffset(0x2000);
105 map_info = maps_->Find(0x30000);
106 map_info->GetElfFields().elf_.reset(elf_fake);
107
108 elf_fake = new ElfFake(nullptr);
109 elf_fake->FakeSetValid(true);
110 elf_fake->FakeSetInterface(elf_fakes_[3]);
111 elf_fakes_[3]->FakeSetDataVaddrStart(00);
112 elf_fakes_[3]->FakeSetDataVaddrEnd(0x1000);
113 elf_fakes_[3]->FakeSetDataOffset(0);
114 map_info = maps_->Find(0x40000);
115 map_info->GetElfFields().elf_.reset(elf_fake);
116
117 global_.reset(new GlobalMock(empty_));
118 }
119
120 std::shared_ptr<Memory> empty_;
121 std::unique_ptr<BufferMaps> maps_;
122 std::unique_ptr<GlobalMock> global_;
123 std::vector<ElfInterfaceFake*> elf_fakes_;
124 };
125
TEST_F(GlobalTest,ro_rx_rw)126 TEST_F(GlobalTest, ro_rx_rw) {
127 std::string global_var("fake_global");
128 elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
129 EXPECT_CALL(*global_, ReadVariableData(0x12010)).WillOnce(Return(true));
130
131 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
132 }
133
TEST_F(GlobalTest,ro_rx_rw_searchable)134 TEST_F(GlobalTest, ro_rx_rw_searchable) {
135 std::vector<std::string> search_libs = {"first.so"};
136 global_.reset(new GlobalMock(empty_, search_libs));
137
138 std::string global_var("fake_global");
139 elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
140 EXPECT_CALL(*global_, ReadVariableData(0x12010)).WillOnce(Return(true));
141
142 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
143 }
144
TEST_F(GlobalTest,ro_rx_rw_not_searchable)145 TEST_F(GlobalTest, ro_rx_rw_not_searchable) {
146 std::vector<std::string> search_libs = {"second.so"};
147 global_.reset(new GlobalMock(empty_, search_libs));
148
149 std::string global_var("fake_global");
150 elf_fakes_[0]->FakeSetGlobalVariable(global_var, 0x2010);
151
152 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
153 }
154
TEST_F(GlobalTest,ro_rw)155 TEST_F(GlobalTest, ro_rw) {
156 std::string global_var("fake_global");
157 elf_fakes_[1]->FakeSetGlobalVariable(global_var, 0x2010);
158 EXPECT_CALL(*global_, ReadVariableData(0x22010)).WillOnce(Return(true));
159
160 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
161 }
162
TEST_F(GlobalTest,ro_blank_rx_rw)163 TEST_F(GlobalTest, ro_blank_rx_rw) {
164 std::string global_var("fake_global");
165 elf_fakes_[2]->FakeSetGlobalVariable(global_var, 0x2010);
166 EXPECT_CALL(*global_, ReadVariableData(0x33010)).WillOnce(Return(true));
167
168 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
169 }
170
TEST_F(GlobalTest,ro_rw_with_zero_offset)171 TEST_F(GlobalTest, ro_rw_with_zero_offset) {
172 std::string global_var("fake_global");
173 elf_fakes_[3]->FakeSetGlobalVariable(global_var, 0x10);
174 EXPECT_CALL(*global_, ReadVariableData(0x42010)).WillOnce(Return(true));
175
176 global_->TestFindAndReadVariable(maps_.get(), global_var.c_str());
177 }
178
179 } // namespace unwindstack
180