log access violation on windows tinderboxen
where we currently have no good feedback when something goes wrong. Credit: Exception printing code written by msdn-whiteknight as seen at https://stackoverflow.com/questions/22467604/how-can-you-use-capturestackbacktrace-to-capture-the-exception-stack-not-the-ca Change-Id: I44c65b10c0b0151c3236521d62a824570d4cdccf Reviewed-on: https://gerrit.libreoffice.org/c/core/+/119561 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
This commit is contained in:
parent
67faef71f9
commit
24b06b9c6b
2 changed files with 213 additions and 81 deletions
|
@ -28,6 +28,12 @@ $(eval $(call gb_Executable_add_exception_objects,cppunittester,\
|
|||
sal/cppunittester/cppunittester \
|
||||
))
|
||||
|
||||
ifneq ($(strip $(debug)$(DEBUG)),)
|
||||
$(eval $(call gb_Executable_use_system_win32_libs,cppunittester,\
|
||||
dbghelp \
|
||||
))
|
||||
endif
|
||||
|
||||
ifeq ($(COM),MSC)
|
||||
|
||||
$(eval $(call gb_Executable_add_ldflags,cppunittester,\
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#endif
|
||||
#include <windows.h>
|
||||
#endif
|
||||
#if defined(_WIN32) && defined(_DEBUG)
|
||||
#include "dbghelp.h"
|
||||
#endif
|
||||
|
||||
#ifdef UNX
|
||||
#include <sys/time.h>
|
||||
|
@ -378,12 +381,11 @@ void reportResourceUsage([[maybe_unused]] const OUString& /*rPath*/)
|
|||
|
||||
}
|
||||
|
||||
SAL_IMPLEMENT_MAIN()
|
||||
static bool main2()
|
||||
{
|
||||
bool ok = false;
|
||||
OUString path;
|
||||
try
|
||||
{
|
||||
|
||||
#ifdef _WIN32
|
||||
//Disable Dr-Watson in order to crash simply without popup dialogs under
|
||||
//windows
|
||||
|
@ -472,15 +474,139 @@ SAL_IMPLEMENT_MAIN()
|
|||
|
||||
ProtectedFixtureFunctor tests(testlib, args, protectors, result);
|
||||
ok = tests.run();
|
||||
|
||||
reportResourceUsage(path);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && defined(_DEBUG)
|
||||
|
||||
//Prints stack trace based on exception context record
|
||||
void printStack( CONTEXT* ctx )
|
||||
{
|
||||
constexpr int MaxNameLen = 256;
|
||||
BOOL result;
|
||||
HANDLE process;
|
||||
HANDLE thread;
|
||||
HMODULE hModule;
|
||||
STACKFRAME64 stack;
|
||||
ULONG frame;
|
||||
DWORD64 displacement;
|
||||
DWORD disp;
|
||||
char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)];
|
||||
char module[MaxNameLen];
|
||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer;
|
||||
|
||||
memset( &stack, 0, sizeof( STACKFRAME64 ) );
|
||||
|
||||
process = GetCurrentProcess();
|
||||
thread = GetCurrentThread();
|
||||
displacement = 0;
|
||||
#if !defined(_M_AMD64)
|
||||
stack.AddrPC.Offset = (*ctx).Eip;
|
||||
stack.AddrPC.Mode = AddrModeFlat;
|
||||
stack.AddrStack.Offset = (*ctx).Esp;
|
||||
stack.AddrStack.Mode = AddrModeFlat;
|
||||
stack.AddrFrame.Offset = (*ctx).Ebp;
|
||||
stack.AddrFrame.Mode = AddrModeFlat;
|
||||
#endif
|
||||
|
||||
SymInitialize( process, NULL, TRUE ); //load symbols
|
||||
|
||||
std::unique_ptr<IMAGEHLP_LINE64> line(new IMAGEHLP_LINE64);
|
||||
line->SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
|
||||
for( frame = 0; ; frame++ )
|
||||
{
|
||||
//get next call from stack
|
||||
result = StackWalk64
|
||||
(
|
||||
#if defined(_M_AMD64)
|
||||
IMAGE_FILE_MACHINE_AMD64,
|
||||
#else
|
||||
IMAGE_FILE_MACHINE_I386,
|
||||
#endif
|
||||
process,
|
||||
thread,
|
||||
&stack,
|
||||
ctx,
|
||||
NULL,
|
||||
SymFunctionTableAccess64,
|
||||
SymGetModuleBase64,
|
||||
NULL
|
||||
);
|
||||
|
||||
if( !result )
|
||||
break;
|
||||
|
||||
//get symbol name for address
|
||||
pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||
pSymbol->MaxNameLen = MAX_SYM_NAME;
|
||||
SymFromAddr(process, ( ULONG64 )stack.AddrPC.Offset, &displacement, pSymbol);
|
||||
|
||||
//try to get line
|
||||
if (SymGetLineFromAddr64(process, stack.AddrPC.Offset, &disp, line.get()))
|
||||
{
|
||||
printf("\tat %s in %s: line: %lu: address: 0x%0X\n", pSymbol->Name, line->FileName, line->LineNumber, pSymbol->Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
//failed to get line
|
||||
printf("\tat %s, address 0x%0X.\n", pSymbol->Name, pSymbol->Address);
|
||||
hModule = NULL;
|
||||
lstrcpyA(module,"");
|
||||
GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
(LPCTSTR)(stack.AddrPC.Offset), &hModule);
|
||||
|
||||
//at least print module name
|
||||
if(hModule != NULL)GetModuleFileNameA(hModule,module,MaxNameLen);
|
||||
|
||||
printf ("in %s\n",module);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The exception filter function:
|
||||
LONG WINAPI ExpFilter(EXCEPTION_POINTERS* ex)
|
||||
{
|
||||
// we only want this active on the Jenkins tinderboxen
|
||||
printf("*** Exception 0x%x occured ***\n\n",ex->ExceptionRecord->ExceptionCode);
|
||||
printStack(ex->ContextRecord);
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
|
||||
SAL_IMPLEMENT_MAIN()
|
||||
{
|
||||
bool ok = false;
|
||||
// This magic kind of Windows-specific exception handling has to be in it's own function
|
||||
// because it cannot be in a function that has objects with destructors.
|
||||
__try
|
||||
{
|
||||
ok = main2();
|
||||
}
|
||||
__except (ExpFilter(GetExceptionInformation()))
|
||||
{
|
||||
}
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
SAL_IMPLEMENT_MAIN()
|
||||
{
|
||||
bool ok = false;
|
||||
try
|
||||
{
|
||||
ok = main2();
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
SAL_WARN("vcl.app", "Fatal exception: " << e.what());
|
||||
}
|
||||
|
||||
reportResourceUsage(path);
|
||||
|
||||
return ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|
||||
|
|
Loading…
Reference in a new issue