forked from OSchip/llvm-project
400 lines
14 KiB
C++
400 lines
14 KiB
C++
//===-- 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
|