]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/lldb/tools/lldb-mi/MIDriverMain.cpp
Merge ^/head r274961 through r276418.
[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 sigwinch_handler( int vSigno )
82 {
83         MIunused( vSigno );
84
85         struct winsize window_size;
86         if( ::isatty( STDIN_FILENO ) && ::ioctl( STDIN_FILENO, TIOCGWINSZ, &window_size ) == 0 )
87         {
88                 CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
89                 if( window_size.ws_col > 0 )
90                 {
91                         rDriverMgr.DriverResizeWindow( (uint32_t) window_size.ws_col );
92                 }
93         }
94
95         CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGWINCH", vSigno ) );
96 }
97
98 // CODETAG_IOR_SIGNALS
99 //++ ------------------------------------------------------------------------------------
100 // Details:     The SIGINT signal is sent to a process by its controlling terminal when a 
101 //                      user wishes to interrupt the process. This is typically initiated by pressing 
102 //                      Control-C, but on some systems, the "delete" character or "break" key can be 
103 //                      used.
104 //                      Be aware this function may be called on another thread besides the main thread.
105 // Type:        Function.
106 // Args:        vSigno  - (R) Signal number.                                    
107 // Return:      None.
108 // Throws:      None.
109 //--
110 void sigint_handler( int vSigno )
111 {
112         static bool g_interrupt_sent = false;
113         CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
114         lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger();
115         if( pDebugger != nullptr )
116         {
117                 if( !g_interrupt_sent )
118                 {
119                         g_interrupt_sent = true;
120                         pDebugger->DispatchInputInterrupt();
121                         g_interrupt_sent = false;
122                 }
123         }
124
125         CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGINT", vSigno ) );
126
127         // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
128         // Signal MI to shutdown or halt a running debug session
129         CMICmnStreamStdin::Instance().SetCtrlCHit();
130 }
131
132 // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
133 // CODETAG_IOR_SIGNALS
134 //++ ------------------------------------------------------------------------------------
135 // Details:     The SIGTSTP signal is sent to a process by its controlling terminal to 
136 //                      request it to stop temporarily. It is commonly initiated by the user pressing 
137 //                      Control-Z. Unlike SIGSTOP, the process can register a signal handler for or 
138 //                      ignore the signal.
139 //                      *** The function does not behave ATM like the UNIX equivalent ***
140 // Type:        Function.
141 // Args:        vSigno  - (R) Signal number.                                    
142 // Return:      None.
143 // Throws:      None.
144 //--
145 void sigtstp_handler( int vSigno )
146 {
147         CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
148         lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger();
149         if( pDebugger != nullptr )
150         {
151                 pDebugger->SaveInputTerminalState();
152         }
153
154         CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGTSTP", vSigno ) );
155
156         // Signal MI to shutdown
157         CMICmnStreamStdin::Instance().SetCtrlCHit();
158 }
159
160 // ToDo: Reevaluate if this function needs to be implemented like the UNIX equivalent
161 // CODETAG_IOR_SIGNALS
162 //++ ------------------------------------------------------------------------------------
163 // Details:     The SIGCONT signal instructs the operating system to continue (restart) a 
164 //                      process previously paused by the SIGSTOP or SIGTSTP signal. One important use 
165 //                      of this signal is in job control in the UNIX shell.
166 //                      *** The function does not behave ATM like the UNIX equivalent ***
167 // Type:        Function.
168 // Args:        vSigno  - (R) Signal number.                            
169 // Return:      None.
170 // Throws:      None.
171 //--
172 void sigcont_handler( int vSigno )
173 {
174         CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
175         lldb::SBDebugger * pDebugger = rDriverMgr.DriverGetTheDebugger();
176         if( pDebugger != nullptr )
177         {
178                 pDebugger->RestoreInputTerminalState();
179         }
180
181         CMICmnLog::Instance().WriteLog( CMIUtilString::Format( MIRSRC( IDS_PROCESS_SIGNAL_RECEIVED ), "SIGCONT", vSigno ) );
182
183         // Signal MI to shutdown
184         CMICmnStreamStdin::Instance().SetCtrlCHit();
185 }
186
187 //++ ------------------------------------------------------------------------------------
188 // Details:     Init the MI driver system. Initialize the whole driver system which includes
189 //                      both the original LLDB driver and the MI driver.
190 // Type:        Function.
191 // Args:        None.                           
192 // Return:      MIstatus::success - Functional succeeded.
193 //                      MIstatus::failure - Functional failed.
194 // Throws:      None.
195 //--
196 bool DriverSystemInit( void )
197 {
198         bool bOk = MIstatus::success;
199
200 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
201         Driver * pDriver = Driver::CreateSelf();
202         if( pDriver == nullptr )
203                 return MIstatus::failure;
204 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
205
206         CMIDriver & rMIDriver = CMIDriver::Instance();
207         CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
208         bOk = rDriverMgr.Initialize();
209
210         // Register MIDriver first as it needs to initialize and be ready
211         // for the Driver to get information from MIDriver when it initializes
212         // (LLDB Driver is registered with the Driver Manager in MI's Initialize())
213         bOk = bOk && rDriverMgr.RegisterDriver( rMIDriver, "MIDriver" );        // Will be main driver
214
215         return bOk;
216 }
217
218 //++ ------------------------------------------------------------------------------------
219 // Details:     Shutdown the debugger system. Release / terminate resources external to
220 //                      specifically the MI driver.
221 // Type:        Function.
222 // Args:        vbAppExitOk     - (R) True = No problems, false = App exiting with problems (investigate!).                             
223 // Return:      MIstatus::success - Functional succeeded.
224 //                      MIstatus::failure - Functional failed.
225 // Throws:      None.
226 //--
227 bool DriverSystemShutdown( const bool vbAppExitOk )
228 {
229         bool bOk = MIstatus::success;
230
231         // *** Order is important here ***
232         CMIDriverMgr::Instance().Shutdown();
233
234 #if MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
235         delete g_driver;
236         g_driver = nullptr;     
237 #endif // MICONFIG_COMPILE_MIDRIVER_WITH_LLDBDRIVER
238
239         return bOk;
240 }
241
242 #else
243 void
244 sigwinch_handler (int signo)
245 {
246     struct winsize window_size;
247     if (isatty (STDIN_FILENO)
248         && ::ioctl (STDIN_FILENO, TIOCGWINSZ, &window_size) == 0)
249     {
250         if ((window_size.ws_col > 0) && g_driver != NULL)
251         {
252             g_driver->ResizeWindow (window_size.ws_col);
253         }
254     }
255 }
256
257 void
258 sigint_handler (int signo)
259 {
260         static bool g_interrupt_sent = false;
261     if (g_driver)
262         {
263                 if (!g_interrupt_sent)
264                 {
265                         g_interrupt_sent = true;
266                 g_driver->GetDebugger().DispatchInputInterrupt();
267                         g_interrupt_sent = false;
268                         return;
269                 }
270         }
271     
272         exit (signo);
273 }
274
275 void
276 sigtstp_handler (int signo)
277 {
278     g_driver->GetDebugger().SaveInputTerminalState();
279     signal (signo, SIG_DFL);
280     kill (getpid(), signo);
281     signal (signo, sigtstp_handler);
282 }
283
284 void
285 sigcont_handler (int signo)
286 {
287     g_driver->GetDebugger().RestoreInputTerminalState();
288     signal (signo, SIG_DFL);
289     kill (getpid(), signo);
290     signal (signo, sigcont_handler);
291 }
292 #endif // #if MICONFIG_COMPILE_MIDRIVER_VERSION
293
294 //++ ------------------------------------------------------------------------------------
295 // Details:     MI's application start point of execution. The applicaton runs in two modes.
296 //                      An LLDB native driver mode where it acts no different from the LLDB driver.
297 //                      The other mode is the MI when it finds on the command line
298 //                      the --interpreter option. Command line argument --help on its own will give
299 //                      help for the LLDB driver. If entered with --interpreter then application
300 //                      help will provided.
301 // Type:        Method.
302 // Args:        argc    - (R) An integer that contains the count of arguments that follow in 
303 //                                                argv. The argc parameter is always greater than or equal to 1.
304 //                      argv    - (R) An array of null-terminated strings representing command-line 
305 //                                                arguments entered by the user of the program. By convention, 
306 //                                                argv[0] is the command with which the program is invoked.
307 // Return:      int -  0 =       Normal exit, program success.
308 //                                >0    = Program success with status   i.e. Control-C signal status
309 //                                <0    = Program failed.
310 //                              -1              = Program failed reason not specified here, see MI log file.
311 //                              -1000   = Program failed did not initailize successfully.
312 // Throws:      None.
313 //--
314 #if MICONFIG_COMPILE_MIDRIVER_VERSION
315 int main( int argc, char const *argv[] )
316 {
317 #if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
318 #ifdef _WIN32
319         CMIUtilDebug::ShowDlgWaitForDbgAttach();
320 #else
321         CMIUtilDebug::WaitForDbgAttachInfinteLoop();
322 #endif //  _WIN32
323 #endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
324
325         // *** Order is important here ***
326         bool bOk = DriverSystemInit();
327         if( !bOk )
328         {
329                 DriverSystemShutdown( bOk );
330                 return -1000;
331         }
332                 
333         // CODETAG_IOR_SIGNALS
334         signal( SIGPIPE, SIG_IGN );
335         signal( SIGWINCH, sigwinch_handler );
336         signal( SIGINT, sigint_handler );
337         signal( SIGTSTP, sigtstp_handler );
338         signal( SIGCONT, sigcont_handler );
339                 
340         bool bExiting = false;
341         CMIDriverMgr & rDriverMgr = CMIDriverMgr::Instance();
342         bOk = bOk && rDriverMgr.ParseArgs( argc, argv, bExiting );
343         if( bOk && !bExiting )
344                 bOk = rDriverMgr.DriverParseArgs( argc, argv, stdout, bExiting );
345         if( bOk && !bExiting )
346                 bOk = rDriverMgr.DriverMainLoop();
347         
348         // Logger and other resources shutdown now
349         DriverSystemShutdown( bOk );
350
351         const int appResult = bOk ? 0 : -1;
352
353         return appResult;
354 }
355 #else // Operate the lldb Driver only version of the code
356 int main(int argc, char const *argv[], char *envp[])
357 {
358         MIunused( envp );
359         using namespace lldb;
360         SBDebugger::Initialize();
361
362         SBHostOS::ThreadCreated ("<lldb.driver.main-thread>");
363
364         signal (SIGPIPE, SIG_IGN);
365         signal (SIGWINCH, sigwinch_handler);
366         signal (SIGINT, sigint_handler);
367         signal (SIGTSTP, sigtstp_handler);
368         signal (SIGCONT, sigcont_handler);
369
370         // Create a scope for driver so that the driver object will destroy itself
371         // before SBDebugger::Terminate() is called.
372         {
373                 Driver driver;
374
375                 bool exiting = false;
376                 SBError error (driver.ParseArgs (argc, argv, stdout, exiting));
377                 if (error.Fail())
378                 {
379                         const char *error_cstr = error.GetCString ();
380                         if (error_cstr)
381                                 ::fprintf (stderr, "error: %s\n", error_cstr);
382                 }
383                 else if (!exiting)
384                 {
385                         driver.MainLoop();
386                 }
387         }
388
389         SBDebugger::Terminate();
390         return 0;
391 }
392 #endif // MICONFIG_COMPILE_MIDRIVER_VERSION
393