mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-12 18:30:25 +01:00
In progress ... reverting back to the example code make it ALL work
(in DEBUG)
This commit is contained in:
parent
bd2b89f9de
commit
3a234929e5
17
compare.txt
Normal file
17
compare.txt
Normal 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
|
177
src/crashhandler_windows.cpp
Normal file
177
src/crashhandler_windows.cpp
Normal 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(¤t_context, 0, sizeof(CONTEXT));
|
||||
RtlCaptureContext(¤t_context);
|
||||
stack_trace sttrace(¤t_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
178
src/working_trace.hpp
Normal 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(¤t_context);
|
||||
// context = ¤t_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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user