OLD | NEW |
1 // Copyright (c) 2014 Google Inc. | 1 // Copyright (c) 2014 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 30 matching lines...) Expand all Loading... |
41 #include "common/scoped_ptr.h" | 41 #include "common/scoped_ptr.h" |
42 #include "common/tests/auto_tempdir.h" | 42 #include "common/tests/auto_tempdir.h" |
43 #include "common/using_std_string.h" | 43 #include "common/using_std_string.h" |
44 | 44 |
45 using namespace google_breakpad; | 45 using namespace google_breakpad; |
46 | 46 |
47 namespace { | 47 namespace { |
48 | 48 |
49 typedef testing::Test MicrodumpWriterTest; | 49 typedef testing::Test MicrodumpWriterTest; |
50 | 50 |
51 TEST(MicrodumpWriterTest, Setup) { | 51 void CrashAndGetMicrodump( |
| 52 const MappingList& mappings, |
| 53 const char* build_fingerprint, |
| 54 const char* product_info, |
| 55 scoped_array<char>* buf) { |
52 int fds[2]; | 56 int fds[2]; |
53 ASSERT_NE(-1, pipe(fds)); | 57 ASSERT_NE(-1, pipe(fds)); |
54 | 58 |
55 AutoTempDir temp_dir; | 59 AutoTempDir temp_dir; |
56 string stderr_file = temp_dir.path() + "/stderr.log"; | 60 string stderr_file = temp_dir.path() + "/stderr.log"; |
57 int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | 61 int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); |
58 ASSERT_NE(-1, err_fd); | 62 ASSERT_NE(-1, err_fd); |
59 | 63 |
60 const pid_t child = fork(); | 64 const pid_t child = fork(); |
61 if (child == 0) { | 65 if (child == 0) { |
62 close(fds[1]); | 66 close(fds[1]); |
63 char b; | 67 char b; |
64 IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); | 68 IGNORE_RET(HANDLE_EINTR(read(fds[0], &b, sizeof(b)))); |
65 close(fds[0]); | 69 close(fds[0]); |
66 syscall(__NR_exit); | 70 syscall(__NR_exit); |
67 } | 71 } |
68 close(fds[0]); | 72 close(fds[0]); |
69 | 73 |
70 ExceptionHandler::CrashContext context; | 74 ExceptionHandler::CrashContext context; |
71 memset(&context, 0, sizeof(context)); | 75 memset(&context, 0, sizeof(context)); |
72 | 76 |
73 // Set a non-zero tid to avoid tripping asserts. | 77 // Set a non-zero tid to avoid tripping asserts. |
74 context.tid = child; | 78 context.tid = child; |
75 | 79 |
| 80 // Redirect temporarily stderr to the stderr.log file. |
| 81 int save_err = dup(STDERR_FILENO); |
| 82 ASSERT_NE(-1, save_err); |
| 83 ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); |
| 84 |
| 85 ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, |
| 86 build_fingerprint, product_info)); |
| 87 |
| 88 // Revert stderr back to the console. |
| 89 dup2(save_err, STDERR_FILENO); |
| 90 close(save_err); |
| 91 |
| 92 // Read back the stderr file and check for the microdump marker. |
| 93 fsync(err_fd); |
| 94 lseek(err_fd, 0, SEEK_SET); |
| 95 const size_t kBufSize = 64 * 1024; |
| 96 buf->reset(new char[kBufSize]); |
| 97 ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); |
| 98 |
| 99 close(err_fd); |
| 100 close(fds[1]); |
| 101 |
| 102 ASSERT_NE(static_cast<char*>(0), strstr( |
| 103 buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); |
| 104 ASSERT_NE(static_cast<char*>(0), strstr( |
| 105 buf->get(), "-----END BREAKPAD MICRODUMP-----")); |
| 106 |
| 107 } |
| 108 |
| 109 TEST(MicrodumpWriterTest, BasicWithMappings) { |
76 // Push some extra mapping to check the MappingList logic. | 110 // Push some extra mapping to check the MappingList logic. |
77 const uint32_t memory_size = sysconf(_SC_PAGESIZE); | 111 const uint32_t memory_size = sysconf(_SC_PAGESIZE); |
78 const char* kMemoryName = "libfoo.so"; | 112 const char* kMemoryName = "libfoo.so"; |
79 const uint8_t kModuleGUID[sizeof(MDGUID)] = { | 113 const uint8_t kModuleGUID[sizeof(MDGUID)] = { |
80 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | 114 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
81 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF | 115 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF |
82 }; | 116 }; |
83 | 117 |
84 MappingInfo info; | 118 MappingInfo info; |
85 info.start_addr = memory_size; | 119 info.start_addr = memory_size; |
86 info.size = memory_size; | 120 info.size = memory_size; |
87 info.offset = 42; | 121 info.offset = 42; |
88 strcpy(info.name, kMemoryName); | 122 strcpy(info.name, kMemoryName); |
89 | 123 |
90 MappingList mappings; | 124 MappingList mappings; |
91 MappingEntry mapping; | 125 MappingEntry mapping; |
92 mapping.first = info; | 126 mapping.first = info; |
93 memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); | 127 memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); |
94 mappings.push_back(mapping); | 128 mappings.push_back(mapping); |
95 | 129 |
96 // Redirect temporarily stderr to the stderr.log file. | 130 scoped_array<char> buf; |
97 int save_err = dup(STDERR_FILENO); | 131 CrashAndGetMicrodump(mappings, NULL, NULL, &buf); |
98 ASSERT_NE(-1, save_err); | |
99 ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); | |
100 | |
101 ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings)); | |
102 | |
103 // Revert stderr back to the console. | |
104 dup2(save_err, STDERR_FILENO); | |
105 close(save_err); | |
106 | |
107 // Read back the stderr file and check for the microdump marker. | |
108 fsync(err_fd); | |
109 lseek(err_fd, 0, SEEK_SET); | |
110 const size_t kBufSize = 64 * 1024; | |
111 scoped_array<char> buf(new char[kBufSize]); | |
112 ASSERT_GT(read(err_fd, buf.get(), kBufSize), 0); | |
113 | |
114 ASSERT_NE(static_cast<char*>(0), strstr( | |
115 buf.get(), "-----BEGIN BREAKPAD MICRODUMP-----")); | |
116 ASSERT_NE(static_cast<char*>(0), strstr( | |
117 buf.get(), "-----END BREAKPAD MICRODUMP-----")); | |
118 | 132 |
119 #ifdef __LP64__ | 133 #ifdef __LP64__ |
120 ASSERT_NE(static_cast<char*>(0), strstr( | 134 ASSERT_NE(static_cast<char*>(0), strstr( |
121 buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " | 135 buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " |
122 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 136 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); |
123 #else | 137 #else |
124 ASSERT_NE(static_cast<char*>(0), strstr( | 138 ASSERT_NE(static_cast<char*>(0), strstr( |
125 buf.get(), "M 00001000 0000002A 00001000 " | 139 buf.get(), "M 00001000 0000002A 00001000 " |
126 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 140 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); |
127 #endif | 141 #endif |
128 | 142 |
129 close(err_fd); | 143 // In absence of a product info in the minidump, the writer should just write |
130 close(fds[1]); | 144 // an unknown marker. |
| 145 ASSERT_NE(static_cast<char*>(0), strstr( |
| 146 buf.get(), "V UNKNOWN:0.0.0.0")); |
| 147 } |
| 148 |
| 149 // Ensure that the product info and build fingerprint metadata show up in the |
| 150 // final microdump if present. |
| 151 TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { |
| 152 const char kProductInfo[] = "MockProduct:42.0.2311.99"; |
| 153 const char kBuildFingerprint[] = |
| 154 "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; |
| 155 scoped_array<char> buf; |
| 156 MappingList no_mappings; |
| 157 |
| 158 CrashAndGetMicrodump(no_mappings, kBuildFingerprint, kProductInfo, &buf); |
| 159 |
| 160 ASSERT_NE(static_cast<char*>(0), strstr(buf.get(), kBuildFingerprint)); |
| 161 ASSERT_NE(static_cast<char*>(0), strstr(buf.get(), kProductInfo)); |
131 } | 162 } |
132 | 163 |
133 } // namespace | 164 } // namespace |
OLD | NEW |