diff options
Diffstat (limited to 'tools/lldb-mi/MIDriverMain.cpp')
-rw-r--r-- | tools/lldb-mi/MIDriverMain.cpp | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/tools/lldb-mi/MIDriverMain.cpp b/tools/lldb-mi/MIDriverMain.cpp new file mode 100644 index 000000000000..a72e4ab20f3d --- /dev/null +++ b/tools/lldb-mi/MIDriverMain.cpp @@ -0,0 +1,393 @@ +//===-- 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 <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 + |