In progress ... reverting back to the example code make it ALL work

(in DEBUG)
This commit is contained in:
Kjell Hedstrom 2015-01-11 22:21:40 -07:00
parent bd2b89f9de
commit 3a234929e5
3 changed files with 372 additions and 0 deletions

17
compare.txt Normal file
View File

@ -0,0 +1,17 @@
SIGFPE
SIGSEGV
SIGILL
must have signal registred per thread
SIGSEGV -- ger ingen stacktrace även fast den är registrerad?
SIGILL -- ger ingen stacktrace i annan tråd även fast den är registrerad
Divison-by-zero verkar inte FÅNGAS ALLS I g3log
MEN DEN FÅNGAS I code/stacktrace både i annan tråd o i vanlig tråd ÄVEN fast den inte är registrerad
Access-violation ger bogus crashdump i g3log
Access-violation ger BRA crashdump i code/stacktrace

View File

@ -0,0 +1,177 @@
/** ==========================================================================
* 2011 by KjellKod.cc. This is PUBLIC DOMAIN to use at your own risk and comes
* with no warranties. This code is yours to share, use and modify with no
* strings attached and no restrictions or obligations.
*
* For more information see g3log/LICENSE or refer refer to http://unlicense.org
* ============================================================================*/
#if !(defined(WIN32) || defined(_WIN32) || defined(__WIN32__))
#error "crashhandler_windows.cpp used but not on a windows system"
#endif
#include <windows.h>
#include <csignal>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <process.h> // getpid
#define getpid _getpid
#include "crashhandler.hpp"
#include "stacktrace_windows.hpp"
#include "g2logmessage.hpp"
#include "g2logmessagecapture.hpp"
#include <working_trace.hpp>
#include <iostream> // TODO REMOVE
// TODO for every LOG or CHECK i should have a thread_local to re-instantiate the signal-handler if we are on windows
// not all signal handlers need to be re-installed
namespace {
void signalHandler(int signal_number) {
using namespace g2::internal;
std::ostringstream fatal_stream;
fatal_stream << "\n\n***** FATAL TRIGGER RECEIVED ******* " << std::endl;
fatal_stream << "\n***** RETHROWING SIGNAL " << signalName(signal_number) << "(" << signal_number << ")" << std::endl;
//const auto dump = stackdump();
/*********** START HACK ************/
CONTEXT current_context;
memset(&current_context, 0, sizeof(CONTEXT));
RtlCaptureContext(&current_context);
stack_trace sttrace(&current_context);
const auto dump = sttrace.to_string();
/************ STOP HACk ***********/
LogCapture trigger(FATAL_SIGNAL, signal_number, dump.c_str());
trigger.stream() << fatal_stream.str();
} // scope exit - message sent to LogWorker, wait to die...
//
// Unhandled exception catching
LONG WINAPI exceptionHandling(EXCEPTION_POINTERS* info) {
const auto exception_code = info->ExceptionRecord->ExceptionCode;
//const auto exceptionText = stacktrace::exceptionIdToText(exception_code);
/**** START HACK ****/
stack_trace sttrace(info->ContextRecord);
// if there is a windows exception then call it like THIS
auto exceptionText = sttrace.to_string();
/**** STOP HACK ***/
//std::cout << "\nexceptionHandling: " << __FUNCTION__ << ", received: " << exceptionText << std::endl;
LogCapture trigger(g2::internal::FATAL_EXCEPTION, SIGABRT /*LogCapture::kExceptionAndNotASignal*/, exceptionText.c_str());
// TODO .... after exit it should NOT throw SIGABRT
// it should instead make sure that it stopps blocking forever
return EXCEPTION_CONTINUE_SEARCH; //EXCEPTION_EXECUTE_HANDLER;
}
/// Setup through (Windows API) AddVectoredExceptionHandler
/// Running exceptions in a Windows debugger might make it impossible to hit the exception handlers
/// Ref: http://blogs.msdn.com/b/zhanli/archive/2010/06/25/c-tips-addvectoredexceptionhandler-addvectoredcontinuehandler-and-setunhandledexceptionfilter.aspx
LONG WINAPI vectorExceptionHandling(PEXCEPTION_POINTERS p) {
std::cout << "\nIn my vectored exception_filter: " << __FUNCTION__ << std::endl;
return exceptionHandling(p);
}
} // end anonymous namespace
namespace g2 {
namespace internal {
/// Generate stackdump. Or in case a stackdump was pre-generated and non-empty just use that one
/// i.e. the latter case is only for Windows and test purposes
std::string stackdump(const char *dump) {
if (nullptr != dump && !std::string(dump).empty()) {
return {dump};
}
return stacktrace::stackdump();
}
/// string representation of signal ID
std::string signalName(int signal_number) {
switch (signal_number) {
case SIGABRT: return "SIGABRT";
break;
case SIGFPE: return "SIGFPE";
break;
case SIGSEGV: return "SIGSEGV";
break;
case SIGILL: return "SIGILL";
break;
case SIGTERM: return "SIGTERM";
break;
default:
std::ostringstream oss;
oss << "UNKNOWN SIGNAL(" << signal_number << ")";
return oss.str();
}
}
// Triggered by g2log::LogWorker after receiving a FATAL trigger
// which is LOG(FATAL), CHECK(false) or a fatal signal our signalhandler caught.
// --- If LOG(FATAL) or CHECK(false) the signal_number will be SIGABRT
void exitWithDefaultSignalHandler(int signal_number) {
// Restore our signalhandling to default
if (SIG_ERR == signal(SIGABRT, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGSEGV, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGILL, SIG_DFL))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGTERM, SIG_DFL))
perror("signal - SIGABRT");
raise(signal_number);
}
void installSignalHandler() {
if (SIG_ERR == signal(SIGABRT, signalHandler))
perror("signal - SIGABRT");
if (SIG_ERR == signal(SIGFPE, signalHandler))
perror("signal - SIGFPE");
if (SIG_ERR == signal(SIGSEGV, signalHandler))
perror("signal - SIGSEGV");
if (SIG_ERR == signal(SIGILL, signalHandler))
perror("signal - SIGILL");
if (SIG_ERR == signal(SIGTERM, signalHandler))
perror("signal - SIGTERM");
}
} // end g2::internal
void installCrashHandler() {
// TODO,. instead of existing at fatal incidents we should catch it
// flush all to logs,. call ShutdownLogging(?) and re-throw the signal
// or the exception (i.e .the normal )
internal::installSignalHandler();
//const size_t kFirstExceptionHandler = 1;
const size_t kLastExceptionHandler = 0;
// http://msdn.microsoft.com/en-us/library/windows/desktop/ms679274%28v=vs.85%29.aspx
AddVectoredExceptionHandler(kLastExceptionHandler, vectorExceptionHandling);
SetUnhandledExceptionFilter(exceptionHandling);
}
} // end namespace g2

