mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-31 08:16:47 +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