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 |