mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-10-29 08:16:51 +00:00
Add a new 'AddSignalHandler' function to Signals.h that allows
arbitrary functions to be run when a crash happens. Delete RemoveDirectoryOnSignal as it is dead and has never had clients. Change PrintStackTraceOnErrorSignal to be implemented in terms of AddSignalHandler. I updated the Win32 versions of these APIs, but can't test them. If there are any problems, I'd be happy to fix them as well. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@66072 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -25,17 +25,16 @@ namespace sys {
|
|||||||
/// @brief Remove a file if a fatal signal occurs.
|
/// @brief Remove a file if a fatal signal occurs.
|
||||||
bool RemoveFileOnSignal(const Path &Filename, std::string* ErrMsg = 0);
|
bool RemoveFileOnSignal(const Path &Filename, std::string* ErrMsg = 0);
|
||||||
|
|
||||||
/// This function registers a signal handler to ensure that if a fatal signal
|
|
||||||
/// gets delivered to the process that the named directory and all its
|
|
||||||
/// contents are removed.
|
|
||||||
/// @brief Remove a directory if a fatal signal occurs.
|
|
||||||
bool RemoveDirectoryOnSignal(const Path& path, std::string* ErrMsg = 0);
|
|
||||||
|
|
||||||
/// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the
|
/// When an error signal (such as SIBABRT or SIGSEGV) is delivered to the
|
||||||
/// process, print a stack trace and then exit.
|
/// process, print a stack trace and then exit.
|
||||||
/// @brief Print a stack trace if a fatal signal occurs.
|
/// @brief Print a stack trace if a fatal signal occurs.
|
||||||
void PrintStackTraceOnErrorSignal();
|
void PrintStackTraceOnErrorSignal();
|
||||||
|
|
||||||
|
/// AddSignalHandler - Add a function to be called when an abort/kill signal
|
||||||
|
/// is delivered to the process. The handler can have a cookie passed to it
|
||||||
|
/// to identify what instance of the handler it is.
|
||||||
|
void AddSignalHandler(void (*FnPtr)(void *), void *Cookie);
|
||||||
|
|
||||||
/// This function registers a function to be called when the user "interrupts"
|
/// This function registers a function to be called when the user "interrupts"
|
||||||
/// the program (typically by pressing ctrl-c). When the user interrupts the
|
/// the program (typically by pressing ctrl-c). When the user interrupts the
|
||||||
/// program, the specified interrupt function is called instead of the program
|
/// program, the specified interrupt function is called instead of the program
|
||||||
|
|||||||
@@ -31,15 +31,11 @@
|
|||||||
#endif
|
#endif
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
static bool StackTraceRequested = false;
|
|
||||||
|
|
||||||
/// InterruptFunction - The function to call if ctrl-c is pressed.
|
/// InterruptFunction - The function to call if ctrl-c is pressed.
|
||||||
static void (*InterruptFunction)() = 0;
|
static void (*InterruptFunction)() = 0;
|
||||||
|
|
||||||
static std::vector<sys::Path> *FilesToRemove = 0 ;
|
static std::vector<sys::Path> *FilesToRemove = 0;
|
||||||
static std::vector<sys::Path> *DirectoriesToRemove = 0;
|
static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
|
||||||
|
|
||||||
// IntSigs - Signals that may interrupt the program at any time.
|
// IntSigs - Signals that may interrupt the program at any time.
|
||||||
static const int IntSigs[] = {
|
static const int IntSigs[] = {
|
||||||
@@ -59,17 +55,77 @@ static const int KillSigs[] = {
|
|||||||
static const int *const KillSigsEnd =
|
static const int *const KillSigsEnd =
|
||||||
KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
|
KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
|
||||||
|
|
||||||
#ifdef HAVE_BACKTRACE
|
// SignalHandler - The signal handler that runs...
|
||||||
static void* StackTrace[256];
|
static RETSIGTYPE SignalHandler(int Sig) {
|
||||||
#endif
|
if (FilesToRemove != 0)
|
||||||
|
while (!FilesToRemove->empty()) {
|
||||||
|
FilesToRemove->back().eraseFromDisk(true);
|
||||||
|
FilesToRemove->pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
|
||||||
|
if (InterruptFunction) {
|
||||||
|
void (*IF)() = InterruptFunction;
|
||||||
|
InterruptFunction = 0;
|
||||||
|
IF(); // run the interrupt function.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
exit(1); // If this is an interrupt signal, exit the program
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise if it is a fault (like SEGV) run any handler.
|
||||||
|
if (CallBacksToRun)
|
||||||
|
for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
|
||||||
|
(*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
|
||||||
|
|
||||||
|
// Restore the signal behavior to default, so that the program actually
|
||||||
|
// crashes when we return and the signal reissues.
|
||||||
|
signal(Sig, SIG_DFL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just call signal
|
||||||
|
static void RegisterHandler(int Signal) {
|
||||||
|
signal(Signal, SignalHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void sys::SetInterruptFunction(void (*IF)()) {
|
||||||
|
InterruptFunction = IF;
|
||||||
|
RegisterHandler(SIGINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoveFileOnSignal - The public API
|
||||||
|
bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
|
||||||
|
if (FilesToRemove == 0)
|
||||||
|
FilesToRemove = new std::vector<sys::Path>();
|
||||||
|
|
||||||
|
FilesToRemove->push_back(Filename);
|
||||||
|
|
||||||
|
std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
|
||||||
|
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AddSignalHandler - Add a function to be called when a signal is delivered
|
||||||
|
/// to the process. The handler can have a cookie passed to it to identify
|
||||||
|
/// what instance of the handler it is.
|
||||||
|
void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
|
||||||
|
if (CallBacksToRun == 0)
|
||||||
|
CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >();
|
||||||
|
CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
|
||||||
|
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// PrintStackTrace - In the case of a program crash or fault, print out a stack
|
// PrintStackTrace - In the case of a program crash or fault, print out a stack
|
||||||
// trace so that the user has an indication of why and where we died.
|
// trace so that the user has an indication of why and where we died.
|
||||||
//
|
//
|
||||||
// On glibc systems we have the 'backtrace' function, which works nicely, but
|
// On glibc systems we have the 'backtrace' function, which works nicely, but
|
||||||
// doesn't demangle symbols.
|
// doesn't demangle symbols.
|
||||||
static void PrintStackTrace() {
|
static void PrintStackTrace(void *) {
|
||||||
#ifdef HAVE_BACKTRACE
|
#ifdef HAVE_BACKTRACE
|
||||||
|
static void* StackTrace[256];
|
||||||
// Use backtrace() to output a backtrace on Linux systems with glibc.
|
// Use backtrace() to output a backtrace on Linux systems with glibc.
|
||||||
int depth = backtrace(StackTrace,
|
int depth = backtrace(StackTrace,
|
||||||
static_cast<int>(array_lengthof(StackTrace)));
|
static_cast<int>(array_lengthof(StackTrace)));
|
||||||
@@ -118,91 +174,9 @@ static void PrintStackTrace() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// SignalHandler - The signal handler that runs...
|
|
||||||
static RETSIGTYPE SignalHandler(int Sig) {
|
|
||||||
if (FilesToRemove != 0)
|
|
||||||
while (!FilesToRemove->empty()) {
|
|
||||||
FilesToRemove->back().eraseFromDisk(true);
|
|
||||||
FilesToRemove->pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectoriesToRemove != 0)
|
|
||||||
while (!DirectoriesToRemove->empty()) {
|
|
||||||
DirectoriesToRemove->back().eraseFromDisk(true);
|
|
||||||
DirectoriesToRemove->pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::find(IntSigs, IntSigsEnd, Sig) != IntSigsEnd) {
|
|
||||||
if (InterruptFunction) {
|
|
||||||
void (*IF)() = InterruptFunction;
|
|
||||||
InterruptFunction = 0;
|
|
||||||
IF(); // run the interrupt function.
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
exit(1); // If this is an interrupt signal, exit the program
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise if it is a fault (like SEGV) output the stacktrace to
|
|
||||||
// STDERR (if we can) and reissue the signal to die...
|
|
||||||
if (StackTraceRequested)
|
|
||||||
PrintStackTrace();
|
|
||||||
signal(Sig, SIG_DFL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just call signal
|
|
||||||
static void RegisterHandler(int Signal) {
|
|
||||||
signal(Signal, SignalHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sys::SetInterruptFunction(void (*IF)()) {
|
|
||||||
InterruptFunction = IF;
|
|
||||||
RegisterHandler(SIGINT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveFileOnSignal - The public API
|
|
||||||
bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
|
|
||||||
if (FilesToRemove == 0)
|
|
||||||
FilesToRemove = new std::vector<sys::Path>;
|
|
||||||
|
|
||||||
FilesToRemove->push_back(Filename);
|
|
||||||
|
|
||||||
std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
|
|
||||||
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// RemoveDirectoryOnSignal - The public API
|
|
||||||
bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) {
|
|
||||||
// Not a directory?
|
|
||||||
struct stat buf;
|
|
||||||
if (0 != stat(path.c_str(), &buf)) {
|
|
||||||
MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!S_ISDIR(buf.st_mode)) {
|
|
||||||
if (ErrMsg)
|
|
||||||
*ErrMsg = path.toString() + " is not a directory";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectoriesToRemove == 0)
|
|
||||||
DirectoriesToRemove = new std::vector<sys::Path>;
|
|
||||||
|
|
||||||
DirectoriesToRemove->push_back(path);
|
|
||||||
|
|
||||||
std::for_each(IntSigs, IntSigsEnd, RegisterHandler);
|
|
||||||
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
|
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
|
||||||
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
||||||
void sys::PrintStackTraceOnErrorSignal() {
|
void sys::PrintStackTraceOnErrorSignal() {
|
||||||
StackTraceRequested = true;
|
AddSignalHandler(PrintStackTrace, 0);
|
||||||
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
|
|||||||
static void (*InterruptFunction)() = 0;
|
static void (*InterruptFunction)() = 0;
|
||||||
|
|
||||||
static std::vector<llvm::sys::Path> *FilesToRemove = NULL;
|
static std::vector<llvm::sys::Path> *FilesToRemove = NULL;
|
||||||
static std::vector<llvm::sys::Path> *DirectoriesToRemove = NULL;
|
static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
|
||||||
static bool RegisteredUnhandledExceptionFilter = false;
|
static bool RegisteredUnhandledExceptionFilter = false;
|
||||||
static bool CleanupExecuted = false;
|
static bool CleanupExecuted = false;
|
||||||
static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
|
static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
|
||||||
@@ -98,37 +98,6 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RemoveDirectoryOnSignal - The public API
|
|
||||||
bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) {
|
|
||||||
// Not a directory?
|
|
||||||
WIN32_FILE_ATTRIBUTE_DATA fi;
|
|
||||||
if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) {
|
|
||||||
MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
|
|
||||||
if (ErrMsg)
|
|
||||||
*ErrMsg = path.toString() + ": not a directory";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
RegisterHandler();
|
|
||||||
|
|
||||||
if (CleanupExecuted) {
|
|
||||||
if (ErrMsg)
|
|
||||||
*ErrMsg = "Process terminating -- cannot register for removal";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (DirectoriesToRemove == NULL)
|
|
||||||
DirectoriesToRemove = new std::vector<sys::Path>;
|
|
||||||
DirectoriesToRemove->push_back(path);
|
|
||||||
|
|
||||||
LeaveCriticalSection(&CriticalSection);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
|
/// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or
|
||||||
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
||||||
void sys::PrintStackTraceOnErrorSignal() {
|
void sys::PrintStackTraceOnErrorSignal() {
|
||||||
@@ -162,14 +131,9 @@ static void Cleanup() {
|
|||||||
FilesToRemove->pop_back();
|
FilesToRemove->pop_back();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (DirectoriesToRemove != NULL)
|
if (CallBacksToRun)
|
||||||
while (!DirectoriesToRemove->empty()) {
|
for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
|
||||||
try {
|
(*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
|
||||||
DirectoriesToRemove->back().eraseFromDisk(true);
|
|
||||||
} catch (...) {
|
|
||||||
}
|
|
||||||
DirectoriesToRemove->pop_back();
|
|
||||||
}
|
|
||||||
|
|
||||||
LeaveCriticalSection(&CriticalSection);
|
LeaveCriticalSection(&CriticalSection);
|
||||||
}
|
}
|
||||||
@@ -259,7 +223,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
assert(!"Crashed in LLVMUnhandledExceptionFilter");
|
assert(0 && "Crashed in LLVMUnhandledExceptionFilter");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow dialog box to pop up allowing choice to start debugger.
|
// Allow dialog box to pop up allowing choice to start debugger.
|
||||||
@@ -292,3 +256,13 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// AddSignalHandler - Add a function to be called when a signal is delivered
|
||||||
|
/// to the process. The handler can have a cookie passed to it to identify
|
||||||
|
/// what instance of the handler it is.
|
||||||
|
void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) {
|
||||||
|
if (CallBacksToRun == 0)
|
||||||
|
CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >();
|
||||||
|
CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie));
|
||||||
|
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user