Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/crash_handler_host_linux.h" | 5 #include "chrome/browser/crash_handler_host_linux.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 #include <stdlib.h> | 8 #include <stdlib.h> |
| 9 #include <sys/socket.h> | 9 #include <sys/socket.h> |
| 10 #include <sys/syscall.h> | 10 #include <sys/syscall.h> |
| 11 #include <sys/types.h> | |
| 12 #include <unistd.h> | 11 #include <unistd.h> |
| 13 | 12 |
| 14 #include "base/eintr_wrapper.h" | 13 #include "base/eintr_wrapper.h" |
| 15 #include "base/file_path.h" | 14 #include "base/file_path.h" |
| 16 #include "base/format_macros.h" | 15 #include "base/format_macros.h" |
| 17 #include "base/linux_util.h" | 16 #include "base/linux_util.h" |
| 18 #include "base/logging.h" | 17 #include "base/logging.h" |
| 19 #include "base/message_loop.h" | 18 #include "base/message_loop.h" |
| 20 #include "base/path_service.h" | 19 #include "base/path_service.h" |
| 21 #include "base/rand_util.h" | 20 #include "base/rand_util.h" |
| 22 #include "base/singleton.h" | 21 #include "base/singleton.h" |
| 23 #include "base/string_util.h" | 22 #include "base/string_util.h" |
| 24 #include "base/task.h" | 23 #include "base/task.h" |
| 25 #include "base/threading/thread.h" | 24 #include "base/threading/thread.h" |
| 26 #include "breakpad/src/client/linux/handler/exception_handler.h" | 25 #include "breakpad/src/client/linux/handler/exception_handler.h" |
| 27 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" | 26 #include "breakpad/src/client/linux/minidump_writer/linux_dumper.h" |
| 28 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" | 27 #include "breakpad/src/client/linux/minidump_writer/minidump_writer.h" |
| 29 #include "chrome/app/breakpad_linux.h" | 28 #include "chrome/app/breakpad_linux.h" |
| 30 #include "chrome/browser/browser_thread.h" | 29 #include "chrome/browser/browser_thread.h" |
| 31 #include "chrome/common/chrome_paths.h" | 30 #include "chrome/common/chrome_paths.h" |
| 32 #include "chrome/common/env_vars.h" | 31 #include "chrome/common/env_vars.h" |
| 33 | 32 |
| 34 using google_breakpad::ExceptionHandler; | 33 using google_breakpad::ExceptionHandler; |
| 35 | 34 |
| 36 namespace { | 35 namespace { |
| 37 | 36 |
| 37 // The length of the control message: | |
| 38 const unsigned kControlMsgSize = | |
| 39 CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); | |
| 40 // The length of the regular payload: | |
| 41 const unsigned kCrashContextSize = sizeof(ExceptionHandler::CrashContext); | |
| 42 | |
| 38 // Handles the crash dump and frees the allocated BreakpadInfo struct. | 43 // Handles the crash dump and frees the allocated BreakpadInfo struct. |
| 39 void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) { | 44 void CrashDumpTask(CrashHandlerHostLinux* handler, BreakpadInfo* info) { |
| 40 if (handler->IsShuttingDown()) | 45 if (handler->IsShuttingDown()) |
| 41 return; | 46 return; |
| 42 | 47 |
| 43 HandleCrashDump(*info); | 48 HandleCrashDump(*info); |
| 44 delete[] info->filename; | 49 delete[] info->filename; |
| 45 delete[] info->process_type; | 50 delete[] info->process_type; |
| 46 delete[] info->crash_url; | 51 delete[] info->crash_url; |
| 47 delete[] info->guid; | 52 delete[] info->guid; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 105 } | 110 } |
| 106 | 111 |
| 107 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { | 112 void CrashHandlerHostLinux::OnFileCanReadWithoutBlocking(int fd) { |
| 108 DCHECK_EQ(fd, browser_socket_); | 113 DCHECK_EQ(fd, browser_socket_); |
| 109 | 114 |
| 110 // A process has crashed and has signaled us by writing a datagram | 115 // A process has crashed and has signaled us by writing a datagram |
| 111 // to the death signal socket. The datagram contains the crash context needed | 116 // to the death signal socket. The datagram contains the crash context needed |
| 112 // for writing the minidump as well as a file descriptor and a credentials | 117 // for writing the minidump as well as a file descriptor and a credentials |
| 113 // block so that they can't lie about their pid. | 118 // block so that they can't lie about their pid. |
| 114 | 119 |
| 115 // The length of the control message: | |
| 116 static const unsigned kControlMsgSize = | |
| 117 CMSG_SPACE(2*sizeof(int)) + CMSG_SPACE(sizeof(struct ucred)); | |
| 118 // The length of the regular payload: | |
| 119 static const unsigned kCrashContextSize = | |
| 120 sizeof(ExceptionHandler::CrashContext); | |
| 121 | |
| 122 const size_t kIovSize = 7; | 120 const size_t kIovSize = 7; |
| 123 struct msghdr msg = {0}; | 121 struct msghdr msg = {0}; |
| 124 struct iovec iov[kIovSize]; | 122 struct iovec iov[kIovSize]; |
| 125 char crash_context[kCrashContextSize]; | 123 char crash_context[kCrashContextSize]; |
| 126 char* guid = new char[kGuidSize + 1]; | 124 char* guid = new char[kGuidSize + 1]; |
| 127 char* crash_url = new char[kMaxActiveURLSize + 1]; | 125 char* crash_url = new char[kMaxActiveURLSize + 1]; |
| 128 char* distro = new char[kDistroSize + 1]; | 126 char* distro = new char[kDistroSize + 1]; |
| 129 char* tid_buf_addr = NULL; | 127 char* tid_buf_addr = NULL; |
| 130 int tid_fd = -1; | 128 int tid_fd = -1; |
| 131 uint64_t uptime; | 129 uint64_t uptime; |
| (...skipping 140 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 272 // went away. We'll just take a guess here and assume the crashing | 270 // went away. We'll just take a guess here and assume the crashing |
| 273 // thread is the thread group leader. | 271 // thread is the thread group leader. |
| 274 crashing_tid = crashing_pid; | 272 crashing_tid = crashing_pid; |
| 275 } | 273 } |
| 276 | 274 |
| 277 ExceptionHandler::CrashContext* bad_context = | 275 ExceptionHandler::CrashContext* bad_context = |
| 278 reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context); | 276 reinterpret_cast<ExceptionHandler::CrashContext*>(crash_context); |
| 279 bad_context->tid = crashing_tid; | 277 bad_context->tid = crashing_tid; |
| 280 } | 278 } |
| 281 | 279 |
| 282 bool upload = true; | 280 // Sanitize the string data a bit more |
| 281 guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0; | |
| 282 | |
| 283 BreakpadInfo* info = new BreakpadInfo; | |
| 284 | |
| 285 info->process_type_length = process_type_.length(); | |
| 286 char* process_type_str = new char[info->process_type_length + 1]; | |
| 287 process_type_.copy(process_type_str, info->process_type_length); | |
| 288 process_type_str[info->process_type_length] = '\0'; | |
| 289 info->process_type = process_type_str; | |
| 290 | |
| 291 info->crash_url_length = strlen(crash_url); | |
| 292 info->crash_url = crash_url; | |
| 293 | |
| 294 info->guid_length = strlen(guid); | |
| 295 info->guid = guid; | |
| 296 | |
| 297 info->distro_length = strlen(distro); | |
| 298 info->distro = distro; | |
| 299 | |
| 300 info->upload = (getenv(env_vars::kHeadless) == NULL); | |
| 301 info->process_start_time = uptime; | |
| 302 | |
| 303 BrowserThread::PostTask( | |
| 304 BrowserThread::FILE, FROM_HERE, | |
| 305 NewRunnableMethod(this, | |
| 306 &CrashHandlerHostLinux::WriteDumpFile, | |
| 307 info, | |
| 308 crashing_pid, | |
| 309 reinterpret_cast<char*>(&crash_context), | |
|
piman
2011/04/15 05:17:17
Woah, are we passing a reference to a buffer on th
Lei Zhang
2011/04/15 05:25:07
Doh. I'll fix it in a bit.
| |
| 310 signal_fd)); | |
| 311 } | |
| 312 | |
| 313 void CrashHandlerHostLinux::WriteDumpFile(BreakpadInfo* info, | |
| 314 pid_t crashing_pid, | |
| 315 char* crash_context, | |
| 316 int signal_fd) { | |
| 317 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
| 318 | |
| 283 FilePath dumps_path("/tmp"); | 319 FilePath dumps_path("/tmp"); |
| 284 PathService::Get(base::DIR_TEMP, &dumps_path); | 320 PathService::Get(base::DIR_TEMP, &dumps_path); |
| 285 if (getenv(env_vars::kHeadless)) { | 321 if (!info->upload) |
| 286 upload = false; | |
| 287 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); | 322 PathService::Get(chrome::DIR_CRASH_DUMPS, &dumps_path); |
| 288 } | |
| 289 const uint64 rand = base::RandUint64(); | 323 const uint64 rand = base::RandUint64(); |
| 290 const std::string minidump_filename = | 324 const std::string minidump_filename = |
| 291 StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", | 325 StringPrintf("%s/chromium-%s-minidump-%016" PRIx64 ".dmp", |
| 292 dumps_path.value().c_str(), process_type_.c_str(), rand); | 326 dumps_path.value().c_str(), process_type_.c_str(), rand); |
| 293 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), | 327 if (!google_breakpad::WriteMinidump(minidump_filename.c_str(), |
| 294 crashing_pid, crash_context, | 328 crashing_pid, crash_context, |
| 295 kCrashContextSize)) { | 329 kCrashContextSize)) { |
| 296 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid; | 330 LOG(ERROR) << "Failed to write crash dump for pid " << crashing_pid; |
| 297 HANDLE_EINTR(close(signal_fd)); | |
|
Lei Zhang
2011/02/17 22:49:08
On failure, we closed |signal_fd| twice.
| |
| 298 } | 331 } |
| 299 | 332 |
| 333 char* minidump_filename_str = new char[minidump_filename.length() + 1]; | |
| 334 minidump_filename.copy(minidump_filename_str, minidump_filename.length()); | |
| 335 minidump_filename_str[minidump_filename.length()] = '\0'; | |
| 336 info->filename = minidump_filename_str; | |
| 337 | |
| 338 BrowserThread::PostTask( | |
| 339 BrowserThread::IO, FROM_HERE, | |
| 340 NewRunnableMethod(this, | |
| 341 &CrashHandlerHostLinux::QueueCrashDumpTask, | |
| 342 info, | |
| 343 signal_fd)); | |
| 344 } | |
| 345 | |
| 346 void CrashHandlerHostLinux::QueueCrashDumpTask(BreakpadInfo* info, | |
| 347 int signal_fd) { | |
| 348 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); | |
| 349 | |
| 300 // Send the done signal to the process: it can exit now. | 350 // Send the done signal to the process: it can exit now. |
| 301 memset(&msg, 0, sizeof(msg)); | 351 struct msghdr msg = {0}; |
| 302 struct iovec done_iov; | 352 struct iovec done_iov; |
| 303 done_iov.iov_base = const_cast<char*>("\x42"); | 353 done_iov.iov_base = const_cast<char*>("\x42"); |
| 304 done_iov.iov_len = 1; | 354 done_iov.iov_len = 1; |
| 305 msg.msg_iov = &done_iov; | 355 msg.msg_iov = &done_iov; |
| 306 msg.msg_iovlen = 1; | 356 msg.msg_iovlen = 1; |
| 307 | 357 |
| 308 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); | 358 HANDLE_EINTR(sendmsg(signal_fd, &msg, MSG_DONTWAIT | MSG_NOSIGNAL)); |
| 309 HANDLE_EINTR(close(signal_fd)); | 359 HANDLE_EINTR(close(signal_fd)); |
| 310 | 360 |
| 311 // Sanitize the string data a bit more | |
| 312 guid[kGuidSize] = crash_url[kMaxActiveURLSize] = distro[kDistroSize] = 0; | |
| 313 | |
| 314 BreakpadInfo* info = new BreakpadInfo; | |
| 315 | |
| 316 char* minidump_filename_str = new char[minidump_filename.length() + 1]; | |
| 317 minidump_filename.copy(minidump_filename_str, minidump_filename.length()); | |
| 318 minidump_filename_str[minidump_filename.length()] = '\0'; | |
| 319 info->filename = minidump_filename_str; | |
| 320 | |
| 321 info->process_type_length = process_type_.length(); | |
| 322 char* process_type_str = new char[info->process_type_length + 1]; | |
| 323 process_type_.copy(process_type_str, info->process_type_length); | |
| 324 process_type_str[info->process_type_length] = '\0'; | |
| 325 info->process_type = process_type_str; | |
| 326 | |
| 327 info->crash_url_length = strlen(crash_url); | |
| 328 info->crash_url = crash_url; | |
| 329 | |
| 330 info->guid_length = strlen(guid); | |
| 331 info->guid = guid; | |
| 332 | |
| 333 info->distro_length = strlen(distro); | |
| 334 info->distro = distro; | |
| 335 | |
| 336 info->upload = upload; | |
| 337 info->process_start_time = uptime; | |
| 338 | |
| 339 uploader_thread_->message_loop()->PostTask( | 361 uploader_thread_->message_loop()->PostTask( |
| 340 FROM_HERE, | 362 FROM_HERE, |
| 341 NewRunnableFunction(&CrashDumpTask, this, info)); | 363 NewRunnableFunction(&CrashDumpTask, this, info)); |
| 342 } | 364 } |
| 343 | 365 |
| 344 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { | 366 void CrashHandlerHostLinux::WillDestroyCurrentMessageLoop() { |
| 345 file_descriptor_watcher_.StopWatchingFileDescriptor(); | 367 file_descriptor_watcher_.StopWatchingFileDescriptor(); |
| 346 | 368 |
| 347 // If we are quitting and there are crash dumps in the queue, turn them into | 369 // If we are quitting and there are crash dumps in the queue, turn them into |
| 348 // no-ops. | 370 // no-ops. |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 394 } | 416 } |
| 395 | 417 |
| 396 void RendererCrashHandlerHostLinux::SetProcessType() { | 418 void RendererCrashHandlerHostLinux::SetProcessType() { |
| 397 process_type_ = "renderer"; | 419 process_type_ = "renderer"; |
| 398 } | 420 } |
| 399 | 421 |
| 400 // static | 422 // static |
| 401 RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() { | 423 RendererCrashHandlerHostLinux* RendererCrashHandlerHostLinux::GetInstance() { |
| 402 return Singleton<RendererCrashHandlerHostLinux>::get(); | 424 return Singleton<RendererCrashHandlerHostLinux>::get(); |
| 403 } | 425 } |
| OLD | NEW |