1 //===-- MIDriverMain.cpp ----------------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 // File: MIDriverMain.cpp
13 // Overview: Defines the entry point for the console application.
14 // The MI application (project name MI) runs in two modes:
15 // An LLDB native driver mode where it acts no different from the LLDB driver.
16 // The other mode is the MI when it finds on the command line
17 // the --interpreter option. Command line argument --help on its own will give
18 // help for the LLDB driver. If entered with --interpreter then MI help will
20 // To implement new MI commands derive a new command class from the command base
21 // class. To enable the new command for interpretation add the new command class
22 // to the command factory. The files of relevance are:
26 // Versions: 1.0.0.1 First version from scratch 28/1/2014 to 28/3/2014. MI not complete.
27 // 1.0.0.2 First deliverable to client 7/3/2014. MI not complete.
28 // 1.0.0.3 Code refactor tidy. Release to community for evaluation 17/5/2014. MI not complete.
29 // 1.0.0.4 Post release to the community for evaluation 17/5/2014. MI not complete.
30 // 1.0.0.5 Second deliverable to client 16/6/2014.
31 // 1.0.0.6 Post release of second deliverable to client 16/6/2014.
32 // Released to the community 24/6/2014.
33 // 1.0.0.7 Post release to the community.
34 // Delivered to client 30/6/2014.
35 // 1.0.0.8 Delivered to client 29/7/2014.
36 // 1.0.0.9 Post release to client 29/7/2014.
37 // See MIreadme.txt for list of MI commands implemented.
39 // Environment: Compilers: Visual C++ 12.
40 // gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
41 // Libraries: See MIReadme.txt.
47 #define _INC_SIGNAL // Stop window's signal.h being included - CODETAG_IOR_SIGNALS
50 // Third party headers:
52 #include <lldb/API/SBHostOS.h>
55 #include "MICmnConfig.h"
56 #include "Platform.h" // Define signals - CODETAG_IOR_SIGNALS
58 #include "MIDriverMgr.h"
60 #include "MICmnResources.h"
61 #include "MICmnStreamStdin.h"
62 #include "MIUtilDebug.h"
65 #if MICONFIG_COMPILE_MIDRIVER_VERSION
68 #pragma warning(once : 4530) // Warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
71 // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
72 // CODETAG_IOR_SIGNALS
73 //++ ------------------------------------------------------------------------------------
74 // Details: The SIGWINCH signal is sent to a process when its controlling terminal
75 // changes its size (a window change).
77 // Args: vSigno - (R) Signal number.
82 sigwinch_handler(int vSigno)
86 struct winsize window_size;
87 if (::isatty(STDIN_FILENO) && ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
89 CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
90 if (window_size.ws_col > 0)
92 rDriverMgr.DriverResizeWindow((uint32_t)window_size.ws_col);
96 CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGWINCH", vSigno));
99 // CODETAG_IOR_SIGNALS
100 //++ ------------------------------------------------------------------------------------
101 // Details: The SIGINT signal is sent to a process by its controlling terminal when a
102 // user wishes to interrupt the process. This is typically initiated by pressing
103 // Control-C, but on some systems, the "delete" character or "break" key can be
105 // Be aware this function may be called on another thread besides the main thread.
107 // Args: vSigno - (R) Signal number.
112 sigint_handler(int vSigno)
114 static bool g_interrupt_sent = false;
115 CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
116 lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
117 if (pDebugger != nullptr)
119 if (!g_interrupt_sent)
121 g_interrupt_sent = true;
122 pDebugger->DispatchInputInterrupt();
123 g_interrupt_sent = false;
127 CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGINT", vSigno));
129 // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
130 // Signal MI to shutdown or halt a running debug session
131 CMICmnStreamStdin::Instance().SetCtrlCHit();
134 // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
135 // CODETAG_IOR_SIGNALS
136 //++ ------------------------------------------------------------------------------------
137 // Details: The SIGTSTP signal is sent to a process by its controlling terminal to
138 // request it to stop temporarily. It is commonly initiated by the user pressing
139 // Control-Z. Unlike SIGSTOP, the process can register a signal handler for or
140 // ignore the signal.
141 // *** The function does not behave ATM like the UNIX equivalent ***
143 // Args: vSigno - (R) Signal number.
148 sigtstp_handler(int vSigno)
150 CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
151 lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
152 if (pDebugger != nullptr)
154 pDebugger->SaveInputTerminalState();
157 CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGTSTP", vSigno));
159 // Signal MI to shutdown
160 CMICmnStreamStdin::Instance().SetCtrlCHit();
163 // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
164 // CODETAG_IOR_SIGNALS
165 //++ ------------------------------------------------------------------------------------
166 // Details: The SIGCONT signal instructs the operating system to continue (restart) a
167 // process previously paused by the SIGSTOP or SIGTSTP signal. One important use
168 // of this signal is in job control in the UNIX shell.
169 // *** The function does not behave ATM like the UNIX equivalent ***
171 // Args: vSigno - (R) Signal number.
176 sigcont_handler(int vSigno)
178 CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
179 lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
180 if (pDebugger != nullptr)
182 pDebugger->RestoreInputTerminalState();
185 CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGCONT", vSigno));
187 // Signal MI to shutdown
188 CMICmnStreamStdin::Instance().SetCtrlCHit();
191 //++ ------------------------------------------------------------------------------------
192 // Details: Init the MI driver system. Initialize the whole driver system which includes
193 // both the original LLDB driver and the MI driver.
196 // Return: MIstatus::success - Functional succeeded.
197 // MIstatus::failure - Functional failed.
201 DriverSystemInit(void)
203 bool bOk = MIstatus::success;
205 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
206 Driver *pDriver = Driver::CreateSelf();
207 if (pDriver == nullptr)
208 return MIstatus::failure;
209 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
211 CMIDriver &rMIDriver = CMIDriver::Instance();
212 CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
213 bOk = rDriverMgr.Initialize();
215 // Register MIDriver first as it needs to initialize and be ready
216 // for the Driver to get information from MIDriver when it initializes
217 // (LLDB Driver is registered with the Driver Manager in MI's Initialize())
218 bOk = bOk && rDriverMgr.RegisterDriver(rMIDriver, "MIDriver"); // Will be main driver
223 //++ ------------------------------------------------------------------------------------
224 // Details: Shutdown the debugger system. Release / terminate resources external to
225 // specifically the MI driver.
227 // Args: vbAppExitOk - (R) True = No problems, false = App exiting with problems (investigate!).
228 // Return: MIstatus::success - Functional succeeded.
229 // MIstatus::failure - Functional failed.
233 DriverSystemShutdown(const bool vbAppExitOk)
235 bool bOk = MIstatus::success;
237 // *** Order is important here ***
238 CMIDriverMgr::Instance().Shutdown();
240 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
243 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
250 sigwinch_handler(int signo)
252 struct winsize window_size;
253 if (isatty(STDIN_FILENO) && ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
255 if ((window_size.ws_col > 0) && g_driver != NULL)
257 g_driver->ResizeWindow(window_size.ws_col);
263 sigint_handler(int signo)
265 static bool g_interrupt_sent = false;
268 if (!g_interrupt_sent)
270 g_interrupt_sent = true;
271 g_driver->GetDebugger().DispatchInputInterrupt();
272 g_interrupt_sent = false;
281 sigtstp_handler(int signo)
283 g_driver->GetDebugger().SaveInputTerminalState();
284 signal(signo, SIG_DFL);
285 kill(getpid(), signo);
286 signal(signo, sigtstp_handler);
290 sigcont_handler(int signo)
292 g_driver->GetDebugger().RestoreInputTerminalState();
293 signal(signo, SIG_DFL);
294 kill(getpid(), signo);
295 signal(signo, sigcont_handler);
297 #endif // #if MICONFIG_COMPILE_MIDRIVER_VERSION
299 //++ ------------------------------------------------------------------------------------
300 // Details: MI's application start point of execution. The applicaton runs in two modes.
301 // An LLDB native driver mode where it acts no different from the LLDB driver.
302 // The other mode is the MI when it finds on the command line
303 // the --interpreter option. Command line argument --help on its own will give
304 // help for the LLDB driver. If entered with --interpreter then application
305 // help will provided.
307 // Args: argc - (R) An integer that contains the count of arguments that follow in
308 // argv. The argc parameter is always greater than or equal to 1.
309 // argv - (R) An array of null-terminated strings representing command-line
310 // arguments entered by the user of the program. By convention,
311 // argv[0] is the command with which the program is invoked.
312 // Return: int - 0 = Normal exit, program success.
313 // >0 = Program success with status i.e. Control-C signal status
314 // <0 = Program failed.
315 // -1 = Program failed reason not specified here, see MI log file.
316 // -1000 = Program failed did not initailize successfully.
319 #if MICONFIG_COMPILE_MIDRIVER_VERSION
321 main(int argc, char const *argv[])
323 #if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
325 CMIUtilDebug::ShowDlgWaitForDbgAttach();
327 CMIUtilDebug::WaitForDbgAttachInfinteLoop();
329 #endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
331 // *** Order is important here ***
332 bool bOk = DriverSystemInit();
335 DriverSystemShutdown(bOk);
339 // CODETAG_IOR_SIGNALS
340 signal(SIGPIPE, SIG_IGN);
341 signal(SIGWINCH, sigwinch_handler);
342 signal(SIGINT, sigint_handler);
343 signal(SIGTSTP, sigtstp_handler);
344 signal(SIGCONT, sigcont_handler);
346 bool bExiting = false;
347 CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
348 bOk = bOk && rDriverMgr.ParseArgs(argc, argv, bExiting);
349 if (bOk && !bExiting)
350 bOk = rDriverMgr.DriverParseArgs(argc, argv, stdout, bExiting);
351 if (bOk && !bExiting)
352 bOk = rDriverMgr.DriverMainLoop();
354 // Logger and other resources shutdown now
355 DriverSystemShutdown(bOk);
357 const int appResult = bOk ? 0 : -1;
361 #else // Operate the lldb Driver only version of the code
363 main(int argc, char const *argv[], char *envp[])
366 using namespace lldb;
367 SBDebugger::Initialize();
369 SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
371 signal(SIGPIPE, SIG_IGN);
372 signal(SIGWINCH, sigwinch_handler);
373 signal(SIGINT, sigint_handler);
374 signal(SIGTSTP, sigtstp_handler);
375 signal(SIGCONT, sigcont_handler);
377 // Create a scope for driver so that the driver object will destroy itself
378 // before SBDebugger::Terminate() is called.
382 bool exiting = false;
383 SBError error(driver.ParseArgs(argc, argv, stdout, exiting));
386 const char *error_cstr = error.GetCString();
388 ::fprintf(stderr, "error: %s\n", error_cstr);
396 SBDebugger::Terminate();
399 #endif // MICONFIG_COMPILE_MIDRIVER_VERSION