diff --git a/dist/dwarfstack/32/dwarfstack.dll b/dist/dwarfstack/32/dwarfstack.dll new file mode 100644 index 0000000..74b9796 Binary files /dev/null and b/dist/dwarfstack/32/dwarfstack.dll differ diff --git a/dist/dwarfstack/64/dwarfstack.dll b/dist/dwarfstack/64/dwarfstack.dll new file mode 100644 index 0000000..8944c72 Binary files /dev/null and b/dist/dwarfstack/64/dwarfstack.dll differ diff --git a/dist/dwarfstack/readme.md b/dist/dwarfstack/readme.md new file mode 100644 index 0000000..c8ce1e3 --- /dev/null +++ b/dist/dwarfstack/readme.md @@ -0,0 +1 @@ +Version/release: https://github.com/ssbssa/dwarfstack/releases/tag/2.2 \ No newline at end of file diff --git a/src/imports/dwarfstack.h b/src/imports/dwarfstack.h new file mode 100644 index 0000000..ba2d23c --- /dev/null +++ b/src/imports/dwarfstack.h @@ -0,0 +1,162 @@ +/* + * Copyright (C) 2013-2019 Hannes Domani + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#ifndef __DWARFSTACK_H__ +#define __DWARFSTACK_H__ + +#include + + +#if defined(DWST_STATIC) +#define EXPORT +#elif defined(DWST_SHARED) +#define EXPORT __declspec(dllexport) +#else +#define EXPORT __declspec(dllimport) +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + + +// dwstCallback(): callback function +// addr: stack address +// filename: source file location +// lineno: line number +// funcname: function name +// context: user-provided pointer (callbackContext) +// columnno: column number +typedef void dwstCallback( + uint64_t addr,const char *filename,int lineno,const char *funcname, + void *context,int columnno ); + +typedef void dwstCallbackW( + uint64_t addr,const wchar_t *filename,int lineno,const char *funcname, + void *context,int columnno ); + +// special values for lineno: + +// DWST_BASE_ADDR: inform about the used image base address +// (important in case it's not the same as the preferred image base address) +// addr: used image base address +// filename: executable location +#define DWST_BASE_ADDR 0 + +// DWST_NO_DBG_SYM: no debug information available +// addr: stack address +// filename: executable location +#define DWST_NO_DBG_SYM -1 + +// DWST_NO_SRC_FILE: no source file information available +// addr: stack address +// filename: executable location +#define DWST_NO_SRC_FILE -2 + +// DWST_NOT_FOUND: no information available (invalid address?) +// addr: stack address +// filename: executable location +#define DWST_NOT_FOUND -3 + + +// dwstOfFile(): stack information of file +// name: executable location +// imageBase: used image base address +// addr: stack addresses +// count: number of addresses +// callbackFunc: callback function +// callbackContext: user-provided pointer (context) +// (for example see examples/addr2line/) +EXPORT int dwstOfFile( + const char *name,uint64_t imageBase, + uint64_t *addr,int count, + dwstCallback *callbackFunc,void *callbackContext ); + +EXPORT int dwstOfFileW( + const wchar_t *name,uint64_t imageBase, + uint64_t *addr,int count, + dwstCallbackW *callbackFunc,void *callbackContext ); + + +// dwstOfProcess(): stack information of current process +// addr: stack addresses +// count: number of addresses +// callbackFunc: callback function +// callbackContext: user-provided pointer (context) +EXPORT int dwstOfProcess( + uintptr_t *addr,int count, + dwstCallback *callbackFunc,void *callbackContext ); + +EXPORT int dwstOfProcessW( + uintptr_t *addr,int count, + dwstCallbackW *callbackFunc,void *callbackContext ); + + +// dwstOfLocation(): stack information of current location +// callbackFunc: callback function +// callbackContext: user-provided pointer (context) +// (for example see examples/location/) +EXPORT int dwstOfLocation( + dwstCallback *callbackFunc,void *callbackContext ); + +EXPORT int dwstOfLocationW( + dwstCallbackW *callbackFunc,void *callbackContext ); + + +// dwstOfException(): stack information of exception +// context: ContextRecord of exception +// callbackFunc: callback function +// callbackContext: user-provided pointer (context) +// (for example see examples/exception/) +EXPORT int dwstOfException( + void *context, + dwstCallback *callbackFunc,void *callbackContext ); + +EXPORT int dwstOfExceptionW( + void *context, + dwstCallbackW *callbackFunc,void *callbackContext ); + + +// dwstExceptionDialog(): show dialog on unhandled exception +// extraInfo: extra information shown in dialog +// (for example see examples/exception-dialog/) +EXPORT void dwstExceptionDialog( + const char *extraInfo ); + +EXPORT void dwstExceptionDialogW( + const wchar_t *extraInfo ); + + +#ifndef DWST_STATIC +// dwstDemangle(): demangle gcc style c++ symbols +// mangled: mangled name +// demangled: demangled name +// length: size of demangled buffer +EXPORT size_t dwstDemangle( + const char *mangled, + char *demangled,size_t length ); +#endif + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/imports/import_32_indep_dwarfstack.def b/src/imports/import_32_indep_dwarfstack.def new file mode 100644 index 0000000..71f1aaf --- /dev/null +++ b/src/imports/import_32_indep_dwarfstack.def @@ -0,0 +1,13 @@ +LIBRARY dwarfstack + +EXPORTS + dwstOfFile @ 441 + dwstOfFileW @ 443 + dwstOfProcess @ 446 + dwstOfProcessW @ 448 + dwstOfLocation @ 444 + dwstOfLocationW @ 445 + dwstOfException @ 438 + dwstOfExceptionW @ 440 + dwstExceptionDialog @ 436 + dwstExceptionDialogW @ 437 \ No newline at end of file diff --git a/src/imports/import_64_indep_dwarfstack.def b/src/imports/import_64_indep_dwarfstack.def new file mode 100644 index 0000000..71f1aaf --- /dev/null +++ b/src/imports/import_64_indep_dwarfstack.def @@ -0,0 +1,13 @@ +LIBRARY dwarfstack + +EXPORTS + dwstOfFile @ 441 + dwstOfFileW @ 443 + dwstOfProcess @ 446 + dwstOfProcessW @ 448 + dwstOfLocation @ 444 + dwstOfLocationW @ 445 + dwstOfException @ 438 + dwstOfExceptionW @ 440 + dwstExceptionDialog @ 436 + dwstExceptionDialogW @ 437 \ No newline at end of file diff --git a/src/main/util/Module.mk b/src/main/util/Module.mk index e6dc7c4..c0273e7 100644 --- a/src/main/util/Module.mk +++ b/src/main/util/Module.mk @@ -5,6 +5,7 @@ src_util := \ cmdline.c \ crc.c \ crypto.c \ + debug.c \ fs.c \ hex.c \ iobuf.c \ diff --git a/src/main/util/debug.c b/src/main/util/debug.c new file mode 100644 index 0000000..7702505 --- /dev/null +++ b/src/main/util/debug.c @@ -0,0 +1,193 @@ +#define LOG_MODULE "util-debug" + +#include + +#include + +#include "core/log.h" + +#include "imports/dwarfstack.h" + +#include "util/debug.h" + +#define EX_DESC(name) \ + case EXCEPTION_##name: \ + desc = " (" #name ")"; \ + break + +#define log_exception(...) _debug_exception_msg("exception", __VA_ARGS__) + +static core_log_message_t _debug_exception_msg; + +static void _debug_stacktrace_printer( + uint64_t addr, + const char *filename, + int lineno, + const char *funcname, + void *context, + int columnno) +{ + int *count; + const char *delim; + void *ptr; + char buffer[512]; + char *buffer_ptr; + + count = context; + delim = strrchr(filename, '/'); + + if (delim) { + filename = delim + 1; + } + + delim = strrchr(filename, '\\'); + + if (delim) { + filename = delim + 1; + } + + ptr = (void *) (uintptr_t) addr; + + switch (lineno) { + case DWST_BASE_ADDR: + log_exception("base address: 0x%p (%s)", ptr, filename); + break; + + case DWST_NOT_FOUND: + case DWST_NO_DBG_SYM: + case DWST_NO_SRC_FILE: + log_exception( + " stack %02d: 0x%p (%s)", (*count)++, ptr, filename); + break; + + default: + buffer_ptr = buffer; + memset(buffer, 0, sizeof(buffer)); + + if (ptr) { + buffer_ptr += sprintf( + buffer_ptr, " stack %02d: 0x%p", (*count)++, ptr); + } else { + buffer_ptr += sprintf( + buffer_ptr, + " %*s", + (int) sizeof(void *) * 2, + ""); + } + + buffer_ptr += sprintf(buffer_ptr, " (%s:%d", filename, lineno); + + if (columnno > 0) { + buffer_ptr += sprintf(buffer_ptr, ":%d", columnno); + } + + buffer_ptr += sprintf(buffer_ptr, ")"); + + if (funcname) { + buffer_ptr += sprintf(buffer_ptr, " [%s]", funcname); + } + + log_exception(buffer); + + break; + } +} + +static LONG WINAPI _debug_unhandled_exception_filter(LPEXCEPTION_POINTERS ep) +{ + DWORD code; + const char *desc; + ULONG_PTR flag; + ULONG_PTR addr; + int count; + + log_exception("=========================================================="); + log_exception("The application has crashed due to an unhandled exception!"); + + code = ep->ExceptionRecord->ExceptionCode; + desc = debug_exception_code_to_str(code); + + log_exception("code: 0x%08lX", code); + log_exception("desc: %s", desc); + + if (code == EXCEPTION_ACCESS_VIOLATION && + ep->ExceptionRecord->NumberParameters == 2) { + flag = ep->ExceptionRecord->ExceptionInformation[0]; + addr = ep->ExceptionRecord->ExceptionInformation[1]; + + log_exception( + "%s violation at 0x%p", + flag == 8 ? "data execution prevention" : + (flag ? "write access" : "read access"), + (void *) addr); + } + + log_exception("stacktrace:"); + + count = 0; + + dwstOfException(ep->ContextRecord, &_debug_stacktrace_printer, &count); + + log_exception("End of stacktrace"); + log_exception("=========================================================="); + + return EXCEPTION_EXECUTE_HANDLER; +} + +void debug_init(core_log_message_t exception_msg) +{ + _debug_exception_msg = exception_msg; + SetUnhandledExceptionFilter(_debug_unhandled_exception_filter); + + log_info("Initialized"); +} + +void debug_print_stacktrace() +{ + int count; + + count = 0; + + log_exception("=========================================================="); + log_exception("Debug stacktrace"); + + dwstOfLocation(&_debug_stacktrace_printer, &count); + + log_exception("End of debug stacktrace"); + log_exception("=========================================================="); +} + +const char *debug_exception_code_to_str(DWORD code) +{ + const char *desc = ""; + + switch (code) { + EX_DESC(ACCESS_VIOLATION); + EX_DESC(ARRAY_BOUNDS_EXCEEDED); + EX_DESC(BREAKPOINT); + EX_DESC(DATATYPE_MISALIGNMENT); + EX_DESC(FLT_DENORMAL_OPERAND); + EX_DESC(FLT_DIVIDE_BY_ZERO); + EX_DESC(FLT_INEXACT_RESULT); + EX_DESC(FLT_INVALID_OPERATION); + EX_DESC(FLT_OVERFLOW); + EX_DESC(FLT_STACK_CHECK); + EX_DESC(FLT_UNDERFLOW); + EX_DESC(ILLEGAL_INSTRUCTION); + EX_DESC(IN_PAGE_ERROR); + EX_DESC(INT_DIVIDE_BY_ZERO); + EX_DESC(INT_OVERFLOW); + EX_DESC(INVALID_DISPOSITION); + EX_DESC(NONCONTINUABLE_EXCEPTION); + EX_DESC(PRIV_INSTRUCTION); + EX_DESC(SINGLE_STEP); + EX_DESC(STACK_OVERFLOW); + case DBG_CONTROL_C: + return "DBG_CONTROL_C"; + default: + log_warning("Unknown exception code: %lX", code); + return "Unknown"; + } + + return desc; +} \ No newline at end of file diff --git a/src/main/util/debug.h b/src/main/util/debug.h new file mode 100644 index 0000000..c69c31c --- /dev/null +++ b/src/main/util/debug.h @@ -0,0 +1,12 @@ +#ifndef UTIL_DEBUG_H +#define UTIL_DEBUG_H + +#include + +#include "core/log.h" + +void debug_init(core_log_message_t exception_msg); +void debug_print_stacktrace(); +const char *debug_exception_code_to_str(DWORD code); + +#endif \ No newline at end of file diff --git a/src/main/util/signal.c b/src/main/util/signal.c index 9851c92..4007d01 100644 --- a/src/main/util/signal.c +++ b/src/main/util/signal.c @@ -1,5 +1,4 @@ #include -#include #include "core/log.h" @@ -46,40 +45,9 @@ static BOOL WINAPI console_ctrl_handler(DWORD dwCtrlType) return FALSE; } -static LONG WINAPI -unhandled_exception_filter(struct _EXCEPTION_POINTERS *ExceptionInfo) -{ - // no exception info provided - if (ExceptionInfo != NULL) { - struct _EXCEPTION_RECORD *ExceptionRecord = - ExceptionInfo->ExceptionRecord; - - log_warning( - "Exception raised: %s", - signal_exception_code_to_str(ExceptionRecord->ExceptionCode)); - - struct _EXCEPTION_RECORD *record_cause = - ExceptionRecord->ExceptionRecord; - - while (record_cause != NULL) { - log_warning( - "Caused by: %s", - signal_exception_code_to_str(record_cause->ExceptionCode)); - record_cause = record_cause->ExceptionRecord; - } - - // TODO print stacktrace - - log_fatal("End exception handler"); - } - - return EXCEPTION_CONTINUE_SEARCH; -} - void signal_exception_handler_init() { SetConsoleCtrlHandler(console_ctrl_handler, TRUE); - SetUnhandledExceptionFilter(unhandled_exception_filter); log_info("Initialized"); } @@ -89,55 +57,4 @@ void signal_register_shutdown_handler(signal_shutdown_handler_t handler) shutdown_handler = handler; log_misc("Registered shutdown handler"); -} - -const char *signal_exception_code_to_str(DWORD code) -{ - switch (code) { - case EXCEPTION_ACCESS_VIOLATION: - return "EXCEPTION_ACCESS_VIOLATION"; - case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: - return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; - case EXCEPTION_BREAKPOINT: - return "EXCEPTION_BREAKPOINT"; - case EXCEPTION_DATATYPE_MISALIGNMENT: - return "EXCEPTION_DATATYPE_MISALIGNMENT"; - case EXCEPTION_FLT_DENORMAL_OPERAND: - return "EXCEPTION_FLT_DENORMAL_OPERAND"; - case EXCEPTION_FLT_DIVIDE_BY_ZERO: - return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; - case EXCEPTION_FLT_INEXACT_RESULT: - return "EXCEPTION_FLT_INEXACT_RESULT"; - case EXCEPTION_FLT_INVALID_OPERATION: - return "EXCEPTION_FLT_INVALID_OPERATION"; - case EXCEPTION_FLT_OVERFLOW: - return "EXCEPTION_FLT_OVERFLOW"; - case EXCEPTION_FLT_STACK_CHECK: - return "EXCEPTION_FLT_STACK_CHECK"; - case EXCEPTION_FLT_UNDERFLOW: - return "EXCEPTION_FLT_UNDERFLOW"; - case EXCEPTION_ILLEGAL_INSTRUCTION: - return "EXCEPTION_ILLEGAL_INSTRUCTION"; - case EXCEPTION_IN_PAGE_ERROR: - return "EXCEPTION_IN_PAGE_ERROR"; - case EXCEPTION_INT_DIVIDE_BY_ZERO: - return "EXCEPTION_INT_DIVIDE_BY_ZERO"; - case EXCEPTION_INT_OVERFLOW: - return "EXCEPTION_INT_OVERFLOW"; - case EXCEPTION_INVALID_DISPOSITION: - return "EXCEPTION_INVALID_DISPOSITION"; - case EXCEPTION_NONCONTINUABLE_EXCEPTION: - return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; - case EXCEPTION_PRIV_INSTRUCTION: - return "EXCEPTION_PRIV_INSTRUCTION"; - case EXCEPTION_SINGLE_STEP: - return "EXCEPTION_SINGLE_STEP"; - case EXCEPTION_STACK_OVERFLOW: - return "EXCEPTION_STACK_OVERFLOW"; - case DBG_CONTROL_C: - return "DBG_CONTROL_C"; - default: - log_warning("Unknown exception code: %lX", code); - return "Unknown"; - } } \ No newline at end of file