mirror of
https://github.com/KjellKod/g3log.git
synced 2024-12-13 02:32:56 +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