1 /*
2  * Copyright (C) 2018 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 #include <sys/mman.h>
19 
20 #include <thread>
21 
22 #include <gtest/gtest.h>
23 
24 #include <unwindstack/MapInfo.h>
25 #include <unwindstack/Maps.h>
26 
27 #include "ElfFake.h"
28 
29 namespace unwindstack {
30 
TEST(MapInfoTest,maps_constructor_const_char)31 TEST(MapInfoTest, maps_constructor_const_char) {
32   auto prev_map = MapInfo::Create(0, 0, 0, 0, "");
33   auto map_info = MapInfo::Create(prev_map, 1, 2, 3, 4, "map");
34 
35   EXPECT_EQ(prev_map.get(), map_info->prev_map().get());
36   EXPECT_EQ(1UL, map_info->start());
37   EXPECT_EQ(2UL, map_info->end());
38   EXPECT_EQ(3UL, map_info->offset());
39   EXPECT_EQ(4UL, map_info->flags());
40   EXPECT_EQ("map", map_info->name());
41   EXPECT_EQ(UINT64_MAX, map_info->load_bias());
42   EXPECT_EQ(0UL, map_info->elf_offset());
43   EXPECT_TRUE(map_info->elf().get() == nullptr);
44 }
45 
TEST(MapInfoTest,maps_constructor_string)46 TEST(MapInfoTest, maps_constructor_string) {
47   std::string name("string_map");
48   auto prev_map = MapInfo::Create(0, 0, 0, 0, "");
49   auto map_info = MapInfo::Create(prev_map, 1, 2, 3, 4, name);
50 
51   EXPECT_EQ(prev_map, map_info->prev_map());
52   EXPECT_EQ(1UL, map_info->start());
53   EXPECT_EQ(2UL, map_info->end());
54   EXPECT_EQ(3UL, map_info->offset());
55   EXPECT_EQ(4UL, map_info->flags());
56   EXPECT_EQ("string_map", map_info->name());
57   EXPECT_EQ(UINT64_MAX, map_info->load_bias());
58   EXPECT_EQ(0UL, map_info->elf_offset());
59   EXPECT_TRUE(map_info->elf().get() == nullptr);
60 }
61 
TEST(MapInfoTest,real_map_check)62 TEST(MapInfoTest, real_map_check) {
63   auto map1 = MapInfo::Create(0, 0x1000, 0, PROT_READ, "fake.so");
64   auto map2 = MapInfo::Create(map1, 0, 0, 0, 0, "");
65   auto map3 = MapInfo::Create(map2, 0x1000, 0x2000, 0x1000, PROT_READ | PROT_EXEC, "fake.so");
66 
67   EXPECT_EQ(nullptr, map1->prev_map());
68   EXPECT_EQ(nullptr, map1->GetPrevRealMap());
69   EXPECT_EQ(map2, map1->next_map());
70   EXPECT_EQ(map3, map1->GetNextRealMap());
71 
72   EXPECT_EQ(map1, map2->prev_map());
73   EXPECT_EQ(nullptr, map2->GetPrevRealMap());
74   EXPECT_EQ(map3, map2->next_map());
75   EXPECT_EQ(nullptr, map2->GetNextRealMap());
76 
77   EXPECT_EQ(map2, map3->prev_map());
78   EXPECT_EQ(map1, map3->GetPrevRealMap());
79   EXPECT_EQ(nullptr, map3->next_map());
80   EXPECT_EQ(nullptr, map3->GetNextRealMap());
81 
82   // Verify that if the middle map is not blank, then the Get{Next,Prev}RealMap
83   // functions return nullptrs.
84   map2->set_offset(1);
85   EXPECT_EQ(nullptr, map1->GetPrevRealMap());
86   EXPECT_EQ(nullptr, map1->GetNextRealMap());
87   EXPECT_EQ(nullptr, map3->GetPrevRealMap());
88   EXPECT_EQ(nullptr, map3->GetNextRealMap());
89   map2->set_offset(0);
90   EXPECT_EQ(map3, map1->GetNextRealMap());
91 
92   map2->set_flags(1);
93   EXPECT_EQ(nullptr, map1->GetPrevRealMap());
94   EXPECT_EQ(nullptr, map1->GetNextRealMap());
95   EXPECT_EQ(nullptr, map3->GetPrevRealMap());
96   EXPECT_EQ(nullptr, map3->GetNextRealMap());
97   map2->set_flags(0);
98   EXPECT_EQ(map3, map1->GetNextRealMap());
99 
100   map2->set_name("something");
101   EXPECT_EQ(nullptr, map1->GetPrevRealMap());
102   EXPECT_EQ(nullptr, map1->GetNextRealMap());
103   EXPECT_EQ(nullptr, map3->GetPrevRealMap());
104   EXPECT_EQ(nullptr, map3->GetNextRealMap());
105   map2->set_name("");
106   EXPECT_EQ(map3, map1->GetNextRealMap());
107 
108   // Verify that if the Get{Next,Prev}RealMap names must match.
109   map1->set_name("another");
110   EXPECT_EQ(nullptr, map1->GetPrevRealMap());
111   EXPECT_EQ(nullptr, map1->GetNextRealMap());
112   EXPECT_EQ(nullptr, map3->GetPrevRealMap());
113   EXPECT_EQ(nullptr, map3->GetNextRealMap());
114   map1->set_name("fake.so");
115   EXPECT_EQ(map3, map1->GetNextRealMap());
116 
117   map3->set_name("another");
118   EXPECT_EQ(nullptr, map1->GetPrevRealMap());
119   EXPECT_EQ(nullptr, map1->GetNextRealMap());
120   EXPECT_EQ(nullptr, map3->GetPrevRealMap());
121   EXPECT_EQ(nullptr, map3->GetNextRealMap());
122   map3->set_name("fake.so");
123   EXPECT_EQ(map3, map1->GetNextRealMap());
124 }
125 
TEST(MapInfoTest,get_function_name)126 TEST(MapInfoTest, get_function_name) {
127   std::shared_ptr<Memory> empty;
128   ElfFake* elf = new ElfFake(empty);
129   ElfInterfaceFake* interface = new ElfInterfaceFake(empty);
130   elf->FakeSetInterface(interface);
131   interface->FakePushFunctionData(FunctionData("function", 1000));
132 
133   auto map_info = MapInfo::Create(1, 2, 3, 4, "");
134   map_info->set_elf(elf);
135 
136   SharedString name;
137   uint64_t offset;
138   ASSERT_TRUE(map_info->GetFunctionName(1000, &name, &offset));
139   EXPECT_EQ("function", name);
140   EXPECT_EQ(1000UL, offset);
141 }
142 
TEST(MapInfoTest,multiple_thread_get_elf_fields)143 TEST(MapInfoTest, multiple_thread_get_elf_fields) {
144   auto map_info = MapInfo::Create(0, 0, 0, 0, "");
145 
146   static constexpr size_t kNumConcurrentThreads = 100;
147   MapInfo::ElfFields* elf_fields[kNumConcurrentThreads];
148 
149   std::atomic_bool wait;
150   wait = true;
151   // Create all of the threads and have them do the call at the same time
152   // to make it likely that a race will occur.
153   std::vector<std::thread*> threads;
154   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
155     std::thread* thread = new std::thread([i, &wait, &map_info, &elf_fields]() {
156       while (wait)
157         ;
158       elf_fields[i] = &map_info->GetElfFields();
159     });
160     threads.push_back(thread);
161   }
162 
163   // Set them all going and wait for the threads to finish.
164   wait = false;
165   for (auto thread : threads) {
166     thread->join();
167     delete thread;
168   }
169 
170   // Now verify that all of elf fields are exactly the same and valid.
171   MapInfo::ElfFields* expected_elf_fields = &map_info->GetElfFields();
172   ASSERT_TRUE(expected_elf_fields != nullptr);
173   for (size_t i = 0; i < kNumConcurrentThreads; i++) {
174     EXPECT_EQ(expected_elf_fields, elf_fields[i]) << "Thread " << i << " mismatched.";
175   }
176 }
177 
TEST(MapInfoTest,elf_file_not_readable)178 TEST(MapInfoTest, elf_file_not_readable) {
179   auto map_info_readable = MapInfo::Create(0, 0x1000, 0, PROT_READ, "fake.so");
180   map_info_readable->set_memory_backed_elf(true);
181   ASSERT_TRUE(map_info_readable->ElfFileNotReadable());
182 
183   auto map_info_no_name = MapInfo::Create(0, 0x1000, 0, PROT_READ, "");
184   map_info_no_name->set_memory_backed_elf(true);
185   ASSERT_FALSE(map_info_no_name->ElfFileNotReadable());
186 
187   auto map_info_bracket = MapInfo::Create(0, 0x2000, 0, PROT_READ, "[vdso]");
188   map_info_bracket->set_memory_backed_elf(true);
189   ASSERT_FALSE(map_info_bracket->ElfFileNotReadable());
190 
191   auto map_info_memfd = MapInfo::Create(0, 0x3000, 0, PROT_READ, "/memfd:jit-cache");
192   map_info_memfd->set_memory_backed_elf(true);
193   ASSERT_FALSE(map_info_memfd->ElfFileNotReadable());
194 }
195 
196 }  // namespace unwindstack
197