exception_handler.cc

来自「SumatraPDF是一款小型开源的pdf阅读工具。虽然玲珑小巧(只有800多K」· CC 代码 · 共 534 行 · 第 1/2 页

CC
534
字号
// staticLONG ExceptionHandler::HandleException(EXCEPTION_POINTERS *exinfo) {  AutoExceptionHandler auto_exception_handler;  ExceptionHandler *current_handler = auto_exception_handler.get_handler();  // Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions.  This  // logic will short-circuit before calling WriteMinidumpOnHandlerThread,  // allowing something else to handle the breakpoint without incurring the  // overhead transitioning to and from the handler thread.  DWORD code = exinfo->ExceptionRecord->ExceptionCode;  LONG action;  if (code != EXCEPTION_BREAKPOINT && code != EXCEPTION_SINGLE_STEP &&      current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL)) {    // The handler fully handled the exception.  Returning    // EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually    // results in the applicaiton being terminated.    //    // Note: If the application was launched from within the Cygwin    // environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the    // application to be restarted.    action = EXCEPTION_EXECUTE_HANDLER;  } else {    // There was an exception, it was a breakpoint or something else ignored    // above, or it was passed to the handler, which decided not to handle it.    // This could be because the filter callback didn't want it, because    // minidump writing failed for some reason, or because the post-minidump    // callback function indicated failure.  Give the previous handler a    // chance to do something with the exception.  If there is no previous    // handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger    // or native "crashed" dialog to handle the exception.    if (current_handler->previous_filter_) {      action = current_handler->previous_filter_(exinfo);    } else {      action = EXCEPTION_CONTINUE_SEARCH;    }  }  return action;}#if _MSC_VER >= 1400  // MSVC 2005/8// staticvoid ExceptionHandler::HandleInvalidParameter(const wchar_t *expression,                                              const wchar_t *function,                                              const wchar_t *file,                                              unsigned int line,                                              uintptr_t reserved) {  // This is an invalid parameter, not an exception.  It's safe to play with  // sprintf here.  AutoExceptionHandler auto_exception_handler;  ExceptionHandler *current_handler = auto_exception_handler.get_handler();  MDRawAssertionInfo assertion;  memset(&assertion, 0, sizeof(assertion));  _snwprintf_s(reinterpret_cast<wchar_t *>(assertion.expression),               sizeof(assertion.expression) / sizeof(assertion.expression[0]),               _TRUNCATE, L"%s", expression);  _snwprintf_s(reinterpret_cast<wchar_t *>(assertion.function),               sizeof(assertion.function) / sizeof(assertion.function[0]),               _TRUNCATE, L"%s", function);  _snwprintf_s(reinterpret_cast<wchar_t *>(assertion.file),               sizeof(assertion.file) / sizeof(assertion.file[0]),               _TRUNCATE, L"%s", file);  assertion.line = line;  assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;  if (!current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion)) {    if (current_handler->previous_iph_) {      // The handler didn't fully handle the exception.  Give it to the      // previous invalid parameter handler.      current_handler->previous_iph_(expression, function, file, line, reserved);    } else {      // If there's no previous handler, pass the exception back in to the      // invalid parameter handler's core.  That's the routine that called this      // function, but now, since this function is no longer registered (and in      // fact, no function at all is registered), this will result in the      // default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson.      // Use _invalid_parameter where it exists (in _DEBUG builds) as it passes      // more information through.  In non-debug builds, it is not available,      // so fall back to using _invalid_parameter_noinfo.  See invarg.c in the      // CRT source.#ifdef _DEBUG      _invalid_parameter(expression, function, file, line, reserved);#else  // _DEBUG      _invalid_parameter_noinfo();#endif  // _DEBUG    }  }  // The handler either took care of the invalid parameter problem itself,  // or passed it on to another handler.  "Swallow" it by exiting, paralleling  // the behavior of "swallowing" exceptions.  exit(0);}#endif  // _MSC_VER >= 1400// staticvoid ExceptionHandler::HandlePureVirtualCall() {  AutoExceptionHandler auto_exception_handler;  ExceptionHandler *current_handler = auto_exception_handler.get_handler();  MDRawAssertionInfo assertion;  memset(&assertion, 0, sizeof(assertion));  assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;  if (!current_handler->WriteMinidumpOnHandlerThread(NULL, &assertion)) {    if (current_handler->previous_pch_) {      // The handler didn't fully handle the exception.  Give it to the      // previous purecall handler.      current_handler->previous_pch_();    } else {      // If there's no previous handler, return and let _purecall handle it.      // This will just put up an assertion dialog.      return;    }  }  // The handler either took care of the invalid parameter problem itself,  // or passed it on to another handler.  "Swallow" it by exiting, paralleling  // the behavior of "swallowing" exceptions.  exit(0);}bool ExceptionHandler::WriteMinidumpOnHandlerThread(    EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion) {  EnterCriticalSection(&handler_critical_section_);  // Set up data to be passed in to the handler thread.  requesting_thread_id_ = GetCurrentThreadId();  exception_info_ = exinfo;  assertion_ = assertion;  // This causes the handler thread to call WriteMinidumpWithException.  ReleaseSemaphore(handler_start_semaphore_, 1, NULL);  // Wait until WriteMinidumpWithException is done and collect its return value.  WaitForSingleObject(handler_finish_semaphore_, INFINITE);  bool status = handler_return_value_;  // Clean up.  requesting_thread_id_ = 0;  exception_info_ = NULL;  assertion_ = NULL;  LeaveCriticalSection(&handler_critical_section_);  return status;}bool ExceptionHandler::WriteMinidump() {  return WriteMinidumpForException(NULL);}bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS *exinfo) {  bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);  UpdateNextID();  return success;}// staticbool ExceptionHandler::WriteMinidump(const wstring &dump_path,                                     MinidumpCallback callback,                                     void *callback_context) {  ExceptionHandler handler(dump_path, NULL, callback, callback_context,                           HANDLER_NONE);  return handler.WriteMinidump();}bool ExceptionHandler::WriteMinidumpWithException(    DWORD requesting_thread_id,    EXCEPTION_POINTERS *exinfo,    MDRawAssertionInfo *assertion) {  // Give user code a chance to approve or prevent writing a minidump.  If the  // filter returns false, don't handle the exception at all.  If this method  // was called as a result of an exception, returning false will cause  // HandleException to call any previous handler or return  // EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear  // as though this handler were not present at all.  if (filter_ && !filter_(callback_context_, exinfo, assertion)) {    return false;  }  bool success = false;  if (minidump_write_dump_) {    HANDLE dump_file = CreateFileW(next_minidump_path_c_,                                  GENERIC_WRITE,                                  0,  // no sharing                                  NULL,                                  CREATE_NEW,  // fail if exists                                  FILE_ATTRIBUTE_NORMAL,                                  NULL);    if (dump_file != INVALID_HANDLE_VALUE) {      MINIDUMP_EXCEPTION_INFORMATION except_info;      except_info.ThreadId = requesting_thread_id;      except_info.ExceptionPointers = exinfo;      except_info.ClientPointers = FALSE;      // Add an MDRawBreakpadInfo stream to the minidump, to provide additional      // information about the exception handler to the Breakpad processor.  The      // information will help the processor determine which threads are      // relevant.  The Breakpad processor does not require this information but      // can function better with Breakpad-generated dumps when it is present.      // The native debugger is not harmed by the presence of this information.      MDRawBreakpadInfo breakpad_info;      breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |                             MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;      breakpad_info.dump_thread_id = GetCurrentThreadId();      breakpad_info.requesting_thread_id = requesting_thread_id;      // Leave room in user_stream_array for a possible assertion info stream.      MINIDUMP_USER_STREAM user_stream_array[2];      user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;      user_stream_array[0].BufferSize = sizeof(breakpad_info);      user_stream_array[0].Buffer = &breakpad_info;      MINIDUMP_USER_STREAM_INFORMATION user_streams;      user_streams.UserStreamCount = 1;      user_streams.UserStreamArray = user_stream_array;      if (assertion) {        user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;        user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);        user_stream_array[1].Buffer = assertion;        ++user_streams.UserStreamCount;      }      // The explicit comparison to TRUE avoids a warning (C4800).      success = (minidump_write_dump_(GetCurrentProcess(),                                      GetCurrentProcessId(),                                      dump_file,                                      MiniDumpNormal,                                      exinfo ? &except_info : NULL,                                      &user_streams,                                      NULL) == TRUE);      CloseHandle(dump_file);    }  }  if (callback_) {    success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,                        exinfo, assertion, success);  }  return success;}void ExceptionHandler::UpdateNextID() {  GUID id;  CoCreateGuid(&id);  next_minidump_id_ = GUIDString::GUIDToWString(&id);  next_minidump_id_c_ = next_minidump_id_.c_str();  wchar_t minidump_path[MAX_PATH];  swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",           dump_path_c_, next_minidump_id_c_);  // remove when VC++7.1 is no longer supported  minidump_path[MAX_PATH - 1] = L'\0';  next_minidump_path_ = minidump_path;  next_minidump_path_c_ = next_minidump_path_.c_str();}}  // namespace google_breakpad

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?