mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-03-17 05:31:32 +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:
parent
fd0339933b
commit
35033a5876
@ -25,17 +25,16 @@ namespace sys {
|
||||
/// @brief Remove a file if a fatal signal occurs.
|
||||
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
|
||||
/// process, print a stack trace and then exit.
|
||||
/// @brief Print a stack trace if a fatal signal occurs.
|
||||
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"
|
||||
/// the program (typically by pressing ctrl-c). When the user interrupts the
|
||||
/// program, the specified interrupt function is called instead of the program
|
||||
|
@ -31,15 +31,11 @@
|
||||
#endif
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
|
||||
static bool StackTraceRequested = false;
|
||||
|
||||
/// InterruptFunction - The function to call if ctrl-c is pressed.
|
||||
static void (*InterruptFunction)() = 0;
|
||||
|
||||
static std::vector<sys::Path> *FilesToRemove = 0 ;
|
||||
static std::vector<sys::Path> *DirectoriesToRemove = 0;
|
||||
static std::vector<sys::Path> *FilesToRemove = 0;
|
||||
static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0;
|
||||
|
||||
// IntSigs - Signals that may interrupt the program at any time.
|
||||
static const int IntSigs[] = {
|
||||
@ -59,17 +55,77 @@ static const int KillSigs[] = {
|
||||
static const int *const KillSigsEnd =
|
||||
KillSigs + sizeof(KillSigs) / sizeof(KillSigs[0]);
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
static void* StackTrace[256];
|
||||
#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 (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
|
||||
// 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
|
||||
// doesn't demangle symbols.
|
||||
static void PrintStackTrace() {
|
||||
static void PrintStackTrace(void *) {
|
||||
#ifdef HAVE_BACKTRACE
|
||||
static void* StackTrace[256];
|
||||
// Use backtrace() to output a backtrace on Linux systems with glibc.
|
||||
int depth = backtrace(StackTrace,
|
||||
static_cast<int>(array_lengthof(StackTrace)));
|
||||
@ -118,91 +174,9 @@ static void PrintStackTrace() {
|
||||
#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
|
||||
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
||||
void sys::PrintStackTraceOnErrorSignal() {
|
||||
StackTraceRequested = true;
|
||||
std::for_each(KillSigs, KillSigsEnd, RegisterHandler);
|
||||
AddSignalHandler(PrintStackTrace, 0);
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType);
|
||||
static void (*InterruptFunction)() = 0;
|
||||
|
||||
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 CleanupExecuted = false;
|
||||
static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL;
|
||||
@ -98,37 +98,6 @@ bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) {
|
||||
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
|
||||
/// SIGSEGV) is delivered to the process, print a stack trace and then exit.
|
||||
void sys::PrintStackTraceOnErrorSignal() {
|
||||
@ -162,14 +131,9 @@ static void Cleanup() {
|
||||
FilesToRemove->pop_back();
|
||||
}
|
||||
|
||||
if (DirectoriesToRemove != NULL)
|
||||
while (!DirectoriesToRemove->empty()) {
|
||||
try {
|
||||
DirectoriesToRemove->back().eraseFromDisk(true);
|
||||
} catch (...) {
|
||||
}
|
||||
DirectoriesToRemove->pop_back();
|
||||
}
|
||||
if (CallBacksToRun)
|
||||
for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i)
|
||||
(*CallBacksToRun)[i].first((*CallBacksToRun)[i].second);
|
||||
|
||||
LeaveCriticalSection(&CriticalSection);
|
||||
}
|
||||
@ -259,7 +223,7 @@ static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) {
|
||||
#endif
|
||||
|
||||
} catch (...) {
|
||||
assert(!"Crashed in LLVMUnhandledExceptionFilter");
|
||||
assert(0 && "Crashed in LLVMUnhandledExceptionFilter");
|
||||
}
|
||||
|
||||
// Allow dialog box to pop up allowing choice to start debugger.
|
||||
@ -292,3 +256,13 @@ static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user