]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp
MFV r288408:
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / lldb / tools / lldb-mi / MIDriverMain.cpp
1 //===-- MIDriverMain.cpp ----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 //++
11 // File:        MIDriverMain.cpp
12 //
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
19 //              provided.
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:
23 //                  MICmdCommands.cpp
24 //                  MICmdBase.h / .cpp
25 //                  MICmdCmd.h / .cpp
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.
38 //
39 // Environment: Compilers:  Visual C++ 12.
40 //                          gcc (Ubuntu/Linaro 4.8.1-10ubuntu9) 4.8.1
41 //              Libraries:  See MIReadme.txt.
42 //
43 // Copyright:   None.
44 //--
45
46 #if defined(_MSC_VER)
47 #define _INC_SIGNAL // Stop window's signal.h being included - CODETAG_IOR_SIGNALS
48 #endif              // _MSC_VER
49
50 // Third party headers:
51 #include <stdio.h>
52 #include <lldb/API/SBHostOS.h>
53
54 // In house headers:
55 #include "MICmnConfig.h"
56 #include "Platform.h" // Define signals - CODETAG_IOR_SIGNALS
57 #include "Driver.h"
58 #include "MIDriverMgr.h"
59 #include "MIDriver.h"
60 #include "MICmnResources.h"
61 #include "MICmnStreamStdin.h"
62 #include "MIUtilDebug.h"
63 #include "MICmnLog.h"
64
65 #if MICONFIG_COMPILE_MIDRIVER_VERSION
66
67 #if defined(_MSC_VER)
68 #pragma warning(once : 4530) // Warning C4530: C++ exception handler used, but unwind semantics are not enabled. Specify /EHsc
69 #endif                       // _MSC_VER
70
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).
76 // Type:    Function.
77 // Args:    vSigno  - (R) Signal number.
78 // Return:  None.
79 // Throws:  None.
80 //--
81 void
82 sigwinch_handler(int vSigno)
83 {
84     MIunused(vSigno);
85
86     struct winsize window_size;
87     if (::isatty(STDIN_FILENO) && ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
88     {
89         CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
90         if (window_size.ws_col > 0)
91         {
92             rDriverMgr.DriverResizeWindow((uint32_t)window_size.ws_col);
93         }
94     }
95
96     CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGWINCH", vSigno));
97 }
98
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
104 //          used.
105 //          Be aware this function may be called on another thread besides the main thread.
106 // Type:    Function.
107 // Args:    vSigno  - (R) Signal number.
108 // Return:  None.
109 // Throws:  None.
110 //--
111 void
112 sigint_handler(int vSigno)
113 {
114     static bool g_interrupt_sent = false;
115     CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
116     lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
117     if (pDebugger != nullptr)
118     {
119         if (!g_interrupt_sent)
120         {
121             g_interrupt_sent = true;
122             pDebugger->DispatchInputInterrupt();
123             g_interrupt_sent = false;
124         }
125     }
126
127     CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGINT", vSigno));
128
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();
132 }
133
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 ***
142 // Type:    Function.
143 // Args:    vSigno  - (R) Signal number.
144 // Return:  None.
145 // Throws:  None.
146 //--
147 void
148 sigtstp_handler(int vSigno)
149 {
150     CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
151     lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
152     if (pDebugger != nullptr)
153     {
154         pDebugger->SaveInputTerminalState();
155     }
156
157     CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGTSTP", vSigno));
158
159     // Signal MI to shutdown
160     CMICmnStreamStdin::Instance().SetCtrlCHit();
161 }
162
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 ***
170 // Type:    Function.
171 // Args:    vSigno  - (R) Signal number.
172 // Return:  None.
173 // Throws:  None.
174 //--
175 void
176 sigcont_handler(int vSigno)
177 {
178     CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
179     lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
180     if (pDebugger != nullptr)
181     {
182         pDebugger->RestoreInputTerminalState();
183     }
184
185     CMICmnLog::Instance().WriteLog(CMIUtilString::Format(MIRSRC(IDS_PROCESS_SIGNAL_RECEIVED), "SIGCONT", vSigno));
186
187     // Signal MI to shutdown
188     CMICmnStreamStdin::Instance().SetCtrlCHit();
189 }
190
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.
194 // Type:    Function.
195 // Args:    None.
196 // Return:  MIstatus::success - Functional succeeded.
197 //          MIstatus::failure - Functional failed.
198 // Throws:  None.
199 //--
200 bool
201 DriverSystemInit(void)
202 {
203     bool bOk = MIstatus::success;
204
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
210
211     CMIDriver &rMIDriver = CMIDriver::Instance();
212     CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
213     bOk = rDriverMgr.Initialize();
214
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
219
220     return bOk;
221 }
222
223 //++ ------------------------------------------------------------------------------------
224 // Details: Shutdown the debugger system. Release / terminate resources external to
225 //          specifically the MI driver.
226 // Type:    Function.
227 // Args:    vbAppExitOk - (R) True = No problems, false = App exiting with problems (investigate!).
228 // Return:  MIstatus::success - Functional succeeded.
229 //          MIstatus::failure - Functional failed.
230 // Throws:  None.
231 //--
232 bool
233 DriverSystemShutdown(const bool vbAppExitOk)
234 {
235     bool bOk = MIstatus::success;
236
237     // *** Order is important here ***
238     CMIDriverMgr::Instance().Shutdown();
239
240 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
241     delete g_driver;
242     g_driver = nullptr;
243 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
244
245     return bOk;
246 }
247
248 #else
249 void
250 sigwinch_handler(int signo)
251 {
252     struct winsize window_size;
253     if (isatty(STDIN_FILENO) && ::ioctl(STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
254     {
255         if ((window_size.ws_col > 0) && g_driver != NULL)
256         {
257             g_driver->ResizeWindow(window_size.ws_col);
258         }
259     }
260 }
261
262 void
263 sigint_handler(int signo)
264 {
265     static bool g_interrupt_sent = false;
266     if (g_driver)
267     {
268         if (!g_interrupt_sent)
269         {
270             g_interrupt_sent = true;
271             g_driver->GetDebugger().DispatchInputInterrupt();
272             g_interrupt_sent = false;
273             return;
274         }
275     }
276
277     exit(signo);
278 }
279
280 void
281 sigtstp_handler(int signo)
282 {
283     g_driver->GetDebugger().SaveInputTerminalState();
284     signal(signo, SIG_DFL);
285     kill(getpid(), signo);
286     signal(signo, sigtstp_handler);
287 }
288
289 void
290 sigcont_handler(int signo)
291 {
292     g_driver->GetDebugger().RestoreInputTerminalState();
293     signal(signo, SIG_DFL);
294     kill(getpid(), signo);
295     signal(signo, sigcont_handler);
296 }
297 #endif // #if MICONFIG_COMPILE_MIDRIVER_VERSION
298
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.
306 // Type:    Method.
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.
317 // Throws:  None.
318 //--
319 #if MICONFIG_COMPILE_MIDRIVER_VERSION
320 int
321 main(int argc, char const *argv[])
322 {
323 #if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
324 #ifdef _WIN32
325     CMIUtilDebug::ShowDlgWaitForDbgAttach();
326 #else
327     CMIUtilDebug::WaitForDbgAttachInfinteLoop();
328 #endif //  _WIN32
329 #endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
330
331     // *** Order is important here ***
332     bool bOk = DriverSystemInit();
333     if (!bOk)
334     {
335         DriverSystemShutdown(bOk);
336         return -1000;
337     }
338
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);
345
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();
353
354     // Logger and other resources shutdown now
355     DriverSystemShutdown(bOk);
356
357     const int appResult = bOk ? 0 : -1;
358
359     return appResult;
360 }
361 #else  // Operate the lldb Driver only version of the code
362 int
363 main(int argc, char const *argv[], char *envp[])
364 {
365     MIunused(envp);
366     using namespace lldb;
367     SBDebugger::Initialize();
368
369     SBHostOS::ThreadCreated("<lldb.driver.main-thread>");
370
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);
376
377     // Create a scope for driver so that the driver object will destroy itself
378     // before SBDebugger::Terminate() is called.
379     {
380         Driver driver;
381
382         bool exiting = false;
383         SBError error(driver.ParseArgs(argc, argv, stdout, exiting));
384         if (error.Fail())
385         {
386             const char *error_cstr = error.GetCString();
387             if (error_cstr)
388                 ::fprintf(stderr, "error: %s\n", error_cstr);
389         }
390         else if (!exiting)
391         {
392             driver.MainLoop();
393         }
394     }
395
396     SBDebugger::Terminate();
397     return 0;
398 }
399 #endif // MICONFIG_COMPILE_MIDRIVER_VERSION