Add callstack printing to cloc

- callstack is printed when SEH / SigSegv / SigIll is raised

Change-Id: I4bddd1208351027ee67fc6bae2404a90022373c7
This commit is contained in:
Hoppe, Mateusz
2018-06-22 17:38:00 +02:00
committed by sys_ocldev
parent a7dbc55ae5
commit e437589ace
16 changed files with 739 additions and 1 deletions

View File

@@ -78,6 +78,8 @@ set(CLOC_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt
)
add_executable(cloc ${CLOC_SRCS})
add_subdirectories()
create_project_source_tree(cloc ${IGDRCL_SOURCE_DIR}/runtime)
set(CLOC_INCLUDES
@@ -94,6 +96,10 @@ target_include_directories(cloc BEFORE PRIVATE ${CLOC_INCLUDES})
target_compile_definitions(cloc PUBLIC ${CLOC_LIB_FLAGS_DEFINITIONS} ${SUPPORTED_GEN_FLAGS_DEFINITONS} DEFAULT_PLATFORM=${DEFAULT_SUPPORTED_PLATFORM})
if(MSVC)
target_link_libraries(cloc dbghelp)
endif()
if(UNIX)
target_link_libraries(cloc dl pthread)
endif()

View File

@@ -21,6 +21,7 @@
*/
#include "offline_compiler/offline_compiler.h"
#include "offline_compiler/utilities/safety_caller.h"
#include "runtime/os_interface/os_library.h"
#include <CL/cl.h>
@@ -32,7 +33,7 @@ int main(int numArgs, const char *argv[]) {
OfflineCompiler *pCompiler = OfflineCompiler::create(numArgs, argv, retVal);
if (retVal == CL_SUCCESS) {
retVal = pCompiler->build();
retVal = buildWithSafetyGuard(pCompiler);
std::string buildLog = pCompiler->getBuildLog();
if (buildLog.empty() == false) {

View File

@@ -0,0 +1,39 @@
# Copyright (c) 2018, Intel Corporation
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
set(CLOC_SRCS_UTILITIES
${CMAKE_CURRENT_SOURCE_DIR}/safety_caller.h
)
if(WIN32)
list(APPEND CLOC_SRCS_UTILITIES
${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_caller_windows.cpp
${CMAKE_CURRENT_SOURCE_DIR}/windows/safety_guard_windows.h
${CMAKE_CURRENT_SOURCE_DIR}/windows/seh_exception.cpp
${CMAKE_CURRENT_SOURCE_DIR}/windows/seh_exception.h
)
else()
list(APPEND CLOC_SRCS_UTILITIES
${CMAKE_CURRENT_SOURCE_DIR}/linux/safety_caller_linux.cpp
${CMAKE_CURRENT_SOURCE_DIR}/linux/safety_guard_linux.h
)
endif()
target_sources(cloc PRIVATE ${CLOC_SRCS_UTILITIES})

View File

@@ -0,0 +1,34 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "runtime/os_interface/os_library.h"
#include "offline_compiler/offline_compiler.h"
#include "offline_compiler/utilities/linux/safety_guard_linux.h"
using namespace OCLRT;
int buildWithSafetyGuard(OfflineCompiler *compiler) {
SafetyGuardLinux safetyGuard;
int retVal = 0;
return safetyGuard.call<int, OfflineCompiler, decltype(&OfflineCompiler::build)>(compiler, &OfflineCompiler::build, retVal);
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "runtime/helpers/abort.h"
#include <cstdlib>
#include <cstdio>
#include <execinfo.h>
#include <signal.h>
#include <setjmp.h>
static jmp_buf jmpbuf;
class SafetyGuardLinux {
public:
SafetyGuardLinux() {
struct sigaction sigact;
sigact.sa_sigaction = sigAction;
sigact.sa_flags = SA_RESTART | SA_SIGINFO;
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaction(SIGILL, &sigact, (struct sigaction *)NULL);
}
static void sigAction(int sig_num, siginfo_t *info, void *ucontext) {
const int callstackDepth = 30;
void *addresses[callstackDepth];
char **callstack;
int backtraceSize = 0;
backtraceSize = backtrace(addresses, callstackDepth);
callstack = backtrace_symbols(addresses, backtraceSize);
for (int i = 0; i < backtraceSize; ++i) {
printf("[%d]: %s\n", i, callstack[i]);
}
free(callstack);
longjmp(jmpbuf, 1);
}
template <typename T, typename Object, typename Method>
T call(Object *object, Method method, T retValueOnCrash) {
int jump = 0;
jump = setjmp(jmpbuf);
if (jump == 0) {
return (object->*method)();
} else {
if (onSigSegv) {
onSigSegv();
} else {
OCLRT::abortExecution();
}
}
return retValueOnCrash;
}
typedef void (*callbackFunction)();
callbackFunction onSigSegv = nullptr;
};

View File

@@ -0,0 +1,28 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
namespace OCLRT {
class OfflineCompiler;
}
extern int buildWithSafetyGuard(OCLRT::OfflineCompiler *compiler);

View File

@@ -0,0 +1,32 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "offline_compiler/offline_compiler.h"
#include "offline_compiler/utilities/windows/safety_guard_windows.h"
using namespace OCLRT;
int buildWithSafetyGuard(OfflineCompiler *compiler) {
SafetyGuardWindows safetyGuard;
int retVal = 0;
return safetyGuard.call<int, OfflineCompiler, decltype(&OfflineCompiler::build)>(compiler, &OfflineCompiler::build, retVal);
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "offline_compiler/utilities/windows/seh_exception.h"
#include "runtime/helpers/abort.h"
#include <setjmp.h>
static jmp_buf jmpbuf;
class SafetyGuardWindows {
public:
template <typename T, typename Object, typename Method>
T call(Object *object, Method method, T retValueOnCrash) {
int jump = 0;
jump = setjmp(jmpbuf);
if (jump == 0) {
__try {
return (object->*method)();
} __except (SehException::filter(GetExceptionCode(), GetExceptionInformation())) {
if (onExcept) {
onExcept();
} else {
OCLRT::abortExecution();
}
longjmp(jmpbuf, 1);
}
}
return retValueOnCrash;
}
typedef void (*callbackFunction)();
callbackFunction onExcept = nullptr;
};

View File

@@ -0,0 +1,175 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#include "seh_exception.h"
#include "runtime/os_interface/os_library.h"
#include <memory>
#include <string>
#pragma warning(push)
#pragma warning(disable : 4091)
#include <dbghelp.h>
#pragma warning(pop)
#include <excpt.h>
#include <psapi.h>
#include <windows.h>
using namespace std;
string SehException::getExceptionDescription(unsigned int code) {
switch (code) {
case EXCEPTION_ACCESS_VIOLATION:
return "Access violation";
case EXCEPTION_DATATYPE_MISALIGNMENT:
return "Datatype misalignement";
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return "Divide by zero";
case EXCEPTION_STACK_OVERFLOW:
return "Stack overflow";
default:
break;
}
return "Unknown";
}
int SehException::filter(unsigned int code, struct _EXCEPTION_POINTERS *ep) {
printf("EXCEPTION: %s\n", SehException::getExceptionDescription(code).c_str());
if (code != EXCEPTION_STACK_OVERFLOW) {
string callstack;
SehException::getCallStack(code, ep, callstack);
printf("Callstack:\n\n%s", callstack.c_str());
}
return EXCEPTION_EXECUTE_HANDLER;
}
void SehException::getCallStack(unsigned int code, struct _EXCEPTION_POINTERS *ep, string &stack) {
DWORD machine = 0;
HANDLE hProcess = GetCurrentProcess();
HANDLE hThread = GetCurrentThread();
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL) {
machine = IMAGE_FILE_MACHINE_I386;
} else if (systemInfo.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
machine = IMAGE_FILE_MACHINE_AMD64;
} else {
stack = "invalid processor arch";
return;
}
stack.clear();
BOOL result = SymInitialize(hProcess, NULL, TRUE);
STACKFRAME64 stackFrame;
memset(&stackFrame, 0, sizeof(STACKFRAME64));
const int nameSize = 255;
char buffer[sizeof(IMAGEHLP_SYMBOL64) + (nameSize + 1) * sizeof(char)];
IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer);
symbol->MaxNameLength = nameSize;
DWORD displacement = 0;
DWORD64 displacement64 = 0;
unique_ptr<OCLRT::OsLibrary> psApiLib(OCLRT::OsLibrary::load("psapi.dll"));
auto getMappedFileName = reinterpret_cast<getMappedFileNameFunction>(psApiLib->getProcAddress("GetMappedFileNameA"));
size_t callstackCounter = 0;
const size_t maxCallstackDepth = 1000;
#ifdef _WIN64
stackFrame.AddrPC.Offset = ep->ContextRecord->Rip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = ep->ContextRecord->Rsp;
stackFrame.AddrStack.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
#else
stackFrame.AddrPC.Offset = ep->ContextRecord->Eip;
stackFrame.AddrPC.Mode = AddrModeFlat;
stackFrame.AddrStack.Offset = ep->ContextRecord->Esp;
stackFrame.AddrStack.Mode = AddrModeFlat;
stackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp;
stackFrame.AddrFrame.Mode = AddrModeFlat;
#endif
while (callstackCounter < maxCallstackDepth) {
symbol->Name[255] = '\0';
if (!StackWalk64(machine, hProcess, hThread, &stackFrame, ep->ContextRecord, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {
break;
}
if (stackFrame.AddrFrame.Offset == 0) {
break;
}
string lineInCode;
string module;
string symbolName;
DWORD64 address = stackFrame.AddrPC.Offset;
IMAGEHLP_LINE64 imageLine;
imageLine.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
if (SymGetLineFromAddr64(hProcess, address, &displacement, &imageLine)) {
lineInCode = imageLine.FileName;
char filename[MAX_PATH + 1];
filename[MAX_PATH] = '\0';
if (getMappedFileName(hProcess, reinterpret_cast<LPVOID>(imageLine.Address), filename, MAX_PATH)) {
module = filename;
}
}
if (SymGetSymFromAddr64(hProcess, address, &displacement64, symbol)) {
symbolName = symbol->Name;
}
addLineToCallstack(stack, callstackCounter, module, lineInCode, symbolName);
callstackCounter++;
}
}
void SehException::addLineToCallstack(std::string &callstack, size_t counter, std::string &module, std::string &line, std::string &symbol) {
callstack += "[";
callstack += to_string(counter);
callstack += "]: ";
if (module.size()) {
callstack += "Module:";
callstack += module + "\n\t";
}
if (line.size()) {
callstack += line + ":";
}
callstack += symbol + "\n";
}

View File

@@ -0,0 +1,38 @@
/*
* Copyright (c) 2018, Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#pragma once
#include "windows.h"
#include "excpt.h"
#include <string>
class SehException {
public:
static std::string getExceptionDescription(unsigned int code);
static void getCallStack(unsigned int code, struct _EXCEPTION_POINTERS *ep, std::string &stack);
static int filter(unsigned int code, struct _EXCEPTION_POINTERS *ep);
protected:
static void addLineToCallstack(std::string &callstack, size_t counter, std::string &module, std::string &line, std::string &symbol);
typedef DWORD(WINAPI *getMappedFileNameFunction)(HANDLE hProcess, LPVOID lpv, LPSTR lpFilename, DWORD nSize);
};