1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crazy_linker_proc_maps.h"
6
7 #include <limits.h>
8 #include <minitest/minitest.h>
9 #include "crazy_linker_system_mock.h"
10
11 namespace crazy {
12
13 namespace {
14
15 const char kProcMaps0[] =
16 "4000b000-4000c000 r--p 00000000 00:00 0\n"
17 "4005c000-40081000 r-xp 00000000 b3:01 141 /system/bin/mksh\n"
18 "40082000-40083000 r--p 00025000 b3:01 141 /system/bin/mksh\n"
19 "40083000-40084000 rw-p 00026000 b3:01 141 /system/bin/mksh\n"
20 "40084000-40088000 rw-p 00000000 00:00 0\n"
21 "40088000-40090000 r--s 00000000 00:0b 1704 /dev/__properties__\n"
22 "400eb000-400ec000 r--p 00000000 00:00 0\n"
23 "40141000-40150000 r-xp 00000000 b3:01 126 /system/bin/linker\n"
24 "40150000-40151000 r--p 0000e000 b3:01 126 /system/bin/linker\n"
25 "40151000-40152000 rw-p 0000f000 b3:01 126 /system/bin/linker\n"
26 "40152000-40153000 rw-p 00000000 00:00 0\n"
27 "40231000-40277000 r-xp 00001000 b3:01 638 /system/lib/libc.so\n"
28 "40277000-40279000 r--p 00046000 b3:01 638 /system/lib/libc.so\n"
29 "40279000-4027b000 rw-p 00048000 b3:01 638 /system/lib/libc.so\n"
30 "4027b000-40289000 rw-p 00000000 00:00 0\n"
31 "41e6b000-41e72000 rw-p 00000000 00:00 0 [heap]\n"
32 "be91b000-be93c000 rw-p 00000000 00:00 0 [stack]\n"
33 "ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]\n";
34
35 class ScopedTestEnv {
36 public:
ScopedTestEnv()37 ScopedTestEnv() : sys_() {
38 sys_.AddRegularFile("/proc/self/maps", kProcMaps0, sizeof(kProcMaps0) - 1);
39 }
40
~ScopedTestEnv()41 ~ScopedTestEnv() {}
42
43 private:
44 SystemMock sys_;
45 };
46
47 } // namespace
48
TEST(ProcMaps,FindElfBinaryForAddress)49 TEST(ProcMaps, FindElfBinaryForAddress) {
50 ScopedTestEnv env;
51 char path[512];
52 uintptr_t load_address;
53
54 EXPECT_TRUE(FindElfBinaryForAddress(
55 reinterpret_cast<void*>(0x400694c2), &load_address, path, sizeof(path)));
56 EXPECT_EQ(0x4005c000, load_address);
57 EXPECT_STREQ("/system/bin/mksh", path);
58 }
59
TEST(ProcMaps,FindElfBinaryForAddressWithBadAddress)60 TEST(ProcMaps, FindElfBinaryForAddressWithBadAddress) {
61 ScopedTestEnv env;
62 char path[512];
63 uintptr_t load_address;
64
65 EXPECT_FALSE(FindElfBinaryForAddress(
66 reinterpret_cast<void*>(0x50000000), &load_address, path, sizeof(path)));
67 }
68
TEST(ProcMaps,FindProtectionFlagsForAddress)69 TEST(ProcMaps, FindProtectionFlagsForAddress) {
70 ScopedTestEnv env;
71 static const struct {
72 uintptr_t address;
73 bool success;
74 int prot;
75 } kData[] = {{0x4000afff, false, 0},
76 {0x4000b000, true, PROT_READ},
77 {0x4000bfff, true, PROT_READ},
78 {0x4000c000, false, 0},
79 {0x4005bfff, false, 0},
80 {0x4005c000, true, PROT_READ | PROT_EXEC},
81 {0x40067832, true, PROT_READ | PROT_EXEC},
82 {0x40082000, true, PROT_READ},
83 {0x40083000, true, PROT_READ | PROT_WRITE},
84 {0x40084000, true, PROT_READ | PROT_WRITE}, };
85
86 int prot;
87 for (size_t n = 0; n < ARRAY_LEN(kData); ++n) {
88 void* address = reinterpret_cast<void*>(kData[n].address);
89 TEST_TEXT << minitest::Format("Checking address %p", address);
90 EXPECT_EQ(kData[n].success, FindProtectionFlagsForAddress(address, &prot));
91 if (kData[n].success) {
92 TEST_TEXT << minitest::Format("Checking address %p", address);
93 EXPECT_EQ(kData[n].prot, prot);
94 }
95 }
96 }
97
TEST(ProcMaps,FindLoadAddressForFile)98 TEST(ProcMaps, FindLoadAddressForFile) {
99 ScopedTestEnv env;
100 static const struct {
101 bool success;
102 uintptr_t address;
103 uintptr_t offset;
104 const char* name;
105 } kData[] = {{true, 0x4005c000, 0, "mksh"},
106 {true, 0x40141000, 0, "/system/bin/linker"},
107 {false, 0, 0, "[heap]"},
108 {false, 0, 0, "bin/mksh"},
109 {true, 0x4005c000, 0, "/system/bin/mksh"},
110 {true, 0x40231000, 0x1000000, "libc.so"}, };
111 for (size_t n = 0; n < ARRAY_LEN(kData); ++n) {
112 uintptr_t address, offset;
113 TEST_TEXT << "Checking " << kData[n].name;
114 bool success = FindLoadAddressForFile(kData[n].name, &address, &offset);
115 EXPECT_EQ(kData[n].success, success);
116 if (success) {
117 TEST_TEXT << "Checking " << kData[n].name;
118 EXPECT_EQ(kData[n].address, address);
119
120 TEST_TEXT << "Checking " << kData[n].name;
121 EXPECT_EQ(kData[n].offset, offset);
122 }
123 }
124 }
125
TEST(ProcMaps,GetNextEntry)126 TEST(ProcMaps, GetNextEntry) {
127 ScopedTestEnv env;
128 // "4000b000-4000c000 r--p 00000000 00:00 0\n"
129 // "4005c000-40081000 r-xp 00000000 b3:01 141 /system/bin/mksh\n"
130 // "40082000-40083000 r--p 00025000 b3:01 141 /system/bin/mksh\n"
131 // "40083000-40084000 rw-p 00026000 b3:01 141 /system/bin/mksh\n"
132 // "40084000-40088000 rw-p 00000000 00:00 0\n"
133 // "40088000-40090000 r--s 00000000 00:0b 1704
134 // /dev/__properties__\n"
135 // "400eb000-400ec000 r--p 00000000 00:00 0\n"
136 // "40141000-40150000 r-xp 00000000 b3:01 126 /system/bin/linker\n"
137 // "40150000-40151000 r--p 0000e000 b3:01 126 /system/bin/linker\n"
138 // "40151000-40152000 rw-p 0000f000 b3:01 126 /system/bin/linker\n"
139 // "40152000-40153000 rw-p 00000000 00:00 0\n"
140 // "40231000-40277000 r-xp 00001000 b3:01 638
141 // /system/lib/libc.so\n"
142 // "40277000-40279000 r--p 00046000 b3:01 638
143 // /system/lib/libc.so\n"
144 // "40279000-4027b000 rw-p 00048000 b3:01 638
145 // /system/lib/libc.so\n"
146 // "4027b000-40289000 rw-p 00000000 00:00 0\n"
147 // "41e6b000-41e72000 rw-p 00000000 00:00 0 [heap]\n"
148 // "be91b000-be93c000 rw-p 00000000 00:00 0 [stack]\n"
149 // "ffff0000-ffff1000 r-xp 00000000 00:00 0 [vectors]\n"
150 static const struct {
151 size_t vma_start;
152 size_t vma_end;
153 int prot_flags;
154 size_t load_offset;
155 const char* path;
156 } kData[] = {
157 {0x4000b000, 0x4000c000, PROT_READ, 0, NULL},
158 {0x4005c000, 0x40081000, PROT_READ | PROT_EXEC, 0, "/system/bin/mksh"},
159 {0x40082000, 0x40083000, PROT_READ,
160 0x25000 * PAGE_SIZE, "/system/bin/mksh"},
161 {0x40083000, 0x40084000, PROT_READ | PROT_WRITE,
162 0x26000 * PAGE_SIZE, "/system/bin/mksh"},
163 {0x40084000, 0x40088000, PROT_READ | PROT_WRITE, 0, NULL},
164 {0x40088000, 0x40090000, PROT_READ, 0, "/dev/__properties__"},
165 {0x400eb000, 0x400ec000, PROT_READ, 0, NULL},
166 {0x40141000, 0x40150000, PROT_READ | PROT_EXEC,
167 0, "/system/bin/linker"},
168 {0x40150000, 0x40151000, PROT_READ,
169 0xe000 * PAGE_SIZE, "/system/bin/linker"},
170 {0x40151000, 0x40152000, PROT_READ | PROT_WRITE,
171 0xf000 * PAGE_SIZE, "/system/bin/linker"},
172 {0x40152000, 0x40153000, PROT_READ | PROT_WRITE, 0, NULL},
173 {0x40231000, 0x40277000, PROT_READ | PROT_EXEC,
174 0x1000 * PAGE_SIZE, "/system/lib/libc.so"},
175 {0x40277000, 0x40279000, PROT_READ,
176 0x46000 * PAGE_SIZE, "/system/lib/libc.so"},
177 {0x40279000, 0x4027b000, PROT_READ | PROT_WRITE,
178 0x48000 * PAGE_SIZE, "/system/lib/libc.so"},
179 {0x4027b000, 0x40289000, PROT_READ | PROT_WRITE, 0, NULL},
180 {0x41e6b000, 0x41e72000, PROT_READ | PROT_WRITE, 0, "[heap]"},
181 {0xbe91b000, 0xbe93c000, PROT_READ | PROT_WRITE, 0, "[stack]"},
182 {0xffff0000, 0xffff1000, PROT_READ | PROT_EXEC, 0, "[vectors]"}, };
183
184 ProcMaps self_maps;
185 ProcMaps::Entry entry;
186
187 for (size_t n = 0; n < ARRAY_LEN(kData); ++n) {
188 minitest::internal::String text =
189 minitest::Format("Checking entry #%d %p-%p",
190 n + 1,
191 kData[n].vma_start,
192 kData[n].vma_end);
193 TEST_TEXT << text;
194 EXPECT_TRUE(self_maps.GetNextEntry(&entry));
195 TEST_TEXT << text;
196 EXPECT_EQ(kData[n].vma_start, entry.vma_start);
197 TEST_TEXT << text;
198 EXPECT_EQ(kData[n].vma_end, entry.vma_end);
199 TEST_TEXT << text;
200 EXPECT_EQ(kData[n].prot_flags, entry.prot_flags);
201 TEST_TEXT << text;
202 EXPECT_EQ(kData[n].load_offset, entry.load_offset);
203
204 if (!kData[n].path) {
205 TEST_TEXT << text;
206 EXPECT_FALSE(entry.path);
207 } else {
208 EXPECT_MEMEQ(
209 kData[n].path, strlen(kData[n].path), entry.path, entry.path_len);
210 }
211 }
212 EXPECT_FALSE(self_maps.GetNextEntry(&entry));
213 }
214
215 } // namespace crazy
216