 Chromium Code Reviews
 Chromium Code Reviews Issue 1334473003:
  Add GPU fingerprint information to breakpad microdumps.  (Closed) 
  Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master
    
  
    Issue 1334473003:
  Add GPU fingerprint information to breakpad microdumps.  (Closed) 
  Base URL: https://chromium.googlesource.com/breakpad/breakpad.git@master| 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 | 
| 53 void CrashAndGetMicrodump( | 54 void CrashAndGetMicrodump( | 
| 54 const MappingList& mappings, | 55 const MappingList& mappings, | 
| 55 const char* build_fingerprint, | 56 const MicrodumpExtraInfo µdump_extra_info, | 
| 56 const char* product_info, | |
| 57 scoped_array<char>* buf) { | 57 scoped_array<char>* buf) { | 
| 58 int fds[2]; | 58 int fds[2]; | 
| 59 ASSERT_NE(-1, pipe(fds)); | 59 ASSERT_NE(-1, pipe(fds)); | 
| 60 | 60 | 
| 61 AutoTempDir temp_dir; | 61 AutoTempDir temp_dir; | 
| 62 string stderr_file = temp_dir.path() + "/stderr.log"; | 62 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); | 63 int err_fd = open(stderr_file.c_str(), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); | 
| 64 ASSERT_NE(-1, err_fd); | 64 ASSERT_NE(-1, err_fd); | 
| 65 | 65 | 
| 66 const pid_t child = fork(); | 66 const pid_t child = fork(); | 
| (...skipping 11 matching lines...) Expand all Loading... | |
| 78 | 78 | 
| 79 // Set a non-zero tid to avoid tripping asserts. | 79 // Set a non-zero tid to avoid tripping asserts. | 
| 80 context.tid = child; | 80 context.tid = child; | 
| 81 | 81 | 
| 82 // Redirect temporarily stderr to the stderr.log file. | 82 // Redirect temporarily stderr to the stderr.log file. | 
| 83 int save_err = dup(STDERR_FILENO); | 83 int save_err = dup(STDERR_FILENO); | 
| 84 ASSERT_NE(-1, save_err); | 84 ASSERT_NE(-1, save_err); | 
| 85 ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); | 85 ASSERT_NE(-1, dup2(err_fd, STDERR_FILENO)); | 
| 86 | 86 | 
| 87 ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, | 87 ASSERT_TRUE(WriteMicrodump(child, &context, sizeof(context), mappings, | 
| 88 build_fingerprint, product_info)); | 88 microdump_extra_info)); | 
| 89 | 89 | 
| 90 // Revert stderr back to the console. | 90 // Revert stderr back to the console. | 
| 91 dup2(save_err, STDERR_FILENO); | 91 dup2(save_err, STDERR_FILENO); | 
| 92 close(save_err); | 92 close(save_err); | 
| 93 | 93 | 
| 94 // Read back the stderr file and check for the microdump marker. | 94 // Read back the stderr file and check for the microdump marker. | 
| 95 fsync(err_fd); | 95 fsync(err_fd); | 
| 96 lseek(err_fd, 0, SEEK_SET); | 96 lseek(err_fd, 0, SEEK_SET); | 
| 97 const size_t kBufSize = 64 * 1024; | 97 const size_t kBufSize = 64 * 1024; | 
| 98 buf->reset(new char[kBufSize]); | 98 buf->reset(new char[kBufSize]); | 
| 99 ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); | 99 ASSERT_GT(read(err_fd, buf->get(), kBufSize), 0); | 
| 100 | 100 | 
| 101 close(err_fd); | 101 close(err_fd); | 
| 102 close(fds[1]); | 102 close(fds[1]); | 
| 103 | 103 | 
| 104 ASSERT_NE(static_cast<char*>(0), strstr( | 104 ASSERT_NE(static_cast<char*>(0), strstr( | 
| 105 buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); | 105 buf->get(), "-----BEGIN BREAKPAD MICRODUMP-----")); | 
| 106 ASSERT_NE(static_cast<char*>(0), strstr( | 106 ASSERT_NE(static_cast<char*>(0), strstr( | 
| 107 buf->get(), "-----END BREAKPAD MICRODUMP-----")); | 107 buf->get(), "-----END BREAKPAD MICRODUMP-----")); | 
| 108 } | 108 } | 
| 109 | 109 | 
| 110 void CheckMicrodumpContents(const string µdum_content, | 110 void CheckMicrodumpContents(const string& microdump_content, | 
| 111 const string &expected_fingerprint, | 111 const MicrodumpExtraInfo &expected_info) { | 
| 112 const string &expected_product_info) { | 112 std::istringstream iss(microdump_content); | 
| 113 std::istringstream iss(microdum_content); | |
| 114 bool did_find_os_info = false; | 113 bool did_find_os_info = false; | 
| 115 bool did_find_product_info = false; | 114 bool did_find_product_info = false; | 
| 115 bool did_find_gpu_info = false; | |
| 116 for (string line; std::getline(iss, line);) { | 116 for (string line; std::getline(iss, line);) { | 
| 117 if (line.find("O ") == 0) { | 117 if (line.find("O ") == 0) { | 
| 118 std::istringstream os_info_tokens(line); | 118 std::istringstream os_info_tokens(line); | 
| 119 string token; | 119 string token; | 
| 120 os_info_tokens.ignore(2); // Ignore the "O " preamble. | 120 os_info_tokens.ignore(2); // Ignore the "O " preamble. | 
| 121 // Check the OS descriptor char (L=Linux, A=Android). | 121 // Check the OS descriptor char (L=Linux, A=Android). | 
| 122 os_info_tokens >> token; | 122 os_info_tokens >> token; | 
| 123 ASSERT_TRUE(token == "L" || token == "A"); | 123 ASSERT_TRUE(token == "L" || token == "A"); | 
| 124 | 124 | 
| 125 os_info_tokens >> token; // HW architecture. | 125 os_info_tokens >> token; // HW architecture. | 
| 126 os_info_tokens >> token; // Number of cpus. | 126 os_info_tokens >> token; // Number of cpus. | 
| 127 for (size_t i = 0; i < token.size(); ++i) | 127 for (size_t i = 0; i < token.size(); ++i) | 
| 128 ASSERT_TRUE(isxdigit(token[i])); | 128 ASSERT_TRUE(isxdigit(token[i])); | 
| 129 os_info_tokens >> token; // SW architecture. | 129 os_info_tokens >> token; // SW architecture. | 
| 130 | 130 | 
| 131 // Check that the build fingerprint is in the right place. | 131 // Check that the build fingerprint is in the right place. | 
| 132 os_info_tokens >> token; | 132 os_info_tokens >> token; | 
| 133 ASSERT_EQ(expected_fingerprint, token); | 133 if (expected_info.build_fingerprint) | 
| 134 ASSERT_EQ(expected_info.build_fingerprint, token); | |
| 134 did_find_os_info = true; | 135 did_find_os_info = true; | 
| 135 } else if (line.find("V ") == 0) { | 136 } else if (line.find("V ") == 0) { | 
| 136 ASSERT_EQ("V " + expected_product_info, line); | 137 if (expected_info.product_info) | 
| 138 ASSERT_EQ(string("V ") + expected_info.product_info, line); | |
| 137 did_find_product_info = true; | 139 did_find_product_info = true; | 
| 140 } else if (line.find("G ") == 0) { | |
| 141 if (expected_info.gpu_fingerprint) | |
| 142 ASSERT_EQ(string("G ") + expected_info.gpu_fingerprint, line); | |
| 143 did_find_gpu_info = true; | |
| 138 } | 144 } | 
| 139 } | 145 } | 
| 140 ASSERT_TRUE(did_find_os_info); | 146 ASSERT_TRUE(did_find_os_info); | 
| 141 ASSERT_TRUE(did_find_product_info); | 147 ASSERT_TRUE(did_find_product_info); | 
| 148 ASSERT_TRUE(did_find_gpu_info); | |
| 149 } | |
| 150 | |
| 151 void CheckMicrodumpContents(const string& microdump_content, | |
| 152 const string& expected_fingerprint, | |
| 153 const string& expected_product_info, | |
| 154 const string& expected_gpu_fingerprint) { | |
| 155 CheckMicrodumpContents(microdump_content, | |
| 156 MicrodumpExtraInfo(expected_fingerprint.c_str(), | |
| 157 expected_product_info.c_str(), | |
| 158 expected_gpu_fingerprint.c_str())); | |
| 142 } | 159 } | 
| 143 | 160 | 
| 144 TEST(MicrodumpWriterTest, BasicWithMappings) { | 161 TEST(MicrodumpWriterTest, BasicWithMappings) { | 
| 145 // Push some extra mapping to check the MappingList logic. | 162 // Push some extra mapping to check the MappingList logic. | 
| 146 const uint32_t memory_size = sysconf(_SC_PAGESIZE); | 163 const uint32_t memory_size = sysconf(_SC_PAGESIZE); | 
| 147 const char* kMemoryName = "libfoo.so"; | 164 const char* kMemoryName = "libfoo.so"; | 
| 148 const uint8_t kModuleGUID[sizeof(MDGUID)] = { | 165 const uint8_t kModuleGUID[sizeof(MDGUID)] = { | 
| 149 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | 166 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, | 
| 150 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF | 167 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF | 
| 151 }; | 168 }; | 
| 152 | 169 | 
| 153 MappingInfo info; | 170 MappingInfo info; | 
| 154 info.start_addr = memory_size; | 171 info.start_addr = memory_size; | 
| 155 info.size = memory_size; | 172 info.size = memory_size; | 
| 156 info.offset = 42; | 173 info.offset = 42; | 
| 157 strcpy(info.name, kMemoryName); | 174 strcpy(info.name, kMemoryName); | 
| 158 | 175 | 
| 159 MappingList mappings; | 176 MappingList mappings; | 
| 160 MappingEntry mapping; | 177 MappingEntry mapping; | 
| 161 mapping.first = info; | 178 mapping.first = info; | 
| 162 memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); | 179 memcpy(mapping.second, kModuleGUID, sizeof(MDGUID)); | 
| 163 mappings.push_back(mapping); | 180 mappings.push_back(mapping); | 
| 164 | 181 | 
| 165 scoped_array<char> buf; | 182 scoped_array<char> buf; | 
| 166 CrashAndGetMicrodump(mappings, NULL, NULL, &buf); | 183 CrashAndGetMicrodump(mappings, MicrodumpExtraInfo(), &buf); | 
| 167 | 184 | 
| 168 #ifdef __LP64__ | 185 #ifdef __LP64__ | 
| 169 ASSERT_NE(static_cast<char*>(0), strstr( | 186 ASSERT_NE(static_cast<char*>(0), strstr( | 
| 170 buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " | 187 buf.get(), "M 0000000000001000 000000000000002A 0000000000001000 " | 
| 171 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 188 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 
| 172 #else | 189 #else | 
| 173 ASSERT_NE(static_cast<char*>(0), strstr( | 190 ASSERT_NE(static_cast<char*>(0), strstr( | 
| 174 buf.get(), "M 00001000 0000002A 00001000 " | 191 buf.get(), "M 00001000 0000002A 00001000 " | 
| 175 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 192 "33221100554477668899AABBCCDDEEFF0 libfoo.so")); | 
| 176 #endif | 193 #endif | 
| 177 | 194 | 
| 178 // In absence of a product info in the minidump, the writer should just write | 195 // In absence of a product info in the minidump, the writer should just write | 
| 179 // an unknown marker. | 196 // an unknown marker. | 
| 180 ASSERT_NE(static_cast<char*>(0), strstr( | 197 ASSERT_NE(static_cast<char*>(0), strstr( | 
| 181 buf.get(), "V UNKNOWN:0.0.0.0")); | 198 buf.get(), "V UNKNOWN:0.0.0.0")); | 
| 182 } | 199 } | 
| 183 | 200 | 
| 184 // Ensure that the product info and build fingerprint metadata show up in the | 201 // Ensure that the product info and build fingerprint metadata show up in the | 
| 185 // final microdump if present. | 202 // final microdump if present. | 
| 186 TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { | 203 TEST(MicrodumpWriterTest, BuildFingerprintAndProductInfo) { | 
| 187 const char kProductInfo[] = "MockProduct:42.0.2311.99"; | 204 const char kProductInfo[] = "MockProduct:42.0.2311.99"; | 
| 188 const char kBuildFingerprint[] = | 205 const char kBuildFingerprint[] = | 
| 189 "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; | 206 "aosp/occam/mako:5.1.1/LMY47W/12345678:userdegbug/dev-keys"; | 
| 207 const char kGPUFingerprint[] = | |
| 208 "Qualcomm;Adreno (TM) 330;OpenGL ES 3.0 V@104.0 AU@ (GIT@Id3510ff6dc)"; | |
| 209 const MicrodumpExtraInfo kMicrodumpExtraInfo( | |
| 210 kBuildFingerprint, kProductInfo, kGPUFingerprint); | |
| 190 scoped_array<char> buf; | 211 scoped_array<char> buf; | 
| 191 MappingList no_mappings; | 212 MappingList no_mappings; | 
| 192 | 213 | 
| 193 CrashAndGetMicrodump(no_mappings, kBuildFingerprint, kProductInfo, &buf); | 214 CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfo, &buf); | 
| 194 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, kProductInfo); | 215 CheckMicrodumpContents(string(buf.get()), kMicrodumpExtraInfo); | 
| 195 } | 216 } | 
| 196 | 217 | 
| 197 TEST(MicrodumpWriterTest, NoProductInfo) { | 218 TEST(MicrodumpWriterTest, NoProductInfo) { | 
| 198 const char kBuildFingerprint[] = "foobar"; | 219 const char kBuildFingerprint[] = "foobar"; | 
| 220 const char kGPUFingerprint[] = "bazqux"; | |
| 
Primiano Tucci (use gerrit)
2015/09/10 12:38:58
you probably want to check here that GPUfinerprint
 
Tobias Sargeant
2015/09/10 13:18:39
Done.
 | |
| 199 scoped_array<char> buf; | 221 scoped_array<char> buf; | 
| 200 MappingList no_mappings; | 222 MappingList no_mappings; | 
| 201 | 223 | 
| 202 CrashAndGetMicrodump(no_mappings, kBuildFingerprint, NULL, &buf); | 224 const MicrodumpExtraInfo kMicrodumpExtraInfoNoProductInfo( | 
| 203 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, "UNKNOWN:0.0.0.0" ); | 225 kBuildFingerprint, NULL, kGPUFingerprint); | 
| 226 | |
| 227 CrashAndGetMicrodump(no_mappings, kMicrodumpExtraInfoNoProductInfo, &buf); | |
| 228 CheckMicrodumpContents(string(buf.get()), kBuildFingerprint, | |
| 229 "UNKNOWN:0.0.0.0", kGPUFingerprint); | |
| 204 } | 230 } | 
| 205 } // namespace | 231 } // namespace | 
| OLD | NEW |