| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2009, Google Inc. | |
| 2 // All rights reserved. | |
| 3 // | |
| 4 // Redistribution and use in source and binary forms, with or without | |
| 5 // modification, are permitted provided that the following conditions are | |
| 6 // met: | |
| 7 // | |
| 8 // * Redistributions of source code must retain the above copyright | |
| 9 // notice, this list of conditions and the following disclaimer. | |
| 10 // * Redistributions in binary form must reproduce the above | |
| 11 // copyright notice, this list of conditions and the following disclaimer | |
| 12 // in the documentation and/or other materials provided with the | |
| 13 // distribution. | |
| 14 // * Neither the name of Google Inc. nor the names of its | |
| 15 // contributors may be used to endorse or promote products derived from | |
| 16 // this software without specific prior written permission. | |
| 17 // | |
| 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 29 | |
| 30 // The ExceptionHandler object installs signal handlers for a number of | |
| 31 // signals. We rely on the signal handler running on the thread which crashed | |
| 32 // in order to identify it. This is true of the synchronous signals (SEGV etc), | |
| 33 // but not true of ABRT. Thus, if you send ABRT to yourself in a program which | |
| 34 // uses ExceptionHandler, you need to use tgkill to direct it to the current | |
| 35 // thread. | |
| 36 // | |
| 37 // The signal flow looks like this: | |
| 38 // | |
| 39 // SignalHandler (uses a global stack of ExceptionHandler objects to find | |
| 40 // | one to handle the signal. If the first rejects it, try | |
| 41 // | the second etc...) | |
| 42 // V | |
| 43 // HandleSignal ----------------------------| (clones a new process which | |
| 44 // | | shares an address space with | |
| 45 // (wait for cloned | the crashed process. This | |
| 46 // process) | allows us to ptrace the crashed | |
| 47 // | | process) | |
| 48 // V V | |
| 49 // (set signal handler to ThreadEntry (static function to bounce | |
| 50 // SIG_DFL and rethrow, | back into the object) | |
| 51 // killing the crashed | | |
| 52 // process) V | |
| 53 // DoDump (writes minidump) | |
| 54 // | | |
| 55 // V | |
| 56 // sys_exit | |
| 57 // | |
| 58 | |
| 59 // This code is a little fragmented. Different functions of the ExceptionHandler | |
| 60 // class run in a number of different contexts. Some of them run in a normal | |
| 61 // context and are easy to code, others run in a compromised context and the | |
| 62 // restrictions at the top of minidump_writer.cc apply: no libc and use the | |
| 63 // alternative malloc. Each function should have comment above it detailing the | |
| 64 // context which it runs in. | |
| 65 | |
| 66 #include "breakpad/linux/exception_handler.h" | |
| 67 | |
| 68 #include <errno.h> | |
| 69 #include <fcntl.h> | |
| 70 #include <linux/limits.h> | |
| 71 #include <sched.h> | |
| 72 #include <signal.h> | |
| 73 #include <stdio.h> | |
| 74 #include <sys/mman.h> | |
| 75 #include <sys/signal.h> | |
| 76 #include <sys/syscall.h> | |
| 77 #include <sys/ucontext.h> | |
| 78 #include <sys/user.h> | |
| 79 #include <sys/wait.h> | |
| 80 #include <unistd.h> | |
| 81 | |
| 82 #include "breakpad/linux/linux_libc_support.h" | |
| 83 #include "breakpad/linux/linux_syscall_support.h" | |
| 84 #include "breakpad/linux/memory.h" | |
| 85 #include "breakpad/linux/minidump_writer.h" | |
| 86 #include "common/linux/guid_creator.h" | |
| 87 | |
| 88 // A wrapper for the tgkill syscall: send a signal to a specific thread. | |
| 89 static int tgkill(pid_t tgid, pid_t tid, int sig) { | |
| 90 syscall(__NR_tgkill, tgid, tid, sig); | |
| 91 } | |
| 92 | |
| 93 namespace google_breakpad { | |
| 94 | |
| 95 // The list of signals which we consider to be crashes. The default action for | |
| 96 // all these signals must be Core (see man 7 signal) because we rethrow the | |
| 97 // signal after handling it and expect that it'll be fatal. | |
| 98 static const int kExceptionSignals[] = { | |
| 99 SIGSEGV, SIGABRT, SIGFPE, SIGILL, SIGBUS, -1 | |
| 100 }; | |
| 101 | |
| 102 // We can stack multiple exception handlers. In that case, this is the global | |
| 103 // which holds the stack. | |
| 104 std::vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL; | |
| 105 unsigned ExceptionHandler::handler_stack_index_ = 0; | |
| 106 pthread_mutex_t ExceptionHandler::handler_stack_mutex_ = | |
| 107 PTHREAD_MUTEX_INITIALIZER; | |
| 108 | |
| 109 // Runs before crashing: normal context. | |
| 110 ExceptionHandler::ExceptionHandler(const std::string &dump_path, | |
| 111 FilterCallback filter, | |
| 112 MinidumpCallback callback, | |
| 113 void *callback_context, | |
| 114 bool install_handler) | |
| 115 : filter_(filter), | |
| 116 callback_(callback), | |
| 117 callback_context_(callback_context), | |
| 118 dump_path_(), | |
| 119 handler_installed_(install_handler), | |
| 120 crash_handler_(NULL) { | |
| 121 set_dump_path(dump_path); | |
| 122 | |
| 123 if (install_handler) { | |
| 124 InstallHandlers(); | |
| 125 | |
| 126 pthread_mutex_lock(&handler_stack_mutex_); | |
| 127 if (handler_stack_ == NULL) | |
| 128 handler_stack_ = new std::vector<ExceptionHandler *>; | |
| 129 handler_stack_->push_back(this); | |
| 130 pthread_mutex_unlock(&handler_stack_mutex_); | |
| 131 } | |
| 132 } | |
| 133 | |
| 134 // Runs before crashing: normal context. | |
| 135 ExceptionHandler::~ExceptionHandler() { | |
| 136 UninstallHandlers(); | |
| 137 } | |
| 138 | |
| 139 // Runs before crashing: normal context. | |
| 140 bool ExceptionHandler::InstallHandlers() { | |
| 141 // We run the signal handlers on an alternative stack because we might have | |
| 142 // crashed because of a stack overflow. | |
| 143 | |
| 144 // We use this value rather than SIGSTKSZ because we would end up overrunning | |
| 145 // such a small stack. | |
| 146 static const unsigned kSigStackSize = 8192; | |
| 147 | |
| 148 signal_stack = malloc(kSigStackSize); | |
| 149 stack_t stack; | |
| 150 memset(&stack, 0, sizeof(stack)); | |
| 151 stack.ss_sp = signal_stack; | |
| 152 stack.ss_size = kSigStackSize; | |
| 153 | |
| 154 if (sigaltstack(&stack, NULL) == -1) | |
| 155 return false; | |
| 156 | |
| 157 struct sigaction sa; | |
| 158 memset(&sa, 0, sizeof(sa)); | |
| 159 sigemptyset(&sa.sa_mask); | |
| 160 | |
| 161 // mask all exception signals when we're handling one of them. | |
| 162 for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) | |
| 163 sigaddset(&sa.sa_mask, kExceptionSignals[i]); | |
| 164 | |
| 165 sa.sa_sigaction = SignalHandler; | |
| 166 sa.sa_flags = SA_ONSTACK | SA_SIGINFO; | |
| 167 | |
| 168 for (unsigned i = 0; kExceptionSignals[i] != -1; ++i) { | |
| 169 struct sigaction* old = new struct sigaction; | |
| 170 if (sigaction(kExceptionSignals[i], &sa, old) == -1) | |
| 171 return false; | |
| 172 old_handlers_.push_back(std::make_pair(kExceptionSignals[i], old)); | |
| 173 } | |
| 174 } | |
| 175 | |
| 176 // Runs before crashing: normal context. | |
| 177 void ExceptionHandler::UninstallHandlers() { | |
| 178 for (unsigned i = 0; i < old_handlers_.size(); ++i) { | |
| 179 struct sigaction *action = | |
| 180 reinterpret_cast<struct sigaction*>(old_handlers_[i].second); | |
| 181 sigaction(old_handlers_[i].first, action, NULL); | |
| 182 delete action; | |
| 183 } | |
| 184 | |
| 185 old_handlers_.clear(); | |
| 186 } | |
| 187 | |
| 188 // Runs before crashing: normal context. | |
| 189 void ExceptionHandler::UpdateNextID() { | |
| 190 GUID guid; | |
| 191 char guid_str[kGUIDStringLength + 1]; | |
| 192 if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) { | |
| 193 next_minidump_id_ = guid_str; | |
| 194 next_minidump_id_c_ = next_minidump_id_.c_str(); | |
| 195 | |
| 196 char minidump_path[PATH_MAX]; | |
| 197 snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp", | |
| 198 dump_path_c_, | |
| 199 guid_str); | |
| 200 | |
| 201 next_minidump_path_ = minidump_path; | |
| 202 next_minidump_path_c_ = next_minidump_path_.c_str(); | |
| 203 } | |
| 204 } | |
| 205 | |
| 206 // This function runs in a compromised context: see the top of the file. | |
| 207 // Runs on the crashing thread. | |
| 208 // static | |
| 209 void ExceptionHandler::SignalHandler(int sig, siginfo_t* info, void* uc) { | |
| 210 // All the exception signals are blocked at this point. | |
| 211 | |
| 212 pthread_mutex_lock(&handler_stack_mutex_); | |
| 213 | |
| 214 if (!handler_stack_->size()) { | |
| 215 pthread_mutex_unlock(&handler_stack_mutex_); | |
| 216 return; | |
| 217 } | |
| 218 | |
| 219 for (int i = handler_stack_->size() - 1; i >= 0; --i) { | |
| 220 if ((*handler_stack_)[i]->HandleSignal(sig, info, uc)) { | |
| 221 // successfully handled: We are in an invalid state since an exception | |
| 222 // signal has been delivered. We don't call the exit handlers because | |
| 223 // they could end up corrupting on-disk state. | |
| 224 break; | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 pthread_mutex_unlock(&handler_stack_mutex_); | |
| 229 | |
| 230 // Terminate ourselves with the same signal so that our parent knows that we | |
| 231 // crashed. The default action for all the signals which we catch is Core, so | |
| 232 // this is the end of us. | |
| 233 signal(sig, SIG_DFL); | |
| 234 tgkill(getpid(), sys_gettid(), sig); | |
| 235 | |
| 236 // not reached. | |
| 237 } | |
| 238 | |
| 239 struct ThreadArgument { | |
| 240 pid_t pid; // the crashing process | |
| 241 ExceptionHandler* handler; | |
| 242 const void* context; // a CrashContext structure | |
| 243 size_t context_size; | |
| 244 }; | |
| 245 | |
| 246 // This is the entry function for the cloned process. We are in a compromised | |
| 247 // context here: see the top of the file. | |
| 248 // static | |
| 249 int ExceptionHandler::ThreadEntry(void *arg) { | |
| 250 const ThreadArgument *thread_arg = reinterpret_cast<ThreadArgument*>(arg); | |
| 251 return thread_arg->handler->DoDump(thread_arg->pid, thread_arg->context, | |
| 252 thread_arg->context_size) == false; | |
| 253 } | |
| 254 | |
| 255 // This function runs in a compromised context: see the top of the file. | |
| 256 // Runs on the crashing thread. | |
| 257 bool ExceptionHandler::HandleSignal(int sig, siginfo_t* info, void* uc) { | |
| 258 if (filter_ && !filter_(callback_context_)) | |
| 259 return false; | |
| 260 | |
| 261 // Allow ourselves to be dumped. | |
| 262 sys_prctl(PR_SET_DUMPABLE, 1); | |
| 263 | |
| 264 CrashContext context; | |
| 265 memcpy(&context.siginfo, info, sizeof(siginfo_t)); | |
| 266 memcpy(&context.context, uc, sizeof(struct ucontext)); | |
| 267 memcpy(&context.float_state, ((struct ucontext *)uc)->uc_mcontext.fpregs, | |
| 268 sizeof(context.float_state)); | |
| 269 context.tid = sys_gettid(); | |
| 270 | |
| 271 if (crash_handler_ && crash_handler_(&context, sizeof(context), | |
| 272 callback_context_)) | |
| 273 return true; | |
| 274 | |
| 275 static const unsigned kChildStackSize = 8000; | |
| 276 PageAllocator allocator; | |
| 277 uint8_t* stack = (uint8_t*) allocator.Alloc(kChildStackSize); | |
| 278 if (!stack) | |
| 279 return false; | |
| 280 // clone() needs the top-most address. (scrub just to be safe) | |
| 281 stack += kChildStackSize; | |
| 282 my_memset(stack - 16, 0, 16); | |
| 283 | |
| 284 ThreadArgument thread_arg; | |
| 285 thread_arg.handler = this; | |
| 286 thread_arg.pid = getpid(); | |
| 287 thread_arg.context = &context; | |
| 288 thread_arg.context_size = sizeof(context); | |
| 289 | |
| 290 const pid_t child = sys_clone( | |
| 291 ThreadEntry, stack, CLONE_FILES | CLONE_FS | CLONE_UNTRACED, | |
| 292 &thread_arg, NULL, NULL, NULL); | |
| 293 int r, status; | |
| 294 do { | |
| 295 r = sys_waitpid(child, &status, __WALL); | |
| 296 } while (r == -1 && errno == EINTR); | |
| 297 | |
| 298 if (r == -1) { | |
| 299 static const char msg[] = "ExceptionHandler::HandleSignal: waitpid failed:"; | |
| 300 sys_write(2, msg, sizeof(msg) - 1); | |
| 301 sys_write(2, strerror(errno), strlen(strerror(errno))); | |
| 302 sys_write(2, "\n", 1); | |
| 303 } | |
| 304 | |
| 305 bool success = r != -1 && WIFEXITED(status) && WEXITSTATUS(status) == 0; | |
| 306 | |
| 307 if (callback_) | |
| 308 success = callback_(dump_path_c_, next_minidump_id_c_, | |
| 309 callback_context_, success); | |
| 310 | |
| 311 return success; | |
| 312 } | |
| 313 | |
| 314 // This function runs in a compromised context: see the top of the file. | |
| 315 // Runs on the cloned process. | |
| 316 bool ExceptionHandler::DoDump(pid_t crashing_process, const void* context, | |
| 317 size_t context_size) { | |
| 318 return google_breakpad::WriteMinidump( | |
| 319 next_minidump_path_c_, crashing_process, context, context_size); | |
| 320 } | |
| 321 | |
| 322 } // namespace google_breakpad | |
| OLD | NEW |