| //===-- 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 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. |
| // 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 <stdio.h> |
| #include <lldb/API/SBHostOS.h> |
| |
| // 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 ("<lldb.driver.main-thread>"); |
| |
| 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 |
| |