| OLD | NEW |
| 1 // Copyright 2014 The Crashpad Authors. All rights reserved. | 1 // Copyright 2014 The Crashpad Authors. All rights reserved. |
| 2 // | 2 // |
| 3 // Licensed under the Apache License, Version 2.0 (the "License"); | 3 // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 // you may not use this file except in compliance with the License. | 4 // you may not use this file except in compliance with the License. |
| 5 // You may obtain a copy of the License at | 5 // You may obtain a copy of the License at |
| 6 // | 6 // |
| 7 // http://www.apache.org/licenses/LICENSE-2.0 | 7 // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 // | 8 // |
| 9 // Unless required by applicable law or agreed to in writing, software | 9 // Unless required by applicable law or agreed to in writing, software |
| 10 // distributed under the License is distributed on an "AS IS" BASIS, | 10 // distributed under the License is distributed on an "AS IS" BASIS, |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 52 #include "handler/mac/exception_handler_server.h" | 52 #include "handler/mac/exception_handler_server.h" |
| 53 #include "util/mach/child_port_handshake.h" | 53 #include "util/mach/child_port_handshake.h" |
| 54 #include "util/mach/mach_extensions.h" | 54 #include "util/mach/mach_extensions.h" |
| 55 #include "util/posix/close_stdio.h" | 55 #include "util/posix/close_stdio.h" |
| 56 #elif defined(OS_WIN) | 56 #elif defined(OS_WIN) |
| 57 #include <windows.h> | 57 #include <windows.h> |
| 58 | 58 |
| 59 #include "handler/win/crash_report_exception_handler.h" | 59 #include "handler/win/crash_report_exception_handler.h" |
| 60 #include "util/win/exception_handler_server.h" | 60 #include "util/win/exception_handler_server.h" |
| 61 #include "util/win/handle.h" | 61 #include "util/win/handle.h" |
| 62 #include "util/win/initial_client_data.h" |
| 62 #endif // OS_MACOSX | 63 #endif // OS_MACOSX |
| 63 | 64 |
| 64 namespace crashpad { | 65 namespace crashpad { |
| 65 | 66 |
| 66 namespace { | 67 namespace { |
| 67 | 68 |
| 68 void Usage(const base::FilePath& me) { | 69 void Usage(const base::FilePath& me) { |
| 69 fprintf(stderr, | 70 fprintf(stderr, |
| 70 "Usage: %" PRFilePath " [OPTION]...\n" | 71 "Usage: %" PRFilePath " [OPTION]...\n" |
| 71 "Crashpad's exception handler server.\n" | 72 "Crashpad's exception handler server.\n" |
| 72 "\n" | 73 "\n" |
| 73 " --annotation=KEY=VALUE set a process annotation in each crash report\n" | 74 " --annotation=KEY=VALUE set a process annotation in each crash report\n" |
| 74 " --database=PATH store the crash report database at PATH\n" | 75 " --database=PATH store the crash report database at PATH\n" |
| 75 #if defined(OS_MACOSX) | 76 #if defined(OS_MACOSX) |
| 76 " --handshake-fd=FD establish communication with the client over FD\n
" | 77 " --handshake-fd=FD establish communication with the client over FD\n
" |
| 77 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" | 78 " --mach-service=SERVICE register SERVICE with the bootstrap server\n" |
| 78 #elif defined(OS_WIN) | 79 #elif defined(OS_WIN) |
| 79 " --handshake-handle=HANDLE\n" | 80 " --initial-client-data=HANDLE_request_crash_dump,\n" |
| 80 " create a new pipe and send its name via HANDLE\n" | 81 " HANDLE_request_non_crash_dump,\n" |
| 82 " HANDLE_non_crash_dump_completed,\n" |
| 83 " HANDLE_pipe,\n" |
| 84 " HANDLE_client_process,\n" |
| 85 " Address_crash_exception_information,\n" |
| 86 " Address_non_crash_exception_information,\n" |
| 87 " Address_debug_critical_section\n" |
| 88 " use precreated data to register initial client\n" |
| 81 #endif // OS_MACOSX | 89 #endif // OS_MACOSX |
| 82 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" | 90 " --metrics-dir=DIR store metrics files in DIR (only in Chromium)\n" |
| 83 " --no-rate-limit don't rate limit crash uploads\n" | 91 " --no-rate-limit don't rate limit crash uploads\n" |
| 84 #if defined(OS_MACOSX) | 92 #if defined(OS_MACOSX) |
| 85 " --reset-own-crash-exception-port-to-system-default\n" | 93 " --reset-own-crash-exception-port-to-system-default\n" |
| 86 " reset the server's exception handler to default\n
" | 94 " reset the server's exception handler to default\n
" |
| 87 #elif defined(OS_WIN) | 95 #elif defined(OS_WIN) |
| 88 " --pipe-name=PIPE communicate with the client over PIPE\n" | 96 " --pipe-name=PIPE communicate with the client over PIPE\n" |
| 89 #endif // OS_MACOSX | 97 #endif // OS_MACOSX |
| 90 " --url=URL send crash reports to this Breakpad server URL,\n
" | 98 " --url=URL send crash reports to this Breakpad server URL,\n
" |
| (...skipping 27 matching lines...) Expand all Loading... |
| 118 g_exception_handler_server->Stop(); | 126 g_exception_handler_server->Stop(); |
| 119 } | 127 } |
| 120 | 128 |
| 121 #endif // OS_MACOSX | 129 #endif // OS_MACOSX |
| 122 | 130 |
| 123 #if defined(OS_WIN) | 131 #if defined(OS_WIN) |
| 124 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { | 132 LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* exception_pointers) { |
| 125 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); | 133 Metrics::HandlerCrashed(exception_pointers->ExceptionRecord->ExceptionCode); |
| 126 return EXCEPTION_CONTINUE_SEARCH; | 134 return EXCEPTION_CONTINUE_SEARCH; |
| 127 } | 135 } |
| 128 #endif | 136 #endif // OS_WIN |
| 129 | 137 |
| 130 } // namespace | 138 } // namespace |
| 131 | 139 |
| 132 int HandlerMain(int argc, char* argv[]) { | 140 int HandlerMain(int argc, char* argv[]) { |
| 133 #if defined(OS_WIN) | 141 #if defined(OS_WIN) |
| 134 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); | 142 SetUnhandledExceptionFilter(&UnhandledExceptionHandler); |
| 135 #endif | 143 #endif |
| 136 | 144 |
| 137 const base::FilePath argv0( | 145 const base::FilePath argv0( |
| 138 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); | 146 ToolSupport::CommandLineArgumentToFilePathStringType(argv[0])); |
| 139 const base::FilePath me(argv0.BaseName()); | 147 const base::FilePath me(argv0.BaseName()); |
| 140 | 148 |
| 141 enum OptionFlags { | 149 enum OptionFlags { |
| 142 // Long options without short equivalents. | 150 // Long options without short equivalents. |
| 143 kOptionLastChar = 255, | 151 kOptionLastChar = 255, |
| 144 kOptionAnnotation, | 152 kOptionAnnotation, |
| 145 kOptionDatabase, | 153 kOptionDatabase, |
| 146 #if defined(OS_MACOSX) | 154 #if defined(OS_MACOSX) |
| 147 kOptionHandshakeFD, | 155 kOptionHandshakeFD, |
| 156 #endif // OS_MACOSX |
| 157 #if defined(OS_WIN) |
| 158 kOptionInitialClientData, |
| 159 #endif // OS_WIN |
| 160 #if defined(OS_MACOSX) |
| 148 kOptionMachService, | 161 kOptionMachService, |
| 149 #elif defined(OS_WIN) | |
| 150 kOptionHandshakeHandle, | |
| 151 #endif // OS_MACOSX | 162 #endif // OS_MACOSX |
| 152 kOptionMetrics, | 163 kOptionMetrics, |
| 153 kOptionNoRateLimit, | 164 kOptionNoRateLimit, |
| 154 #if defined(OS_MACOSX) | 165 #if defined(OS_MACOSX) |
| 155 kOptionResetOwnCrashExceptionPortToSystemDefault, | 166 kOptionResetOwnCrashExceptionPortToSystemDefault, |
| 156 #elif defined(OS_WIN) | 167 #elif defined(OS_WIN) |
| 157 kOptionPipeName, | 168 kOptionPipeName, |
| 158 #endif // OS_MACOSX | 169 #endif // OS_MACOSX |
| 159 kOptionURL, | 170 kOptionURL, |
| 160 | 171 |
| 161 // Standard options. | 172 // Standard options. |
| 162 kOptionHelp = -2, | 173 kOptionHelp = -2, |
| 163 kOptionVersion = -3, | 174 kOptionVersion = -3, |
| 164 }; | 175 }; |
| 165 | 176 |
| 166 struct { | 177 struct { |
| 167 std::map<std::string, std::string> annotations; | 178 std::map<std::string, std::string> annotations; |
| 168 std::string url; | 179 std::string url; |
| 169 const char* database; | 180 const char* database; |
| 170 const char* metrics; | 181 const char* metrics; |
| 171 #if defined(OS_MACOSX) | 182 #if defined(OS_MACOSX) |
| 172 int handshake_fd; | 183 int handshake_fd; |
| 173 std::string mach_service; | 184 std::string mach_service; |
| 174 bool reset_own_crash_exception_port_to_system_default; | 185 bool reset_own_crash_exception_port_to_system_default; |
| 175 #elif defined(OS_WIN) | 186 #elif defined(OS_WIN) |
| 176 HANDLE handshake_handle; | |
| 177 std::string pipe_name; | 187 std::string pipe_name; |
| 188 InitialClientData initial_client_data; |
| 178 #endif // OS_MACOSX | 189 #endif // OS_MACOSX |
| 179 bool rate_limit; | 190 bool rate_limit; |
| 180 } options = {}; | 191 } options = {}; |
| 181 #if defined(OS_MACOSX) | 192 #if defined(OS_MACOSX) |
| 182 options.handshake_fd = -1; | 193 options.handshake_fd = -1; |
| 183 #elif defined(OS_WIN) | |
| 184 options.handshake_handle = INVALID_HANDLE_VALUE; | |
| 185 #endif | 194 #endif |
| 186 options.rate_limit = true; | 195 options.rate_limit = true; |
| 187 | 196 |
| 188 const option long_options[] = { | 197 const option long_options[] = { |
| 189 {"annotation", required_argument, nullptr, kOptionAnnotation}, | 198 {"annotation", required_argument, nullptr, kOptionAnnotation}, |
| 190 {"database", required_argument, nullptr, kOptionDatabase}, | 199 {"database", required_argument, nullptr, kOptionDatabase}, |
| 191 #if defined(OS_MACOSX) | 200 #if defined(OS_MACOSX) |
| 192 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, | 201 {"handshake-fd", required_argument, nullptr, kOptionHandshakeFD}, |
| 193 {"mach-service", required_argument, nullptr, kOptionMachService}, | 202 #endif // OS_MACOSX |
| 203 #if defined(OS_WIN) |
| 204 {"initial-client-data", |
| 205 required_argument, |
| 206 nullptr, |
| 207 kOptionInitialClientData}, |
| 208 #endif // OS_MACOSX |
| 209 #if defined(OS_MACOSX) |
| 210 {"mach-service", required_argument, nullptr, kOptionMachService}, |
| 211 #endif // OS_MACOSX |
| 212 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, |
| 213 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, |
| 214 #if defined(OS_MACOSX) |
| 215 {"reset-own-crash-exception-port-to-system-default", |
| 216 no_argument, |
| 217 nullptr, |
| 218 kOptionResetOwnCrashExceptionPortToSystemDefault}, |
| 194 #elif defined(OS_WIN) | 219 #elif defined(OS_WIN) |
| 195 {"handshake-handle", required_argument, nullptr, kOptionHandshakeHandle}, | 220 {"pipe-name", required_argument, nullptr, kOptionPipeName}, |
| 196 #endif // OS_MACOSX | 221 #endif // OS_MACOSX |
| 197 {"metrics-dir", required_argument, nullptr, kOptionMetrics}, | 222 {"url", required_argument, nullptr, kOptionURL}, |
| 198 {"no-rate-limit", no_argument, nullptr, kOptionNoRateLimit}, | 223 {"help", no_argument, nullptr, kOptionHelp}, |
| 199 #if defined(OS_MACOSX) | 224 {"version", no_argument, nullptr, kOptionVersion}, |
| 200 {"reset-own-crash-exception-port-to-system-default", | 225 {nullptr, 0, nullptr, 0}, |
| 201 no_argument, | |
| 202 nullptr, | |
| 203 kOptionResetOwnCrashExceptionPortToSystemDefault}, | |
| 204 #elif defined(OS_WIN) | |
| 205 {"pipe-name", required_argument, nullptr, kOptionPipeName}, | |
| 206 #endif // OS_MACOSX | |
| 207 {"url", required_argument, nullptr, kOptionURL}, | |
| 208 {"help", no_argument, nullptr, kOptionHelp}, | |
| 209 {"version", no_argument, nullptr, kOptionVersion}, | |
| 210 {nullptr, 0, nullptr, 0}, | |
| 211 }; | 226 }; |
| 212 | 227 |
| 213 int opt; | 228 int opt; |
| 214 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { | 229 while ((opt = getopt_long(argc, argv, "", long_options, nullptr)) != -1) { |
| 215 switch (opt) { | 230 switch (opt) { |
| 216 case kOptionAnnotation: { | 231 case kOptionAnnotation: { |
| 217 std::string key; | 232 std::string key; |
| 218 std::string value; | 233 std::string value; |
| 219 if (!SplitString(optarg, '=', &key, &value)) { | 234 if (!SplitStringFirst(optarg, '=', &key, &value)) { |
| 220 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); | 235 ToolSupport::UsageHint(me, "--annotation requires KEY=VALUE"); |
| 221 return EXIT_FAILURE; | 236 return EXIT_FAILURE; |
| 222 } | 237 } |
| 223 std::string old_value; | 238 std::string old_value; |
| 224 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { | 239 if (!MapInsertOrReplace(&options.annotations, key, value, &old_value)) { |
| 225 LOG(WARNING) << "duplicate key " << key << ", discarding value " | 240 LOG(WARNING) << "duplicate key " << key << ", discarding value " |
| 226 << old_value; | 241 << old_value; |
| 227 } | 242 } |
| 228 break; | 243 break; |
| 229 } | 244 } |
| 230 case kOptionDatabase: { | 245 case kOptionDatabase: { |
| 231 options.database = optarg; | 246 options.database = optarg; |
| 232 break; | 247 break; |
| 233 } | 248 } |
| 234 #if defined(OS_MACOSX) | 249 #if defined(OS_MACOSX) |
| 235 case kOptionHandshakeFD: { | 250 case kOptionHandshakeFD: { |
| 236 if (!StringToNumber(optarg, &options.handshake_fd) || | 251 if (!StringToNumber(optarg, &options.handshake_fd) || |
| 237 options.handshake_fd < 0) { | 252 options.handshake_fd < 0) { |
| 238 ToolSupport::UsageHint(me, | 253 ToolSupport::UsageHint(me, |
| 239 "--handshake-fd requires a file descriptor"); | 254 "--handshake-fd requires a file descriptor"); |
| 240 return EXIT_FAILURE; | 255 return EXIT_FAILURE; |
| 241 } | 256 } |
| 242 break; | 257 break; |
| 243 } | 258 } |
| 244 case kOptionMachService: { | 259 case kOptionMachService: { |
| 245 options.mach_service = optarg; | 260 options.mach_service = optarg; |
| 246 break; | 261 break; |
| 247 } | 262 } |
| 248 #elif defined(OS_WIN) | 263 #elif defined(OS_WIN) |
| 249 case kOptionHandshakeHandle: { | 264 case kOptionInitialClientData: { |
| 250 // Use unsigned int, because the handle was presented by the client in | 265 if (!options.initial_client_data.InitializeFromString(optarg)) { |
| 251 // 0x%x format. | 266 ToolSupport::UsageHint( |
| 252 unsigned int handle_uint; | 267 me, "failed to parse --initial-client-data"); |
| 253 if (!StringToNumber(optarg, &handle_uint) || | |
| 254 (options.handshake_handle = IntToHandle(handle_uint)) == | |
| 255 INVALID_HANDLE_VALUE) { | |
| 256 ToolSupport::UsageHint(me, "--handshake-handle requires a HANDLE"); | |
| 257 return EXIT_FAILURE; | 268 return EXIT_FAILURE; |
| 258 } | 269 } |
| 259 break; | 270 break; |
| 260 } | 271 } |
| 261 #endif // OS_MACOSX | 272 #endif // OS_MACOSX |
| 262 case kOptionMetrics: { | 273 case kOptionMetrics: { |
| 263 options.metrics = optarg; | 274 options.metrics = optarg; |
| 264 break; | 275 break; |
| 265 } | 276 } |
| 266 case kOptionNoRateLimit: { | 277 case kOptionNoRateLimit: { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 303 if (options.handshake_fd < 0 && options.mach_service.empty()) { | 314 if (options.handshake_fd < 0 && options.mach_service.empty()) { |
| 304 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); | 315 ToolSupport::UsageHint(me, "--handshake-fd or --mach-service is required"); |
| 305 return EXIT_FAILURE; | 316 return EXIT_FAILURE; |
| 306 } | 317 } |
| 307 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { | 318 if (options.handshake_fd >= 0 && !options.mach_service.empty()) { |
| 308 ToolSupport::UsageHint( | 319 ToolSupport::UsageHint( |
| 309 me, "--handshake-fd and --mach-service are incompatible"); | 320 me, "--handshake-fd and --mach-service are incompatible"); |
| 310 return EXIT_FAILURE; | 321 return EXIT_FAILURE; |
| 311 } | 322 } |
| 312 #elif defined(OS_WIN) | 323 #elif defined(OS_WIN) |
| 313 if (options.handshake_handle == INVALID_HANDLE_VALUE && | 324 if (!options.initial_client_data.IsValid() && options.pipe_name.empty()) { |
| 314 options.pipe_name.empty()) { | 325 ToolSupport::UsageHint(me, |
| 315 ToolSupport::UsageHint(me, "--handshake-handle or --pipe-name is required"); | 326 "--initial-client-data or --pipe-name is required"); |
| 316 return EXIT_FAILURE; | 327 return EXIT_FAILURE; |
| 317 } | 328 } |
| 318 if (options.handshake_handle != INVALID_HANDLE_VALUE && | 329 if (options.initial_client_data.IsValid() && !options.pipe_name.empty()) { |
| 319 !options.pipe_name.empty()) { | |
| 320 ToolSupport::UsageHint( | 330 ToolSupport::UsageHint( |
| 321 me, "--handshake-handle and --pipe-name are incompatible"); | 331 me, "--initial-client-data and --pipe-name are incompatible"); |
| 322 return EXIT_FAILURE; | 332 return EXIT_FAILURE; |
| 323 } | 333 } |
| 324 #endif // OS_MACOSX | 334 #endif // OS_MACOSX |
| 325 | 335 |
| 326 if (!options.database) { | 336 if (!options.database) { |
| 327 ToolSupport::UsageHint(me, "--database is required"); | 337 ToolSupport::UsageHint(me, "--database is required"); |
| 328 return EXIT_FAILURE; | 338 return EXIT_FAILURE; |
| 329 } | 339 } |
| 330 | 340 |
| 331 if (argc) { | 341 if (argc) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 382 } | 392 } |
| 383 #elif defined(OS_WIN) | 393 #elif defined(OS_WIN) |
| 384 // Shut down as late as possible relative to programs we're watching. | 394 // Shut down as late as possible relative to programs we're watching. |
| 385 if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY)) | 395 if (!SetProcessShutdownParameters(0x100, SHUTDOWN_NORETRY)) |
| 386 PLOG(ERROR) << "SetProcessShutdownParameters"; | 396 PLOG(ERROR) << "SetProcessShutdownParameters"; |
| 387 | 397 |
| 388 ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty()); | 398 ExceptionHandlerServer exception_handler_server(!options.pipe_name.empty()); |
| 389 | 399 |
| 390 if (!options.pipe_name.empty()) { | 400 if (!options.pipe_name.empty()) { |
| 391 exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name)); | 401 exception_handler_server.SetPipeName(base::UTF8ToUTF16(options.pipe_name)); |
| 392 } else if (options.handshake_handle != INVALID_HANDLE_VALUE) { | |
| 393 std::wstring pipe_name = exception_handler_server.CreatePipe(); | |
| 394 | |
| 395 uint32_t pipe_name_length = static_cast<uint32_t>(pipe_name.size()); | |
| 396 if (!LoggingWriteFile(options.handshake_handle, | |
| 397 &pipe_name_length, | |
| 398 sizeof(pipe_name_length))) { | |
| 399 return EXIT_FAILURE; | |
| 400 } | |
| 401 if (!LoggingWriteFile(options.handshake_handle, | |
| 402 pipe_name.c_str(), | |
| 403 pipe_name.size() * sizeof(pipe_name[0]))) { | |
| 404 return EXIT_FAILURE; | |
| 405 } | |
| 406 } | 402 } |
| 407 #endif // OS_MACOSX | 403 #endif // OS_MACOSX |
| 408 | 404 |
| 409 base::GlobalHistogramAllocator* histogram_allocator = nullptr; | 405 base::GlobalHistogramAllocator* histogram_allocator = nullptr; |
| 410 if (options.metrics) { | 406 if (options.metrics) { |
| 411 const base::FilePath metrics_dir( | 407 const base::FilePath metrics_dir( |
| 412 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); | 408 ToolSupport::CommandLineArgumentToFilePathStringType(options.metrics)); |
| 413 static const char kMetricsName[] = "CrashpadMetrics"; | 409 static const char kMetricsName[] = "CrashpadMetrics"; |
| 414 const size_t kMetricsFileSize = 1 << 20; | 410 const size_t kMetricsFileSize = 1 << 20; |
| 415 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( | 411 if (base::GlobalHistogramAllocator::CreateWithActiveFileInDir( |
| (...skipping 17 matching lines...) Expand all Loading... |
| 433 database.get(), options.url, options.rate_limit); | 429 database.get(), options.url, options.rate_limit); |
| 434 upload_thread.Start(); | 430 upload_thread.Start(); |
| 435 | 431 |
| 436 PruneCrashReportThread prune_thread(database.get(), | 432 PruneCrashReportThread prune_thread(database.get(), |
| 437 PruneCondition::GetDefault()); | 433 PruneCondition::GetDefault()); |
| 438 prune_thread.Start(); | 434 prune_thread.Start(); |
| 439 | 435 |
| 440 CrashReportExceptionHandler exception_handler( | 436 CrashReportExceptionHandler exception_handler( |
| 441 database.get(), &upload_thread, &options.annotations); | 437 database.get(), &upload_thread, &options.annotations); |
| 442 | 438 |
| 439 #if defined(OS_WIN) |
| 440 if (options.initial_client_data.IsValid()) { |
| 441 exception_handler_server.InitializeWithInheritedDataForInitialClient( |
| 442 options.initial_client_data, &exception_handler); |
| 443 } |
| 444 #endif // OS_WIN |
| 445 |
| 443 exception_handler_server.Run(&exception_handler); | 446 exception_handler_server.Run(&exception_handler); |
| 444 | 447 |
| 445 upload_thread.Stop(); | 448 upload_thread.Stop(); |
| 446 prune_thread.Stop(); | 449 prune_thread.Stop(); |
| 447 | 450 |
| 448 if (histogram_allocator) | 451 if (histogram_allocator) |
| 449 histogram_allocator->DeletePersistentLocation(); | 452 histogram_allocator->DeletePersistentLocation(); |
| 450 | 453 |
| 451 return EXIT_SUCCESS; | 454 return EXIT_SUCCESS; |
| 452 } | 455 } |
| 453 | 456 |
| 454 } // namespace crashpad | 457 } // namespace crashpad |
| OLD | NEW |