OLD | NEW |
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/proc_maps_linux.h" | 5 #include "base/debug/proc_maps_linux.h" |
6 #include "base/files/file_path.h" | 6 #include "base/files/file_path.h" |
7 #include "base/path_service.h" | 7 #include "base/path_service.h" |
8 #include "base/strings/stringprintf.h" | 8 #include "base/strings/stringprintf.h" |
9 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" | 9 #include "base/third_party/dynamic_annotations/dynamic_annotations.h" |
10 #include "base/threading/platform_thread.h" | 10 #include "base/threading/platform_thread.h" |
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
192 // We should be able to find both the current executable as well as the stack | 192 // We should be able to find both the current executable as well as the stack |
193 // mapped into memory. Use the address of |proc_maps| as a way of finding the | 193 // mapped into memory. Use the address of |proc_maps| as a way of finding the |
194 // stack. | 194 // stack. |
195 FilePath exe_path; | 195 FilePath exe_path; |
196 EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); | 196 EXPECT_TRUE(PathService::Get(FILE_EXE, &exe_path)); |
197 uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps); | 197 uintptr_t address = reinterpret_cast<uintptr_t>(&proc_maps); |
198 bool found_exe = false; | 198 bool found_exe = false; |
199 bool found_stack = false; | 199 bool found_stack = false; |
200 bool found_address = false; | 200 bool found_address = false; |
201 | 201 |
202 // Valgrind uses its own allocated stacks instead of the kernel-provided stack | |
203 // without letting the kernel know via prctl(PR_SET_MM_START_STACK). This | |
204 // causes the kernel to use [stack:TID] format. See http://crbug.com/431702 | |
205 // for details. | |
206 std::string stack_with_tid = | |
207 StringPrintf("[stack:%d]", PlatformThread::CurrentId()); | |
208 | |
209 for (size_t i = 0; i < regions.size(); ++i) { | 202 for (size_t i = 0; i < regions.size(); ++i) { |
210 if (regions[i].path == exe_path.value()) { | 203 if (regions[i].path == exe_path.value()) { |
211 // It's OK to find the executable mapped multiple times as there'll be | 204 // It's OK to find the executable mapped multiple times as there'll be |
212 // multiple sections (e.g., text, data). | 205 // multiple sections (e.g., text, data). |
213 found_exe = true; | 206 found_exe = true; |
214 } | 207 } |
215 | 208 |
216 bool is_correct_stack = false; | 209 // Valgrind uses its own allocated stacks instead of the kernel-provided |
217 if (regions[i].path == "[stack]") { | 210 // stack without letting the kernel know via prctl(PR_SET_MM_START_STACK). |
218 is_correct_stack = true; | 211 // Depending on which kernel you're running it'll impact the output of |
219 EXPECT_FALSE(RunningOnValgrind()); | 212 // /proc/self/maps. |
| 213 // |
| 214 // Prior to version 3.4, the kernel completely ignores other stacks and |
| 215 // always prints out the vma lying within mm->start_stack as [stack] even |
| 216 // if the program was currently executing on a different stack. |
| 217 // |
| 218 // Starting in 3.4, the kernel will print out the vma containing the current |
| 219 // stack pointer as [stack:TID] as long as that vma does not lie within |
| 220 // mm->start_stack. |
| 221 // |
| 222 // Because this has gotten too complicated and brittle of a test, completely |
| 223 // ignore checking for the stack and address when running under Valgrind. |
| 224 // See http://crbug.com/431702 for more details. |
| 225 if (!RunningOnValgrind() && regions[i].path == "[stack]") { |
220 EXPECT_GE(address, regions[i].start); | 226 EXPECT_GE(address, regions[i].start); |
221 EXPECT_LT(address, regions[i].end); | 227 EXPECT_LT(address, regions[i].end); |
222 } else if (regions[i].path == stack_with_tid) { | |
223 is_correct_stack = true; | |
224 EXPECT_TRUE(RunningOnValgrind()); | |
225 } | |
226 | |
227 if (is_correct_stack) { | |
228 // Note that the stack is executable when it is created by Valgrind. | |
229 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ); | 228 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::READ); |
230 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE); | 229 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::WRITE); |
231 EXPECT_EQ(RunningOnValgrind(), | 230 EXPECT_FALSE(regions[i].permissions & MappedMemoryRegion::EXECUTE); |
232 (regions[i].permissions & MappedMemoryRegion::EXECUTE) != 0); | |
233 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE); | 231 EXPECT_TRUE(regions[i].permissions & MappedMemoryRegion::PRIVATE); |
234 EXPECT_FALSE(found_stack) << "Found duplicate stacks"; | 232 EXPECT_FALSE(found_stack) << "Found duplicate stacks"; |
235 found_stack = true; | 233 found_stack = true; |
236 } | 234 } |
237 | 235 |
238 if (address >= regions[i].start && address < regions[i].end) { | 236 if (address >= regions[i].start && address < regions[i].end) { |
239 EXPECT_FALSE(found_address) << "Found same address in multiple regions"; | 237 EXPECT_FALSE(found_address) << "Found same address in multiple regions"; |
240 found_address = true; | 238 found_address = true; |
241 } | 239 } |
242 } | 240 } |
243 | 241 |
244 EXPECT_TRUE(found_exe); | 242 EXPECT_TRUE(found_exe); |
245 EXPECT_TRUE(found_stack); | 243 if (!RunningOnValgrind()) { |
246 EXPECT_TRUE(found_address); | 244 EXPECT_TRUE(found_stack); |
| 245 EXPECT_TRUE(found_address); |
| 246 } |
247 } | 247 } |
248 | 248 |
249 TEST(ProcMapsTest, ReadProcMapsNonEmptyString) { | 249 TEST(ProcMapsTest, ReadProcMapsNonEmptyString) { |
250 std::string old_string("I forgot to clear the string"); | 250 std::string old_string("I forgot to clear the string"); |
251 std::string proc_maps(old_string); | 251 std::string proc_maps(old_string); |
252 ASSERT_TRUE(ReadProcMaps(&proc_maps)); | 252 ASSERT_TRUE(ReadProcMaps(&proc_maps)); |
253 EXPECT_EQ(std::string::npos, proc_maps.find(old_string)); | 253 EXPECT_EQ(std::string::npos, proc_maps.find(old_string)); |
254 } | 254 } |
255 | 255 |
256 TEST(ProcMapsTest, MissingFields) { | 256 TEST(ProcMapsTest, MissingFields) { |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
319 EXPECT_EQ(5ULL, regions.size()); | 319 EXPECT_EQ(5ULL, regions.size()); |
320 EXPECT_EQ("/bin/cat", regions[0].path); | 320 EXPECT_EQ("/bin/cat", regions[0].path); |
321 EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path); | 321 EXPECT_EQ("/lib/x86_64-linux-gnu/libc-2.15.so", regions[1].path); |
322 EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path); | 322 EXPECT_EQ("/lib/x86_64-linux-gnu/ld-2.15.so", regions[2].path); |
323 EXPECT_EQ("\"vd so\"", regions[3].path); | 323 EXPECT_EQ("\"vd so\"", regions[3].path); |
324 EXPECT_EQ("[vsys call]", regions[4].path); | 324 EXPECT_EQ("[vsys call]", regions[4].path); |
325 } | 325 } |
326 | 326 |
327 } // namespace debug | 327 } // namespace debug |
328 } // namespace base | 328 } // namespace base |
OLD | NEW |