178
src/working_trace.hpp Normal file
View File

@ -0,0 +1,178 @@
#pragma once
//Public domain dedication by Robert Engeln
// Originally published at: http://code-freeze.blogspot.com/2012/01/generating-stack-traces-from-c.html
#include <windows.h>
#include <DbgHelp.h>
#include <stdio.h>
#include <conio.h>
#include <csignal>
#include <iostream>
#include <string>
#include <sstream>
// temporary
#include <cassert>
class sym_handler
{
public:
static sym_handler& get_instance()
{
static sym_handler instance;
return instance;
}
std::string get_symbol_info(DWORD64 addr)
{
std::stringstream ss;
DWORD64 displacement64;
DWORD displacement;
char symbol_buffer[sizeof(SYMBOL_INFO) + 256];
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(symbol_buffer);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = 255;
IMAGEHLP_LINE64 line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
// ss << addr;
if (m_initialized)
{
if (SymFromAddr(GetCurrentProcess(),
addr,
&displacement64,
symbol))
{
ss << " " << std::string(symbol->Name, symbol->NameLen) << std::endl;
if (SymGetLineFromAddr64(GetCurrentProcess(),
addr,
&displacement,
&line))
{
ss << "File Name:" << line.FileName << " line: " << line.LineNumber;
}
}
else{
DWORD err = GetLastError();
}
}
return ss.str();
}
void capture_stack_trace(CONTEXT* context, DWORD64* frame_ptrs, size_t count)
{
if (m_initialized)
{
assert(context);
//CONTEXT current_context;
//// In the case of a windows exception then the context
//// wil be pre-set (ref: windows_exception_handler)
//// ACTUALLY ... Why can't the signal handler call
//// RtlCaptureContext.
//if (!context)
//{
// RtlCaptureContext(&current_context);
// context = &current_context;
//}
DWORD machine_type;
STACKFRAME64 frame;
ZeroMemory(&frame, sizeof(frame));
frame.AddrPC.Mode = AddrModeFlat;
frame.AddrFrame.Mode = AddrModeFlat;
frame.AddrStack.Mode = AddrModeFlat;
#ifdef _M_X64
frame.AddrPC.Offset = context->Rip;
frame.AddrFrame.Offset = context->Rbp;
frame.AddrStack.Offset = context->Rsp;
machine_type = IMAGE_FILE_MACHINE_AMD64;
#else
frame.AddrPC.Offset = context->Eip;
frame.AddrPC.Offset = context->Ebp;
frame.AddrPC.Offset = context->Esp;
machine_type = IMAGE_FILE_MACHINE_I386;
#endif
for (size_t i = 0; i < count; i++)
{
if (StackWalk64(machine_type,
GetCurrentProcess(),
GetCurrentThread(),
&frame,
context,
NULL,
SymFunctionTableAccess64,
SymGetModuleBase64,
NULL))
{
frame_ptrs[i] = frame.AddrPC.Offset;
}
else
{
break;
}
}
}
}
private:
sym_handler()
{
m_initialized = SymInitialize(GetCurrentProcess(), NULL, TRUE) == TRUE;
}
~sym_handler()
{
if (m_initialized)
{
SymCleanup(GetCurrentProcess());
m_initialized = false;
}
}
bool m_initialized;
};
class stack_trace
{
public:
stack_trace(CONTEXT* context)
{
ZeroMemory(m_frame_ptrs, sizeof(m_frame_ptrs));
sym_handler::get_instance().capture_stack_trace(context,
m_frame_ptrs,
max_frame_ptrs);
}
std::string to_string() const
{
std::stringstream ss;
for (size_t i = 0;
i < max_frame_ptrs && m_frame_ptrs[i];
++i)
{
ss << sym_handler::get_instance().get_symbol_info(m_frame_ptrs[i]) << "\n";
}
return ss.str();
}
private:
static const size_t max_frame_ptrs = 16;
DWORD64 m_frame_ptrs[max_frame_ptrs];
};
inline std::string to_string(const stack_trace& trace)
{
return trace.to_string();
}