Index: chrome_frame/crash_reporting/vectored_handler-impl.h |
diff --git a/chrome_frame/crash_reporting/vectored_handler-impl.h b/chrome_frame/crash_reporting/vectored_handler-impl.h |
deleted file mode 100644 |
index eb317a8c78cb365eb5d9e2ea55e4e68c64b1ca34..0000000000000000000000000000000000000000 |
--- a/chrome_frame/crash_reporting/vectored_handler-impl.h |
+++ /dev/null |
@@ -1,289 +0,0 @@ |
-// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#ifndef CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ |
-#define CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ |
- |
-#include "base/logging.h" |
-#include "chrome_frame/crash_reporting/vectored_handler.h" |
-#include "chrome_frame/crash_reporting/nt_loader.h" |
- |
-#if !defined(_M_IX86) |
-#error only x86 is supported for now. |
-#endif |
- |
-#ifndef EXCEPTION_CHAIN_END |
-#define EXCEPTION_CHAIN_END ((struct _EXCEPTION_REGISTRATION_RECORD*)-1) |
-#if !defined(_WIN32_WINNT_WIN8) |
-typedef struct _EXCEPTION_REGISTRATION_RECORD { |
- struct _EXCEPTION_REGISTRATION_RECORD* Next; |
- PVOID Handler; |
-} EXCEPTION_REGISTRATION_RECORD; |
-// VEH handler flags settings. |
-// These are grabbed from winnt.h for PocketPC. |
-// Only EXCEPTION_NONCONTINUABLE in defined in "regular" winnt.h |
-// #define EXCEPTION_NONCONTINUABLE 0x1 // Noncontinuable exception |
-#define EXCEPTION_UNWINDING 0x2 // Unwind is in progress |
-#define EXCEPTION_EXIT_UNWIND 0x4 // Exit unwind is in progress |
-#define EXCEPTION_STACK_INVALID 0x8 // Stack out of limits or unaligned |
-#define EXCEPTION_NESTED_CALL 0x10 // Nested exception handler call |
-#define EXCEPTION_TARGET_UNWIND 0x20 // Target unwind in progress |
-#define EXCEPTION_COLLIDED_UNWIND 0x40 // Collided exception handler call |
- |
-#define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | \ |
- EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND) |
- |
-#define IS_UNWINDING(Flag) (((Flag) & EXCEPTION_UNWIND) != 0) |
-#define IS_DISPATCHING(Flag) (((Flag) & EXCEPTION_UNWIND) == 0) |
-#define IS_TARGET_UNWIND(Flag) ((Flag) & EXCEPTION_TARGET_UNWIND) |
-#endif // !defined(_WIN32_WINNT_WIN8) |
-#endif // EXCEPTION_CHAIN_END |
- |
-template <typename E> |
-VectoredHandlerT<E>::VectoredHandlerT(E* api) : exceptions_seen_(0), api_(api) { |
-} |
- |
-template <typename E> |
-VectoredHandlerT<E>::~VectoredHandlerT() { |
-} |
- |
-template <typename E> |
-LONG VectoredHandlerT<E>::Handler(EXCEPTION_POINTERS* exceptionInfo) { |
- // TODO(stoyan): Consider reentrancy |
- const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode; |
- |
- // Not interested in non-error exceptions. In this category falls exceptions |
- // like: |
- // 0x40010006 - OutputDebugStringA. Seen when no debugger is attached |
- // (otherwise debugger swallows the exception and prints |
- // the string). |
- // 0x406D1388 - DebuggerProbe. Used by debug CRT - for example see source |
- // code of isatty(). Used to name a thread as well. |
- // RPC_E_DISCONNECTED and Co. - COM IPC non-fatal warnings |
- // STATUS_BREAKPOINT and Co. - Debugger related breakpoints |
- if ((exceptionCode & ERROR_SEVERITY_ERROR) != ERROR_SEVERITY_ERROR) { |
- return ExceptionContinueSearch; |
- } |
- |
- // Ignore custom exception codes. |
- // MSXML likes to raise 0xE0000001 while parsing. |
- // Note the C++ SEH (0xE06D7363) also fails in that range. |
- if (exceptionCode & APPLICATION_ERROR_MASK) { |
- return ExceptionContinueSearch; |
- } |
- |
- exceptions_seen_++; |
- |
- // If the exception code is STATUS_STACK_OVERFLOW then proceed as usual - |
- // we want to report it. Otherwise check whether guard page in stack is gone - |
- // i.e. stack overflow has been already observed and most probably we are |
- // seeing the follow-up STATUS_ACCESS_VIOLATION(s). See bug 32441. |
- if (exceptionCode != STATUS_STACK_OVERFLOW && api_->CheckForStackOverflow()) { |
- return ExceptionContinueSearch; |
- } |
- |
- // Check whether exception will be handled by the module that cuased it. |
- // This should automatically handle the case of IsBadReadPtr and family. |
- const EXCEPTION_REGISTRATION_RECORD* seh = api_->RtlpGetExceptionList(); |
- if (api_->ShouldIgnoreException(exceptionInfo, seh)) { |
- return ExceptionContinueSearch; |
- } |
- |
- const DWORD exceptionFlags = exceptionInfo->ExceptionRecord->ExceptionFlags; |
- // I don't think VEH is called on unwind. Just to be safe. |
- if (IS_DISPATCHING(exceptionFlags)) { |
- if (ModuleHasInstalledSEHFilter()) |
- return ExceptionContinueSearch; |
- |
- if (api_->IsOurModule(exceptionInfo->ExceptionRecord->ExceptionAddress)) { |
- api_->WriteDump(exceptionInfo); |
- return ExceptionContinueSearch; |
- } |
- |
- // See whether our module is somewhere in the call stack. |
- void* back_trace[E::max_back_trace] = {0}; |
- DWORD captured = api_->RtlCaptureStackBackTrace(0, api_->max_back_trace, |
- &back_trace[0], NULL); |
- for (DWORD i = 0; i < captured; ++i) { |
- if (api_->IsOurModule(back_trace[i])) { |
- api_->WriteDump(exceptionInfo); |
- return ExceptionContinueSearch; |
- } |
- } |
- } |
- |
- return ExceptionContinueSearch; |
-} |
- |
-template <typename E> |
-bool VectoredHandlerT<E>::ModuleHasInstalledSEHFilter() { |
- const EXCEPTION_REGISTRATION_RECORD* RegistrationFrame = |
- api_->RtlpGetExceptionList(); |
- // TODO(stoyan): Add the stack limits check and some sanity checks like |
- // decreasing addresses of registration records |
- while (RegistrationFrame != EXCEPTION_CHAIN_END) { |
- if (api_->IsOurModule(RegistrationFrame->Handler)) { |
- return true; |
- } |
- |
- RegistrationFrame = RegistrationFrame->Next; |
- } |
- |
- return false; |
-} |
- |
- |
-// Here comes the default Windows 32-bit implementation. |
-namespace { |
- __declspec(naked) |
- static EXCEPTION_REGISTRATION_RECORD* InternalRtlpGetExceptionList() { |
- __asm { |
- mov eax, fs:0 |
- ret |
- } |
- } |
- |
- __declspec(naked) |
- static char* GetStackTopLimit() { |
- __asm { |
- mov eax, fs:8 |
- ret |
- } |
- } |
-} // end of namespace |
- |
-// Class which methods simply forwards to Win32 API. |
-// Used as template (external interface) of VectoredHandlerT<E>. |
-class Win32VEHTraits { |
- public: |
- enum {max_back_trace = 62}; |
- |
- static inline |
- EXCEPTION_REGISTRATION_RECORD* RtlpGetExceptionList() { |
- return InternalRtlpGetExceptionList(); |
- } |
- |
- static inline WORD RtlCaptureStackBackTrace(DWORD FramesToSkip, |
- DWORD FramesToCapture, void** BackTrace, DWORD* BackTraceHash) { |
- return ::RtlCaptureStackBackTrace(FramesToSkip, FramesToCapture, |
- BackTrace, BackTraceHash); |
- } |
- |
- static bool ShouldIgnoreException(const EXCEPTION_POINTERS* exceptionInfo, |
- const EXCEPTION_REGISTRATION_RECORD* seh_record) { |
- const void* address = exceptionInfo->ExceptionRecord->ExceptionAddress; |
- const DWORD flags = GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT | |
- GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS; |
- HMODULE crashing_module = GetModuleHandleFromAddress(address); |
- if (!crashing_module) |
- return false; |
- |
- HMODULE top_seh_module = NULL; |
- if (EXCEPTION_CHAIN_END != seh_record) |
- top_seh_module = GetModuleHandleFromAddress(seh_record->Handler); |
- |
- // check if the crash address belongs in a module that's expecting |
- // and handling it. This should address cases like kernel32!IsBadXXX |
- // and urlmon!IsValidInterface |
- if (crashing_module == top_seh_module) |
- return true; |
- |
- // We don't want to report exceptions that occur during DLL loading, |
- // as those are captured and ignored by the NT loader. If this thread |
- // is holding the loader's lock, there's a possiblity that the crash |
- // is occurring in a loading DLL, in which case we resolve the |
- // crash address to a module and check on the module's status. |
- if (nt_loader::OwnsLoaderLock()) { |
- nt_loader::LDR_DATA_TABLE_ENTRY* entry = |
- nt_loader::GetLoaderEntry(crashing_module); |
- |
- // If: |
- // 1. we found the entry in question, and |
- // 2. the entry is a DLL (has the IMAGE_DLL flag set), and |
- // 3. the DLL has a non-null entrypoint, and |
- // 4. the loader has not tagged it with the process attached called flag |
- // we conclude that the crash is most likely during the loading of the |
- // module and bail on reporting the crash to avoid false positives |
- // during crashes that occur during module loads, such as e.g. when |
- // the hook manager attempts to load buggy window hook DLLs. |
- if (entry && |
- (entry->Flags & LDRP_IMAGE_DLL) != 0 && |
- (entry->EntryPoint != NULL) && |
- (entry->Flags & LDRP_PROCESS_ATTACH_CALLED) == 0) |
- return true; |
- } |
- |
- return false; |
- } |
- |
- static bool CheckForStackOverflow() { |
- MEMORY_BASIC_INFORMATION mi = {0}; |
- const DWORD kPageSize = 0x1000; |
- void* stack_top = GetStackTopLimit() - kPageSize; |
- ::VirtualQuery(stack_top, &mi, sizeof(mi)); |
- // The above call may result in moving the top of the stack. |
- // Check once more. |
- void* stack_top2 = GetStackTopLimit() - kPageSize; |
- if (stack_top2 != stack_top) |
- ::VirtualQuery(stack_top2, &mi, sizeof(mi)); |
- return !(mi.Protect & PAGE_GUARD); |
- } |
- |
- private: |
- static inline const void* CodeOffset(const void* code, int offset) { |
- return reinterpret_cast<const char*>(code) + offset; |
- } |
- |
- static HMODULE GetModuleHandleFromAddress(const void* p) { |
- HMODULE module_at_address = NULL; |
- MEMORY_BASIC_INFORMATION mi = {0}; |
- if (::VirtualQuery(p, &mi, sizeof(mi)) && (mi.Type & MEM_IMAGE)) { |
- module_at_address = reinterpret_cast<HMODULE>(mi.AllocationBase); |
- } |
- |
- return module_at_address; |
- } |
-}; |
- |
- |
-// Use Win32 API; checks for single (current) module. Will call a specified |
-// CrashHandlerTraits::DumpHandler when taking a dump. |
-class CrashHandlerTraits : public Win32VEHTraits, |
- public ModuleOfInterestWithExcludedRegion { |
- public: |
- |
- typedef bool (*DumpHandler)(EXCEPTION_POINTERS* p); |
- |
- CrashHandlerTraits() : dump_handler_(NULL) {} |
- |
- // Note that breakpad_lock must be held when this is called. |
- void Init(const void* veh_segment_start, const void* veh_segment_end, |
- DumpHandler dump_handler) { |
- DCHECK(dump_handler); |
- dump_handler_ = dump_handler; |
- ModuleOfInterestWithExcludedRegion::SetCurrentModule(); |
- // Pointers to static (non-extern) functions take the address of the |
- // function's first byte, as opposed to an entry in the compiler generated |
- // JMP table. In release builds /OPT:REF wipes away the JMP table, but debug |
- // builds are not so lucky. |
- ModuleOfInterestWithExcludedRegion::SetExcludedRegion(veh_segment_start, |
- veh_segment_end); |
- } |
- |
- void Shutdown() { |
- } |
- |
- inline bool WriteDump(EXCEPTION_POINTERS* p) { |
- if (dump_handler_) { |
- return dump_handler_(p); |
- } else { |
- return false; |
- } |
- } |
- |
- private: |
- DumpHandler dump_handler_; |
-}; |
- |
-#endif // CHROME_FRAME_CRASH_REPORTING_VECTORED_HANDLER_IMPL_H_ |