PageRenderTime 36ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/thirdparty/breakpad/client/solaris/handler/exception_handler.cc

http://github.com/tomahawk-player/tomahawk
C++ | 258 lines | 165 code | 32 blank | 61 comment | 35 complexity | 9d860999d509958fe28c11f1b9af6cfb MD5 | raw file
Possible License(s): LGPL-2.1, BSD-3-Clause, GPL-3.0, GPL-2.0
  1. // Copyright (c) 2007, 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. // Author: Alfred Peng
  30. #include <signal.h>
  31. #include <sys/stat.h>
  32. #include <sys/types.h>
  33. #include <unistd.h>
  34. #include <cassert>
  35. #include <cstdlib>
  36. #include <ctime>
  37. #include "client/solaris/handler/exception_handler.h"
  38. #include "common/solaris/guid_creator.h"
  39. #include "common/solaris/message_output.h"
  40. #include "google_breakpad/common/minidump_format.h"
  41. namespace google_breakpad {
  42. // Signals that we are interested.
  43. static const int kSigTable[] = {
  44. SIGSEGV,
  45. SIGABRT,
  46. SIGFPE,
  47. SIGILL,
  48. SIGBUS
  49. };
  50. std::vector<ExceptionHandler*> *ExceptionHandler::handler_stack_ = NULL;
  51. int ExceptionHandler::handler_stack_index_ = 0;
  52. pthread_mutex_t ExceptionHandler::handler_stack_mutex_ =
  53. PTHREAD_MUTEX_INITIALIZER;
  54. ExceptionHandler::ExceptionHandler(const string &dump_path,
  55. FilterCallback filter,
  56. MinidumpCallback callback,
  57. void *callback_context,
  58. bool install_handler)
  59. : filter_(filter),
  60. callback_(callback),
  61. callback_context_(callback_context),
  62. dump_path_(),
  63. installed_handler_(install_handler) {
  64. set_dump_path(dump_path);
  65. if (install_handler) {
  66. SetupHandler();
  67. }
  68. if (install_handler) {
  69. pthread_mutex_lock(&handler_stack_mutex_);
  70. if (handler_stack_ == NULL)
  71. handler_stack_ = new std::vector<ExceptionHandler *>;
  72. handler_stack_->push_back(this);
  73. pthread_mutex_unlock(&handler_stack_mutex_);
  74. }
  75. }
  76. ExceptionHandler::~ExceptionHandler() {
  77. TeardownAllHandlers();
  78. pthread_mutex_lock(&handler_stack_mutex_);
  79. if (handler_stack_->back() == this) {
  80. handler_stack_->pop_back();
  81. } else {
  82. print_message1(2, "warning: removing Breakpad handler out of order\n");
  83. for (std::vector<ExceptionHandler *>::iterator iterator =
  84. handler_stack_->begin();
  85. iterator != handler_stack_->end();
  86. ++iterator) {
  87. if (*iterator == this) {
  88. handler_stack_->erase(iterator);
  89. }
  90. }
  91. }
  92. if (handler_stack_->empty()) {
  93. // When destroying the last ExceptionHandler that installed a handler,
  94. // clean up the handler stack.
  95. delete handler_stack_;
  96. handler_stack_ = NULL;
  97. }
  98. pthread_mutex_unlock(&handler_stack_mutex_);
  99. }
  100. bool ExceptionHandler::WriteMinidump() {
  101. return InternalWriteMinidump(0, 0, NULL);
  102. }
  103. // static
  104. bool ExceptionHandler::WriteMinidump(const string &dump_path,
  105. MinidumpCallback callback,
  106. void *callback_context) {
  107. ExceptionHandler handler(dump_path, NULL, callback,
  108. callback_context, false);
  109. return handler.InternalWriteMinidump(0, 0, NULL);
  110. }
  111. void ExceptionHandler::SetupHandler() {
  112. // Signal on a different stack to avoid using the stack
  113. // of the crashing lwp.
  114. struct sigaltstack sig_stack;
  115. sig_stack.ss_sp = malloc(MINSIGSTKSZ);
  116. if (sig_stack.ss_sp == NULL)
  117. return;
  118. sig_stack.ss_size = MINSIGSTKSZ;
  119. sig_stack.ss_flags = 0;
  120. if (sigaltstack(&sig_stack, NULL) < 0)
  121. return;
  122. for (size_t i = 0; i < sizeof(kSigTable) / sizeof(kSigTable[0]); ++i)
  123. SetupHandler(kSigTable[i]);
  124. }
  125. void ExceptionHandler::SetupHandler(int signo) {
  126. struct sigaction act, old_act;
  127. act.sa_handler = HandleException;
  128. act.sa_flags = SA_ONSTACK;
  129. if (sigaction(signo, &act, &old_act) < 0)
  130. return;
  131. old_handlers_[signo] = old_act.sa_handler;
  132. }
  133. void ExceptionHandler::TeardownHandler(int signo) {
  134. if (old_handlers_.find(signo) != old_handlers_.end()) {
  135. struct sigaction act;
  136. act.sa_handler = old_handlers_[signo];
  137. act.sa_flags = 0;
  138. sigaction(signo, &act, 0);
  139. }
  140. }
  141. void ExceptionHandler::TeardownAllHandlers() {
  142. for (size_t i = 0; i < sizeof(kSigTable) / sizeof(kSigTable[0]); ++i) {
  143. TeardownHandler(kSigTable[i]);
  144. }
  145. }
  146. // static
  147. void ExceptionHandler::HandleException(int signo) {
  148. //void ExceptionHandler::HandleException(int signo, siginfo_t *sip, ucontext_t *sig_ctx) {
  149. // The context information about the signal is put on the stack of
  150. // the signal handler frame as value parameter. For some reasons, the
  151. // prototype of the handler doesn't declare this information as parameter, we
  152. // will do it by hand. The stack layout for a signal handler frame is here:
  153. // http://src.opensolaris.org/source/xref/onnv/onnv-gate/usr/src/lib/libproc/common/Pstack.c#81
  154. //
  155. // However, if we are being called by another signal handler passing the
  156. // signal up the chain, then we may not have this random extra parameter,
  157. // so we may have to walk the stack to find it. We do the actual work
  158. // on another thread, where it's a little safer, but we want the ebp
  159. // from this frame to find it.
  160. uintptr_t current_ebp = (uintptr_t)_getfp();
  161. pthread_mutex_lock(&handler_stack_mutex_);
  162. ExceptionHandler *current_handler =
  163. handler_stack_->at(handler_stack_->size() - ++handler_stack_index_);
  164. pthread_mutex_unlock(&handler_stack_mutex_);
  165. // Restore original handler.
  166. current_handler->TeardownHandler(signo);
  167. ucontext_t *sig_ctx = NULL;
  168. if (current_handler->InternalWriteMinidump(signo, current_ebp, &sig_ctx)) {
  169. // if (current_handler->InternalWriteMinidump(signo, &sig_ctx)) {
  170. // Fully handled this exception, safe to exit.
  171. exit(EXIT_FAILURE);
  172. } else {
  173. // Exception not fully handled, will call the next handler in stack to
  174. // process it.
  175. typedef void (*SignalHandler)(int signo);
  176. SignalHandler old_handler =
  177. reinterpret_cast<SignalHandler>(current_handler->old_handlers_[signo]);
  178. if (old_handler != NULL)
  179. old_handler(signo);
  180. }
  181. pthread_mutex_lock(&handler_stack_mutex_);
  182. current_handler->SetupHandler(signo);
  183. --handler_stack_index_;
  184. // All the handlers in stack have been invoked to handle the exception,
  185. // normally the process should be terminated and should not reach here.
  186. // In case we got here, ask the OS to handle it to avoid endless loop,
  187. // normally the OS will generate a core and termiate the process. This
  188. // may be desired to debug the program.
  189. if (handler_stack_index_ == 0)
  190. signal(signo, SIG_DFL);
  191. pthread_mutex_unlock(&handler_stack_mutex_);
  192. }
  193. bool ExceptionHandler::InternalWriteMinidump(int signo,
  194. uintptr_t sighandler_ebp,
  195. ucontext_t **sig_ctx) {
  196. if (filter_ && !filter_(callback_context_))
  197. return false;
  198. bool success = false;
  199. GUID guid;
  200. char guid_str[kGUIDStringLength + 1];
  201. if (CreateGUID(&guid) && GUIDToString(&guid, guid_str, sizeof(guid_str))) {
  202. char minidump_path[PATH_MAX];
  203. snprintf(minidump_path, sizeof(minidump_path), "%s/%s.dmp",
  204. dump_path_c_, guid_str);
  205. // Block all the signals we want to process when writing minidump.
  206. // We don't want it to be interrupted.
  207. sigset_t sig_blocked, sig_old;
  208. bool blocked = true;
  209. sigfillset(&sig_blocked);
  210. for (size_t i = 0; i < sizeof(kSigTable) / sizeof(kSigTable[0]); ++i)
  211. sigdelset(&sig_blocked, kSigTable[i]);
  212. if (sigprocmask(SIG_BLOCK, &sig_blocked, &sig_old) != 0) {
  213. blocked = false;
  214. print_message1(2, "HandleException: failed to block signals.\n");
  215. }
  216. success = minidump_generator_.WriteMinidumpToFile(
  217. minidump_path, signo, sighandler_ebp, sig_ctx);
  218. // Unblock the signals.
  219. if (blocked)
  220. sigprocmask(SIG_SETMASK, &sig_old, &sig_old);
  221. if (callback_)
  222. success = callback_(dump_path_c_, guid_str, callback_context_, success);
  223. }
  224. return success;
  225. }
  226. } // namespace google_breakpad