//===-- MIDriverMain.cpp ----------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// //++ // File: MIDriverMain.cpp // // Overview: Defines the entry point for the console application. // The MI application (project name MI) runs in two modes: // An LLDB native driver mode where it acts no different from the LLDB driver. // The other mode is the MI when it finds on the command line // the --interpreter option. Command line argument --help on its own will give // help for the LLDB driver. If entered with --interpreter then MI help will // provided. // To implement new MI commands derive a new command class from the command base // class. To enable the new command for interpretation add the new command class // to the command factory. The files of relevance are: // MICmdCommands.cpp // MICmdBase.h / .cpp // MICmdCmd.h / .cpp // Versions: 1.0.0.1 First version from scratch 28/1/2014 to 28/3/2014. MI not complete. // 1.0.0.2 First deliverable to client 7/3/2014. MI not complete. // 1.0.0.3 Code refactor tidy. Release to community for evaluation 17/5/2014. MI not complete. // 1.0.0.4 Post release to the community for evaluation 17/5/2014. MI not complete. // 1.0.0.5 Second deliverable to client 16/6/2014. // 1.0.0.6 Post release of second deliverable to client 16/6/2014. // Released to the community 24/6/2014. // 1.0.0.7 Post release to the community. // Delivered to client 30/6/2014. // 1.0.0.8 Delivered to client 29/7/2014. // 1.0.0.9 Post release to client 29/7/2014. // See MIreadme.txt for list of MI commands implemented. // // Environment: Compilers: Visual C++ 12. // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1 // Libraries: See MIReadme.txt. // // Copyright: None. //-- #if defined( _MSC_VER ) #define _INC_SIGNAL // Stop window's signal.h being included - CODETAG_IOR_SIGNALS #endif // _MSC_VER // Third party headers: #include #include // In house headers: #include "MICmnConfig.h" #include "Platform.h" // Define signals - CODETAG_IOR_SIGNALS #include "Driver.h" #include "MIDriverMgr.h" #include "MIDriver.h" #include "MICmnResources.h" #include "MICmnStreamStdin.h" #include "MIUtilDebug.h" #include "MICmnLog.h" #if MICONFIG_COMPILE_MIDRIVER_VERSION #if defined( _MSC_VER ) #pragma warning( once : 4530 ) // Warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc #endif // _MSC_VER // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent // CODETAG_IOR_SIGNALS //++ ------------------------------------------------------------------------------------ // Details: The SIGWINCH signal is sent to a process when its controlling terminal // changes its size (a window change). // Type: Function. // Args: vSigno - (R) Signal number. // Return: None. // Throws: None. //-- void sigwinch_handler( int vSigno ) { MIunused( vSigno ); struct winsize window_size; if( ::isatty( STDIN_FILENO ) && ::ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) == 0 ) { CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance(); if( window_size.ws_col > 0 ) { rDriverMgr.DriverResizeWindow( (uint32_t) window_size.ws_col ); } } CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGWINCH", vSigno ) ); } // CODETAG_IOR_SIGNALS //++ ------------------------------------------------------------------------------------ // Details: The SIGINT signal is sent to a process by its controlling terminal when a // user wishes to interrupt the process. This is typically initiated by pressing // Control-C, but on some systems, the "delete" character or "break" key can be // used. // Be aware this function may be called on another thread besides the main thread. // Type: Function. // Args: vSigno - (R) Signal number. // Return: None. // Throws: None. //-- void sigint_handler( int vSigno ) { static bool g_interrupt_sent = false; CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance(); lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger(); if( pDebugger != nullptr ) { if( !g_interrupt_sent ) { g_interrupt_sent = true; pDebugger->DispatchInputInterrupt(); g_interrupt_sent = false; } } CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGINT", vSigno ) ); // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM // Signal MI to shutdown or halt a running debug session CMICmnStreamStdin::Instance().SetCtrlCHit(); } // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent // CODETAG_IOR_SIGNALS //++ ------------------------------------------------------------------------------------ // Details: The SIGTSTP signal is sent to a process by its controlling terminal to // request it to stop temporarily. It is commonly initiated by the user pressing // Control-Z. Unlike SIGSTOP, the process can register a signal handler for or // ignore the signal. // *** The function does not behave ATM like the UNIX equivalent *** // Type: Function. // Args: vSigno - (R) Signal number. // Return: None. // Throws: None. //-- void sigtstp_handler( int vSigno ) { CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance(); lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger(); if( pDebugger != nullptr ) { pDebugger->SaveInputTerminalState(); } CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGTSTP", vSigno ) ); // Signal MI to shutdown CMICmnStreamStdin::Instance().SetCtrlCHit(); } // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent // CODETAG_IOR_SIGNALS //++ ------------------------------------------------------------------------------------ // Details: The SIGCONT signal instructs the operating system to continue (restart) a // process previously paused by the SIGSTOP or SIGTSTP signal. One important use // of this signal is in job control in the UNIX shell. // *** The function does not behave ATM like the UNIX equivalent *** // Type: Function. // Args: vSigno - (R) Signal number. // Return: None. // Throws: None. //-- void sigcont_handler( int vSigno ) { CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance(); lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger(); if( pDebugger != nullptr ) { pDebugger->RestoreInputTerminalState(); } CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGCONT", vSigno ) ); // Signal MI to shutdown CMICmnStreamStdin::Instance().SetCtrlCHit(); } //++ ------------------------------------------------------------------------------------ // Details: Init the MI driver system. Initialize the whole driver system which includes // both the original LLDB driver and the MI driver. // Type: Function. // Args: None. // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool DriverSystemInit( void ) { bool bOk = MIstatus::success; #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER Driver * pDriver = Driver::CreateSelf(); if( pDriver == nullptr ) return MIstatus::failure; #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER CMIDriver & rMIDriver = CMIDriver::Instance(); CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance(); bOk = rDriverMgr.Initialize(); // Register MIDriver first as it needs to initialize and be ready // for the Driver to get information from MIDriver when it initializes // (LLDB Driver is registered with the Driver Manager in MI's Initialize()) bOk = bOk && rDriverMgr.RegisterDriver( rMIDriver, "MIDriver" ); // Will be main driver return bOk; } //++ ------------------------------------------------------------------------------------ // Details: Shutdown the debugger system. Release / terminate resources external to // specifically the MI driver. // Type: Function. // Args: vbAppExitOk - (R) True = No problems, false = App exiting with problems (investigate!). // Return: MIstatus::success - Functional succeeded. // MIstatus::failure - Functional failed. // Throws: None. //-- bool DriverSystemShutdown( const bool vbAppExitOk ) { bool bOk = MIstatus::success; // *** Order is important here *** CMIDriverMgr::Instance().Shutdown(); #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER delete g_driver; g_driver = nullptr; #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER return bOk; } #else void sigwinch_handler (int signo) { struct winsize window_size; if (isatty (STDIN_FILENO) && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0) { if ((window_size.ws_col > 0) && g_driver != NULL) { g_driver->ResizeWindow (window_size.ws_col); } } } void sigint_handler (int signo) { static bool g_interrupt_sent = false; if (g_driver) { if (!g_interrupt_sent) { g_interrupt_sent = true; g_driver->GetDebugger().DispatchInputInterrupt(); g_interrupt_sent = false; return; } } exit (signo); } void sigtstp_handler (int signo) { g_driver->GetDebugger().SaveInputTerminalState(); signal (signo, SIG_DFL); kill (getpid(), signo); signal (signo, sigtstp_handler); } void sigcont_handler (int signo) { g_driver->GetDebugger().RestoreInputTerminalState(); signal (signo, SIG_DFL); kill (getpid(), signo); signal (signo, sigcont_handler); } #endif // #if MICONFIG_COMPILE_MIDRIVER_VERSION //++ ------------------------------------------------------------------------------------ // Details: MI's application start point of execution. The applicaton runs in two modes. // An LLDB native driver mode where it acts no different from the LLDB driver. // The other mode is the MI when it finds on the command line // the --interpreter option. Command line argument --help on its own will give // help for the LLDB driver. If entered with --interpreter then application // help will provided. // Type: Method. // Args: argc - (R) An integer that contains the count of arguments that follow in // argv. The argc parameter is always greater than or equal to 1. // argv - (R) An array of null-terminated strings representing command-line // arguments entered by the user of the program. By convention, // argv[0] is the command with which the program is invoked. // Return: int - 0 = Normal exit, program success. // >0 = Program success with status i.e. Control-C signal status // <0 = Program failed. // -1 = Program failed reason not specified here, see MI log file. // -1000 = Program failed did not initailize successfully. // Throws: None. //-- #if MICONFIG_COMPILE_MIDRIVER_VERSION int main( int argc, char const *argv[] ) { #if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG #ifdef _WIN32 CMIUtilDebug::ShowDlgWaitForDbgAttach(); #else CMIUtilDebug::WaitForDbgAttachInfinteLoop(); #endif // _WIN32 #endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG // *** Order is important here *** bool bOk = DriverSystemInit(); if( !bOk ) { DriverSystemShutdown( bOk ); return -1000; } // CODETAG_IOR_SIGNALS signal( SIGPIPE, SIG_IGN ); signal( SIGWINCH, sigwinch_handler ); signal( SIGINT, sigint_handler ); signal( SIGTSTP, sigtstp_handler ); signal( SIGCONT, sigcont_handler ); bool bExiting = false; CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance(); bOk = bOk && rDriverMgr.ParseArgs( argc, argv, bExiting ); if( bOk && !bExiting ) bOk = rDriverMgr.DriverParseArgs( argc, argv, stdout, bExiting ); if( bOk && !bExiting ) bOk = rDriverMgr.DriverMainLoop(); // Logger and other resources shutdown now DriverSystemShutdown( bOk ); const int appResult = bOk ? 0 : -1; return appResult; } #else // Operate the lldb Driver only version of the code int main(int argc, char const *argv[], char *envp[]) { MIunused( envp ); using namespace lldb; SBDebugger::Initialize(); SBHostOS::ThreadCreated (""); signal (SIGPIPE, SIG_IGN); signal (SIGWINCH, sigwinch_handler); signal (SIGINT, sigint_handler); signal (SIGTSTP, sigtstp_handler); signal (SIGCONT, sigcont_handler); // Create a scope for driver so that the driver object will destroy itself // before SBDebugger::Terminate() is called. { Driver driver; bool exiting = false; SBError error (driver.ParseArgs (argc, argv, stdout, exiting)); if (error.Fail()) { const char *error_cstr = error.GetCString (); if (error_cstr) ::fprintf (stderr, "error: %s\n", error_cstr); } else if (!exiting) { driver.MainLoop(); } } SBDebugger::Terminate(); return 0; } #endif // MICONFIG_COMPILE_MIDRIVER_VERSION