Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2009, Google Inc. | 1 // Copyright (c) 2009, Google Inc. |
| 2 // All rights reserved. | 2 // All rights reserved. |
| 3 // | 3 // |
| 4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
| 5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
| 6 // met: | 6 // met: |
| 7 // | 7 // |
| 8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
| 9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
| 10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 29 | 29 |
| 30 #include <unistd.h> | 30 #include <unistd.h> |
| 31 #include <signal.h> | |
| 32 #include <sys/types.h> | |
| 31 | 33 |
| 34 #include "breakpad_googletest_includes.h" | |
| 35 #include "common/linux/memory.h" | |
| 32 #include "client/linux/minidump_writer/linux_dumper.h" | 36 #include "client/linux/minidump_writer/linux_dumper.h" |
| 33 #include "breakpad_googletest_includes.h" | |
| 34 | 37 |
| 35 using namespace google_breakpad; | 38 using namespace google_breakpad; |
| 36 | 39 |
| 37 namespace { | 40 namespace { |
| 38 typedef testing::Test LinuxDumperTest; | 41 typedef testing::Test LinuxDumperTest; |
| 39 } | 42 } |
| 40 | 43 |
| 41 TEST(LinuxDumperTest, Setup) { | 44 TEST(LinuxDumperTest, Setup) { |
| 42 LinuxDumper dumper(getpid()); | 45 LinuxDumper dumper(getpid()); |
| 43 } | 46 } |
| 44 | 47 |
| 45 TEST(LinuxDumperTest, FindMappings) { | 48 TEST(LinuxDumperTest, FindMappings) { |
| 46 LinuxDumper dumper(getpid()); | 49 LinuxDumper dumper(getpid()); |
| 47 ASSERT_TRUE(dumper.Init()); | 50 ASSERT_TRUE(dumper.Init()); |
| 48 | 51 |
| 49 ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid))); | 52 ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(getpid))); |
| 50 ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(printf))); | 53 ASSERT_TRUE(dumper.FindMapping(reinterpret_cast<void*>(printf))); |
| 51 ASSERT_FALSE(dumper.FindMapping(NULL)); | 54 ASSERT_FALSE(dumper.FindMapping(NULL)); |
| 52 } | 55 } |
| 53 | 56 |
| 54 TEST(LinuxDumperTest, ThreadList) { | 57 TEST(LinuxDumperTest, ThreadList) { |
| 55 LinuxDumper dumper(getpid()); | 58 LinuxDumper dumper(getpid()); |
| 56 ASSERT_TRUE(dumper.Init()); | 59 ASSERT_TRUE(dumper.Init()); |
| 57 | 60 |
| 58 ASSERT_GE(dumper.threads().size(), 1); | 61 ASSERT_GE(dumper.threads().size(), (size_t)1); |
| 59 bool found = false; | 62 bool found = false; |
| 60 for (size_t i = 0; i < dumper.threads().size(); ++i) { | 63 for (size_t i = 0; i < dumper.threads().size(); ++i) { |
| 61 if (dumper.threads()[i] == getpid()) { | 64 if (dumper.threads()[i] == getpid()) { |
| 62 found = true; | 65 found = true; |
| 63 break; | 66 break; |
| 64 } | 67 } |
| 65 } | 68 } |
| 66 } | 69 } |
| 67 | 70 |
| 71 TEST(LinuxDumperTest, VerifyStackReadWithMultipleThreads) { | |
| 72 static const int kNumberOfThreadsInHelperProgram = 5; | |
| 73 char kNumberOfThreadsArgument[2]; | |
| 74 sprintf(kNumberOfThreadsArgument, "%d", kNumberOfThreadsInHelperProgram); | |
|
awong
2010/02/08 20:52:55
Can you use StrintPrintf instead (if you have it)?
| |
| 75 pid_t child_pid = fork(); | |
| 76 if (child_pid == 0) { | |
| 77 // Set the number of threads | |
| 78 execl("./linux_dumper_unittest_helper", | |
| 79 "linux_dumper_unittest_helper", | |
| 80 kNumberOfThreadsArgument, | |
| 81 NULL); | |
| 82 // Kill if we get here. | |
| 83 printf("Errno from exec: %d", errno); | |
| 84 FAIL() << "Exec failed: " << strerror(errno); | |
| 85 } | |
| 86 // The sleep is flaky, but prevents us from reading | |
| 87 // the child process before all threads have been created. | |
| 88 sleep(1); | |
| 89 LinuxDumper dumper(child_pid); | |
| 90 EXPECT_TRUE(dumper.Init()); | |
| 91 EXPECT_EQ((size_t)kNumberOfThreadsInHelperProgram, dumper.threads().size()); | |
| 92 EXPECT_TRUE(dumper.ThreadsSuspend()); | |
| 93 | |
| 94 ThreadInfo one_thread; | |
| 95 for(size_t i = 0; i < dumper.threads().size(); ++i) { | |
| 96 EXPECT_TRUE(dumper.ThreadInfoGet(dumper.threads()[i], &one_thread)); | |
| 97 // We know the threads are in a function which has allocated exactly | |
| 98 // one word off the stack to store its thread id. | |
| 99 #if defined(__ARM_EABI__) | |
| 100 void* process_tid_location = (void *)(one_thread.regs.uregs[11] - 8); | |
| 101 #elif defined(__i386) | |
| 102 void* process_tid_location = (void *)(one_thread.regs.ebp - 4); | |
| 103 #elif defined(__x86_64) | |
| 104 void* process_tid_location = (void *)(one_thread.regs.ebp - 8); | |
|
Ted Mielczarek
2010/02/05 17:04:07
This should be one_thread.regs.rbp. Also, this tes
| |
| 105 #else | |
| 106 #error Platform not supported! | |
| 107 #endif | |
| 108 pid_t one_thread_id; | |
| 109 dumper.CopyFromProcess(&one_thread_id, | |
| 110 dumper.threads()[i], | |
| 111 process_tid_location, | |
| 112 4); | |
| 113 EXPECT_EQ(dumper.threads()[i], one_thread_id); | |
| 114 } | |
| 115 kill(child_pid, SIGKILL); | |
| 116 } | |
| 117 | |
| 68 TEST(LinuxDumperTest, BuildProcPath) { | 118 TEST(LinuxDumperTest, BuildProcPath) { |
| 69 const pid_t pid = getpid(); | 119 const pid_t pid = getpid(); |
| 70 LinuxDumper dumper(pid); | 120 LinuxDumper dumper(pid); |
| 71 | 121 |
| 72 char maps_path[256] = "dummymappath"; | 122 char maps_path[256] = "dummymappath"; |
| 73 char maps_path_expected[256]; | 123 char maps_path_expected[256]; |
| 74 snprintf(maps_path_expected, sizeof(maps_path_expected), | 124 snprintf(maps_path_expected, sizeof(maps_path_expected), |
| 75 "/proc/%d/maps", pid); | 125 "/proc/%d/maps", pid); |
| 76 dumper.BuildProcPath(maps_path, pid, "maps"); | 126 dumper.BuildProcPath(maps_path, pid, "maps"); |
| 77 ASSERT_STREQ(maps_path, maps_path_expected); | 127 ASSERT_STREQ(maps_path, maps_path_expected); |
| 78 | 128 |
| 79 // In release mode, we expect BuildProcPath to handle the invalid | 129 // In release mode, we expect BuildProcPath to handle the invalid |
| 80 // parameters correctly and fill map_path with an empty | 130 // parameters correctly and fill map_path with an empty |
| 81 // NULL-terminated string. | 131 // NULL-terminated string. |
| 82 #ifdef NDEBUG | 132 #ifdef NDEBUG |
| 83 snprintf(maps_path, sizeof(maps_path), "dummymappath"); | 133 snprintf(maps_path, sizeof(maps_path), "dummymappath"); |
| 84 dumper.BuildProcPath(maps_path, 0, "maps"); | 134 dumper.BuildProcPath(maps_path, 0, "maps"); |
| 85 EXPECT_STREQ(maps_path, ""); | 135 EXPECT_STREQ(maps_path, ""); |
| 86 | 136 |
| 87 snprintf(maps_path, sizeof(maps_path), "dummymappath"); | 137 snprintf(maps_path, sizeof(maps_path), "dummymappath"); |
| 88 dumper.BuildProcPath(maps_path, getpid(), ""); | 138 dumper.BuildProcPath(maps_path, getpid(), ""); |
| 89 EXPECT_STREQ(maps_path, ""); | 139 EXPECT_STREQ(maps_path, ""); |
| 90 | 140 |
| 91 snprintf(maps_path, sizeof(maps_path), "dummymappath"); | 141 snprintf(maps_path, sizeof(maps_path), "dummymappath"); |
| 92 dumper.BuildProcPath(maps_path, getpid(), NULL); | 142 dumper.BuildProcPath(maps_path, getpid(), NULL); |
| 93 EXPECT_STREQ(maps_path, ""); | 143 EXPECT_STREQ(maps_path, ""); |
| 94 #endif | 144 #endif |
| 95 } | 145 } |
| 96 | 146 |
| 147 #if !defined(__ARM_EABI__) | |
| 97 TEST(LinuxDumperTest, MappingsIncludeLinuxGate) { | 148 TEST(LinuxDumperTest, MappingsIncludeLinuxGate) { |
| 98 LinuxDumper dumper(getpid()); | 149 LinuxDumper dumper(getpid()); |
| 99 ASSERT_TRUE(dumper.Init()); | 150 ASSERT_TRUE(dumper.Init()); |
| 100 | 151 |
| 101 void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid()); | 152 void* linux_gate_loc = dumper.FindBeginningOfLinuxGateSharedLibrary(getpid()); |
| 102 if (linux_gate_loc) { | 153 ASSERT_TRUE(linux_gate_loc); |
| 103 bool found_linux_gate = false; | 154 bool found_linux_gate = false; |
| 104 | 155 |
| 105 const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); | 156 const wasteful_vector<MappingInfo*> mappings = dumper.mappings(); |
| 106 const MappingInfo* mapping; | 157 const MappingInfo* mapping; |
| 107 for (unsigned i = 0; i < mappings.size(); ++i) { | 158 for (unsigned i = 0; i < mappings.size(); ++i) { |
| 108 mapping = mappings[i]; | 159 mapping = mappings[i]; |
| 109 if (!strcmp(mapping->name, kLinuxGateLibraryName)) { | 160 if (!strcmp(mapping->name, kLinuxGateLibraryName)) { |
| 110 found_linux_gate = true; | 161 found_linux_gate = true; |
| 111 break; | 162 break; |
| 112 } | |
| 113 } | 163 } |
| 114 EXPECT_TRUE(found_linux_gate); | |
| 115 EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr)); | |
| 116 EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG)); | |
| 117 } | 164 } |
| 165 EXPECT_TRUE(found_linux_gate); | |
| 166 EXPECT_EQ(linux_gate_loc, reinterpret_cast<void*>(mapping->start_addr)); | |
| 167 EXPECT_EQ(0, memcmp(linux_gate_loc, ELFMAG, SELFMAG)); | |
| 118 } | 168 } |
| 169 #endif | |
| OLD | NEW |