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 19 matching lines...) Expand all Loading... |
30 #include <ctype.h> | 30 #include <ctype.h> |
31 #include <sys/syscall.h> | 31 #include <sys/syscall.h> |
32 #include <sys/types.h> | 32 #include <sys/types.h> |
33 #include <unistd.h> | 33 #include <unistd.h> |
34 | 34 |
35 #include <sstream> | 35 #include <sstream> |
36 #include <string> | 36 #include <string> |
37 | 37 |
38 #include "breakpad_googletest_includes.h" | 38 #include "breakpad_googletest_includes.h" |
39 #include "client/linux/handler/exception_handler.h" | 39 #include "client/linux/handler/exception_handler.h" |
| 40 #include "client/linux/handler/microdump_extra_info.h" |
40 #include "client/linux/microdump_writer/microdump_writer.h" | 41 #include "client/linux/microdump_writer/microdump_writer.h" |
41 #include "common/linux/eintr_wrapper.h" | 42 #include "common/linux/eintr_wrapper.h" |
42 #include "common/linux/ignore_ret.h" | 43 #include "common/linux/ignore_ret.h" |
43 #include "common/scoped_ptr.h" | 44 #include "common/scoped_ptr.h" |
44 #include "common/tests/auto_tempdir.h" | 45 #include "common/tests/auto_tempdir.h" |
45 #include "common/using_std_string.h" | 46 #include "common/using_std_string.h" |
46 | 47 |
47 using namespace google_breakpad; | 48 using namespace google_breakpad; |
48 | 49 |
49 namespace { | 50 namespace { |
50 | 51 |
51 typedef testing::Test MicrodumpWriterTest; | 52 typedef testing::Test MicrodumpWriterTest; |
52 | 53 |
| 54 MicrodumpExtraInfo MakeMicrodumpExtraInfo( |
| 55 const char* build_fingerprint, |
| 56 const char* product_info, |
| 57 const char* gpu_fingerprint) { |
| 58 MicrodumpExtraInfo info; |
| 59 info.build_fingerprint = build_fingerprint; |
| 60 info.product_info = product_info; |
| 61 info.gpu_fingerprint = gpu_fingerprint; |
| 62 return info; |
| 63 } |
| 64 |
53 void CrashAndGetMicrodump( | 65 void CrashAndGetMicrodump( |
54 const MappingList& mappings, | 66 const MappingList& mappings, |
55 const char* build_fingerprint, | 67 const MicrodumpExtraInfo& microdump_extra_info, |
56 const char* product_info, | |
57 scoped_array<char>* buf) { | 68 scoped_array<char>* buf) { |
58 int fds[2]; | 69 int fds[2]; |
59 ASSERT_NE(-1, pipe(fds)); | 70 ASSERT_NE(-1, pipe(fds)); |
60 | 71 |
61 AutoTempDir temp_dir; | 72 AutoTempDir temp_dir; |
62 string stderr_file = temp_dir.path() + "/stderr.log"; | 73 string stderr_file = temp_dir.path() + "/stderr.log"; |
63 int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | 74 int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); |
64 ASSERT_NE(-1, err_fd); | 75 ASSERT_NE(-1, err_fd); |
65 | 76 |
66 const pid_t child = fork(); | 77 const pid_t child = fork(); |
(...skipping 11 matching lines...) Expand all Loading... |
78 | 89 |
79 // Set a non-zero tid to avoid tripping asserts. | 90 // Set a non-zero tid to avoid tripping asserts. |
80 context.tid = child; | 91 context.tid = child; |
81 | 92 |
82 // Redirect temporarily stderr to the stderr.log file. | 93 // Redirect temporarily stderr to the stderr.log file. |
83 int save_err = dup(STDERR_FILENO); | 94 int save_err = dup(STDERR_FILENO); |
84 ASSERT_NE(-1, save_err); | 95 ASSERT_NE(-1, save_err); |
85 ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); | 96 ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); |
86 | 97 |
87 ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, | 98 ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, |
88 build_fingerprint, product_info)); | 99 microdump_extra_info)); |
89 | 100 |
90 // Revert stderr back to the console. | 101 // Revert stderr back to the console. |
91 dup2(save_err, STDERR_FILENO); | 102 dup2(save_err, STDERR_FILENO); |
92 close(save_err); | 103 close(save_err); |
93 | 104 |
94 // Read back the stderr file and check for the microdump marker. | 105 // Read back the stderr file and check for the microdump marker. |
95 fsync(err_fd); | 106 fsync(err_fd); |
96 lseek(err_fd, 0, SEEK_SET); | 107 lseek(err_fd, 0, SEEK_SET); |
97 const size_t kBufSize = 64 * 1024; | 108 const size_t kBufSize = 64 * 1024; |
98 buf->reset(new char[kBufSize]); | 109 buf->reset(new char[kBufSize]); |
99 ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); | 110 ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); |
100 | 111 |
101 close(err_fd); | 112 close(err_fd); |
102 close(fds[1]); | 113 close(fds[1]); |
103 | 114 |
104 ASSERT_NE(static_cast<char*>(0), strstr( | 115 ASSERT_NE(static_cast<char*>(0), strstr( |
105 buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); | 116 buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); |
106 ASSERT_NE(static_cast<char*>(0), strstr( | 117 ASSERT_NE(static_cast<char*>(0), strstr( |
107 buf->get(), "-----END BREAKPAD MICRODUMP-----")); | 118 buf->get(), "-----END BREAKPAD MICRODUMP-----")); |
108 } | 119 } |
109 | 120 |
110 void CheckMicrodumpContents(const string µdum_content, | 121 void CheckMicrodumpContents(const string& microdump_content, |
111 const string &expected_fingerprint, | 122 const MicrodumpExtraInfo& expected_info) { |
112 const string &expected_product_info) { | 123 std::istringstream iss(microdump_content); |
113 std::istringstream iss(microdum_content); | |
114 bool did_find_os_info = false; | 124 bool did_find_os_info = false; |
115 bool did_find_product_info = false; | 125 bool did_find_product_info = false; |
| 126 bool did_find_gpu_info = false; |
116 for (string line; std::getline(iss, line);) { | 127 for (string line; std::getline(iss, line);) { |
117 if (line.find("O ") == 0) { | 128 if (line.find("O ") == 0) { |
118 std::istringstream os_info_tokens(line); | 129 std::istringstream os_info_tokens(line); |
119 string token; | 130 string token; |
120 os_info_tokens.ignore(2); // Ignore the "O " preamble. | 131 os_info_tokens.ignore(2); // Ignore the "O " preamble. |
121 // Check the OS descriptor char (L=Linux, A=Android). | 132 // Check the OS descriptor char (L=Linux, A=Android). |
122 os_info_tokens >> token; | 133 os_info_tokens >> token; |
123 ASSERT_TRUE(token == "L" || token == "A"); | 134 ASSERT_TRUE(token == "L" || token == "A"); |
124 | 135 |
125 os_info_tokens >> token; // HW architecture. | 136 os_info_tokens >> token; // HW architecture. |
126 os_info_tokens >> token; // Number of cpus. | 137 os_info_tokens >> token; // Number of cpus. |
127 for (size_t i = 0; i < token.size(); ++i) | 138 for (size_t i = 0; i < token.size(); ++i) |
128 ASSERT_TRUE(isxdigit(token[i])); | 139 ASSERT_TRUE(isxdigit(token[i])); |
129 os_info_tokens >> token; // SW architecture. | 140 os_info_tokens >> token; // SW architecture. |
130 | 141 |
131 // Check that the build fingerprint is in the right place. | 142 // Check that the build fingerprint is in the right place. |
132 os_info_tokens >> token; | 143 os_info_tokens >> token; |
133 ASSERT_EQ(expected_fingerprint, token); | 144 if (expected_info.build_fingerprint) |
| 145 ASSERT_EQ(expected_info.build_fingerprint, token); |
134 did_find_os_info = true; | 146 did_find_os_info = true; |
135 } else if (line.find("V ") == 0) { | 147 } else if (line.find("V ") == 0) { |
136 ASSERT_EQ("V " + expected_product_info, line); | 148 if (expected_info.product_info) |
| 149 ASSERT_EQ(string("V ") + expected_info.product_info, line); |
137 did_find_product_info = true; | 150 did_find_product_info = true; |
| 151 } else if (line.find("G ") == 0) { |
| 152 if (expected_info.gpu_fingerprint) |
| 153 ASSERT_EQ(string("G ") + expected_info.gpu_fingerprint, line); |
| 154 did_find_gpu_info = true; |
138 } | 155 } |
139 } | 156 } |
140 ASSERT_TRUE(did_find_os_info); | 157 ASSERT_TRUE(did_find_os_info); |
141 ASSERT_TRUE(did_find_product_info); | 158 ASSERT_TRUE(did_find_product_info); |
| 159 ASSERT_TRUE(did_find_gpu_info); |
| 160 } |
| 161 |
| 162 void CheckMicrodumpContents(const string& microdump_content, |
| 163 const string& expected_fingerprint, |
| 164 const string& expected_product_info, |
| 165 const string& expected_gpu_fingerprint) { |
| 166 CheckMicrodumpContents( |
| 167 microdump_content, |
| 168 MakeMicrodumpExtraInfo(expected_fingerprint.c_str(), |
| 169 expected_product_info.c_str(), |
| 170 expected_gpu_fingerprint.c_str())); |
142 } | 171 } |
143 | 172 |
144 TEST(MicrodumpWriterTest, BasicWithMappings) { | 173 TEST(MicrodumpWriterTest, BasicWithMappings) { |
145 // Push some extra mapping to check the MappingList logic. | 174 // Push some extra mapping to check the MappingList logic. |
146 const uint32_t memory_size = sysconf(_SC_PAGESIZE); | 175 const uint32_t memory_size = sysconf(_SC_PAGESIZE); |
147 const char* kMemoryName = "libfoo.so"; | 176 const char* kMemoryName = "libfoo.so"; |
148 const uint8_t kModuleGUID[sizeof(MDGUID)] = { | 177 const uint8_t kModuleGUID[sizeof(MDGUID)] = { |
149 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | 178 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, |
150 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF | 179 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF |
151 }; | 180 }; |
152 | 181 |
153 MappingInfo info; | 182 MappingInfo info; |
154 info.start_addr = memory_size; | 183 info.start_addr = memory_size; |
155 info.size = memory_size; | 184 info.size = memory_size; |
156 info.offset = 42; | 185 info.offset = 42; |
157 strcpy(info.name, kMemoryName); | 186 strcpy(info.name, kMemoryName); |
158 | 187 |
159 MappingList mappings; | 188 MappingList mappings; |
160 MappingEntry mapping; | 189 MappingEntry mapping; |
161 mapping.first = info; | 190 mapping.first = info; |
162 memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); | 191 memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); |
163 mappings.push_back(mapping); | 192 mappings.push_back(mapping); |
164 | 193 |
165 scoped_array<char> buf; | 194 scoped_array<char> buf; |
166 CrashAndGetMicrodump(mappings, NULL, NULL, &buf); | 195 CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf); |
167 | 196 |
168 #ifdef __LP64__ | 197 #ifdef __LP64__ |
169 ASSERT_NE(static_cast<char*>(0), strstr( | 198 ASSERT_NE(static_cast<char*>(0), strstr( |
170 buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " | 199 buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " |
171 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 200 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); |
172 #else | 201 #else |
173 ASSERT_NE(static_cast<char*>(0), strstr( | 202 ASSERT_NE(static_cast<char*>(0), strstr( |
174 buf.get(), "M 00001000 0000002A 00001000 " | 203 buf.get(), "M 00001000 0000002A 00001000 " |
175 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 204 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); |
176 #endif | 205 #endif |
177 | 206 |
178 // In absence of a product info in the minidump, the writer should just write | 207 // In absence of a product info in the minidump, the writer should just write |
179 // an unknown marker. | 208 // an unknown marker. |
180 ASSERT_NE(static_cast<char*>(0), strstr( | 209 ASSERT_NE(static_cast<char*>(0), strstr( |
181 buf.get(), "V UNKNOWN:0.0.0.0")); | 210 buf.get(), "V UNKNOWN:0.0.0.0")); |
182 } | 211 } |
183 | 212 |
184 // Ensure that the product info and build fingerprint metadata show up in the | 213 // Ensure that the product info and build fingerprint metadata show up in the |
185 // final microdump if present. | 214 // final microdump if present. |
186 TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { | 215 TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { |
187 const char kProductInfo[] = "MockProduct:42.0.2311.99"; | 216 const char kProductInfo[] = "MockProduct:42.0.2311.99"; |
188 const char kBuildFingerprint[] = | 217 const char kBuildFingerprint[] = |
189 "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; | 218 "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; |
| 219 const char kGPUFingerprint[] = |
| 220 "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; |
| 221 const MicrodumpExtraInfo kMicrodumpExtraInfo( |
| 222 MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, kGPUFingerprint)); |
190 scoped_array<char> buf; | 223 scoped_array<char> buf; |
191 MappingList no_mappings; | 224 MappingList no_mappings; |
192 | 225 |
193 CrashAndGetMicrodump(no_mappings, kBuildFingerprint, kProductInfo, &buf); | 226 CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); |
194 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, kProductInfo); | 227 CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo); |
195 } | 228 } |
196 | 229 |
197 TEST(MicrodumpWriterTest, NoProductInfo) { | 230 TEST(MicrodumpWriterTest, NoProductInfo) { |
198 const char kBuildFingerprint[] = "foobar"; | 231 const char kBuildFingerprint[] = "foobar"; |
| 232 const char kGPUFingerprint[] = "bazqux"; |
199 scoped_array<char> buf; | 233 scoped_array<char> buf; |
200 MappingList no_mappings; | 234 MappingList no_mappings; |
201 | 235 |
202 CrashAndGetMicrodump(no_mappings, kBuildFingerprint, NULL, &buf); | 236 const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo( |
203 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, "UNKNOWN:0.0.0.0"
); | 237 MakeMicrodumpExtraInfo(kBuildFingerprint, NULL, kGPUFingerprint)); |
| 238 |
| 239 CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf); |
| 240 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, |
| 241 "UNKNOWN:0.0.0.0", kGPUFingerprint); |
| 242 } |
| 243 |
| 244 TEST(MicrodumpWriterTest, NoGPUInfo) { |
| 245 const char kProductInfo[] = "bazqux"; |
| 246 const char kBuildFingerprint[] = "foobar"; |
| 247 scoped_array<char> buf; |
| 248 MappingList no_mappings; |
| 249 |
| 250 const MicrodumpExtraInfo kMicrodumpExtraInfoNoGPUInfo( |
| 251 MakeMicrodumpExtraInfo(kBuildFingerprint, kProductInfo, NULL)); |
| 252 |
| 253 CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoGPUInfo, &buf); |
| 254 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, |
| 255 kProductInfo, "UNKNOWN"); |
204 } | 256 } |
205 } // namespace | 257 } // namespace |
OLD | NEW |