]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tools/lldb-mi/MIDriver.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / tools / lldb-mi / MIDriver.cpp
1 //===-- MIDriver.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 // Third party headers:
11 #include "lldb/API/SBError.h"
12 #include <fstream>
13
14 // In-house headers:
15 #include "MICmdArgValFile.h"
16 #include "MICmdArgValString.h"
17 #include "MICmdMgr.h"
18 #include "MICmnConfig.h"
19 #include "MICmnLLDBDebugSessionInfo.h"
20 #include "MICmnLLDBDebugger.h"
21 #include "MICmnLog.h"
22 #include "MICmnMIResultRecord.h"
23 #include "MICmnMIValueConst.h"
24 #include "MICmnResources.h"
25 #include "MICmnStreamStderr.h"
26 #include "MICmnStreamStdout.h"
27 #include "MICmnThreadMgrStd.h"
28 #include "MIDriver.h"
29 #include "MIUtilDebug.h"
30 #include "MIUtilSingletonHelper.h"
31
32 // Instantiations:
33 #if _DEBUG
34 const CMIUtilString CMIDriver::ms_constMIVersion =
35     MIRSRC(IDS_MI_VERSION_DESCRIPTION_DEBUG);
36 #else
37 const CMIUtilString CMIDriver::ms_constMIVersion =
38     MIRSRC(IDS_MI_VERSION_DESCRIPTION); // Matches version in resources file
39 #endif // _DEBUG
40 const CMIUtilString
41     CMIDriver::ms_constAppNameShort(MIRSRC(IDS_MI_APPNAME_SHORT));
42 const CMIUtilString CMIDriver::ms_constAppNameLong(MIRSRC(IDS_MI_APPNAME_LONG));
43
44 //++
45 //------------------------------------------------------------------------------------
46 // Details: CMIDriver constructor.
47 // Type:    Method.
48 // Args:    None.
49 // Return:  None.
50 // Throws:  None.
51 //--
52 CMIDriver::CMIDriver()
53     : m_bFallThruToOtherDriverEnabled(false), m_bDriverIsExiting(false),
54       m_handleMainThread(0), m_rStdin(CMICmnStreamStdin::Instance()),
55       m_rLldbDebugger(CMICmnLLDBDebugger::Instance()),
56       m_rStdOut(CMICmnStreamStdout::Instance()),
57       m_eCurrentDriverState(eDriverState_NotRunning),
58       m_bHaveExecutableFileNamePathOnCmdLine(false),
59       m_bDriverDebuggingArgExecutable(false),
60       m_bHaveCommandFileNamePathOnCmdLine(false) {}
61
62 //++
63 //------------------------------------------------------------------------------------
64 // Details: CMIDriver destructor.
65 // Type:    Overridden.
66 // Args:    None.
67 // Return:  None.
68 // Throws:  None.
69 //--
70 CMIDriver::~CMIDriver() {}
71
72 //++
73 //------------------------------------------------------------------------------------
74 // Details: Set whether *this driver (the parent) is enabled to pass a command
75 // to its
76 //          fall through (child) driver to interpret the command and do work
77 //          instead
78 //          (if *this driver decides it can't handle the command).
79 // Type:    Method.
80 // Args:    vbYes   - (R) True = yes fall through, false = do not pass on
81 // command.
82 // Return:  MIstatus::success - Functional succeeded.
83 //          MIstatus::failure - Functional failed.
84 // Throws:  None.
85 //--
86 bool CMIDriver::SetEnableFallThru(const bool vbYes) {
87   m_bFallThruToOtherDriverEnabled = vbYes;
88   return MIstatus::success;
89 }
90
91 //++
92 //------------------------------------------------------------------------------------
93 // Details: Get whether *this driver (the parent) is enabled to pass a command
94 // to its
95 //          fall through (child) driver to interpret the command and do work
96 //          instead
97 //          (if *this driver decides it can't handle the command).
98 // Type:    Method.
99 // Args:    None.
100 // Return:  bool - True = yes fall through, false = do not pass on command.
101 // Throws:  None.
102 //--
103 bool CMIDriver::GetEnableFallThru() const {
104   return m_bFallThruToOtherDriverEnabled;
105 }
106
107 //++
108 //------------------------------------------------------------------------------------
109 // Details: Retrieve MI's application name of itself.
110 // Type:    Method.
111 // Args:    None.
112 // Return:  CMIUtilString & - Text description.
113 // Throws:  None.
114 //--
115 const CMIUtilString &CMIDriver::GetAppNameShort() const {
116   return ms_constAppNameShort;
117 }
118
119 //++
120 //------------------------------------------------------------------------------------
121 // Details: Retrieve MI's application name of itself.
122 // Type:    Method.
123 // Args:    None.
124 // Return:  CMIUtilString & - Text description.
125 // Throws:  None.
126 //--
127 const CMIUtilString &CMIDriver::GetAppNameLong() const {
128   return ms_constAppNameLong;
129 }
130
131 //++
132 //------------------------------------------------------------------------------------
133 // Details: Retrieve MI's version description of itself.
134 // Type:    Method.
135 // Args:    None.
136 // Return:  CMIUtilString & - Text description.
137 // Throws:  None.
138 //--
139 const CMIUtilString &CMIDriver::GetVersionDescription() const {
140   return ms_constMIVersion;
141 }
142
143 //++
144 //------------------------------------------------------------------------------------
145 // Details: Initialize setup *this driver ready for use.
146 // Type:    Method.
147 // Args:    None.
148 // Return:  MIstatus::success - Functional succeeded.
149 //          MIstatus::failure - Functional failed.
150 // Throws:  None.
151 //--
152 bool CMIDriver::Initialize() {
153   m_eCurrentDriverState = eDriverState_Initialising;
154   m_clientUsageRefCnt++;
155
156   ClrErrorDescription();
157
158   if (m_bInitialized)
159     return MIstatus::success;
160
161   bool bOk = MIstatus::success;
162   CMIUtilString errMsg;
163
164   // Initialize all of the modules we depend on
165   MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
166   MI::ModuleInit<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk, errMsg);
167   MI::ModuleInit<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk, errMsg);
168   MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
169   MI::ModuleInit<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk,
170                                      errMsg);
171   MI::ModuleInit<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk, errMsg);
172   MI::ModuleInit<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
173   bOk &= m_rLldbDebugger.SetDriver(*this);
174   MI::ModuleInit<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk, errMsg);
175
176   m_bExitApp = false;
177
178   m_bInitialized = bOk;
179
180   if (!bOk) {
181     const CMIUtilString msg =
182         CMIUtilString::Format(MIRSRC(IDS_MI_INIT_ERR_DRIVER), errMsg.c_str());
183     SetErrorDescription(msg);
184     return MIstatus::failure;
185   }
186
187   m_eCurrentDriverState = eDriverState_RunningNotDebugging;
188
189   return bOk;
190 }
191
192 //++
193 //------------------------------------------------------------------------------------
194 // Details: Unbind detach or release resources used by *this driver.
195 // Type:    Method.
196 // Args:    None.
197 // Return:  MIstatus::success - Functional succeeded.
198 //          MIstatus::failure - Functional failed.
199 // Throws:  None.
200 //--
201 bool CMIDriver::Shutdown() {
202   if (--m_clientUsageRefCnt > 0)
203     return MIstatus::success;
204
205   if (!m_bInitialized)
206     return MIstatus::success;
207
208   m_eCurrentDriverState = eDriverState_ShuttingDown;
209
210   ClrErrorDescription();
211
212   bool bOk = MIstatus::success;
213   CMIUtilString errMsg;
214
215   // Shutdown all of the modules we depend on
216   MI::ModuleShutdown<CMICmnLLDBDebugger>(IDS_MI_INIT_ERR_LLDBDEBUGGER, bOk,
217                                          errMsg);
218   MI::ModuleShutdown<CMICmdMgr>(IDS_MI_INIT_ERR_CMDMGR, bOk, errMsg);
219   MI::ModuleShutdown<CMICmnStreamStdin>(IDS_MI_INIT_ERR_STREAMSTDIN, bOk,
220                                         errMsg);
221   MI::ModuleShutdown<CMICmnThreadMgrStd>(IDS_MI_INIT_ERR_THREADMANAGER, bOk,
222                                          errMsg);
223   MI::ModuleShutdown<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
224   MI::ModuleShutdown<CMICmnStreamStderr>(IDS_MI_INIT_ERR_STREAMSTDERR, bOk,
225                                          errMsg);
226   MI::ModuleShutdown<CMICmnStreamStdout>(IDS_MI_INIT_ERR_STREAMSTDOUT, bOk,
227                                          errMsg);
228   MI::ModuleShutdown<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
229
230   if (!bOk) {
231     SetErrorDescriptionn(MIRSRC(IDS_MI_SHUTDOWN_ERR), errMsg.c_str());
232   }
233
234   m_eCurrentDriverState = eDriverState_NotRunning;
235
236   return bOk;
237 }
238
239 //++
240 //------------------------------------------------------------------------------------
241 // Details: Work function. Client (the driver's user) is able to append their
242 // own message
243 //          in to the MI's Log trace file.
244 // Type:    Method.
245 // Args:    vMessage          - (R) Client's text message.
246 // Return:  MIstatus::success - Functional succeeded.
247 //          MIstatus::failure - Functional failed.
248 // Throws:  None.
249 //--
250 bool CMIDriver::WriteMessageToLog(const CMIUtilString &vMessage) {
251   CMIUtilString msg;
252   msg = CMIUtilString::Format(MIRSRC(IDS_MI_CLIENT_MSG), vMessage.c_str());
253   return m_pLog->Write(msg, CMICmnLog::eLogVerbosity_ClientMsg);
254 }
255
256 //++
257 //------------------------------------------------------------------------------------
258 // Details: CDriverMgr calls *this driver initialize setup ready for use.
259 // Type:    Overridden.
260 // Args:    None.
261 // Return:  MIstatus::success - Functional succeeded.
262 //          MIstatus::failure - Functional failed.
263 // Throws:  None.
264 //--
265 bool CMIDriver::DoInitialize() { return CMIDriver::Instance().Initialize(); }
266
267 //++
268 //------------------------------------------------------------------------------------
269 // Details: CDriverMgr calls *this driver to unbind detach or release resources
270 // used by
271 //          *this driver.
272 // Type:    Overridden.
273 // Args:    None.
274 // Return:  MIstatus::success - Functional succeeded.
275 //          MIstatus::failure - Functional failed.
276 // Throws:  None.
277 //--
278 bool CMIDriver::DoShutdown() { return CMIDriver::Instance().Shutdown(); }
279
280 //++
281 //------------------------------------------------------------------------------------
282 // Details: Retrieve the name for *this driver.
283 // Type:    Overridden.
284 // Args:    None.
285 // Return:  CMIUtilString & - Driver name.
286 // Throws:  None.
287 //--
288 const CMIUtilString &CMIDriver::GetName() const {
289   const CMIUtilString &rName = GetAppNameLong();
290   const CMIUtilString &rVsn = GetVersionDescription();
291   static CMIUtilString strName =
292       CMIUtilString::Format("%s %s", rName.c_str(), rVsn.c_str());
293
294   return strName;
295 }
296
297 //++
298 //------------------------------------------------------------------------------------
299 // Details: Retrieve *this driver's last error condition.
300 // Type:    Overridden.
301 // Args:    None.
302 // Return:  CMIUtilString - Text description.
303 // Throws:  None.
304 //--
305 CMIUtilString CMIDriver::GetError() const { return GetErrorDescription(); }
306
307 //++
308 //------------------------------------------------------------------------------------
309 // Details: Call *this driver to return it's debugger.
310 // Type:    Overridden.
311 // Args:    None.
312 // Return:  lldb::SBDebugger & - LLDB debugger object reference.
313 // Throws:  None.
314 //--
315 lldb::SBDebugger &CMIDriver::GetTheDebugger() {
316   return m_rLldbDebugger.GetTheDebugger();
317 }
318
319 //++
320 //------------------------------------------------------------------------------------
321 // Details: Specify another driver *this driver can call should this driver not
322 // be able
323 //          to handle the client data input. DoFallThruToAnotherDriver() makes
324 //          the call.
325 // Type:    Overridden.
326 // Args:    vrOtherDriver     - (R) Reference to another driver object.
327 // Return:  MIstatus::success - Functional succeeded.
328 //          MIstatus::failure - Functional failed.
329 // Throws:  None.
330 //--
331 bool CMIDriver::SetDriverToFallThruTo(const CMIDriverBase &vrOtherDriver) {
332   m_pDriverFallThru = const_cast<CMIDriverBase *>(&vrOtherDriver);
333
334   return m_pDriverFallThru->SetDriverParent(*this);
335 }
336
337 //++
338 //------------------------------------------------------------------------------------
339 // Details: Proxy function CMIDriverMgr IDriver interface implementation. *this
340 // driver's
341 //          implementation called from here to match the existing function name
342 //          of the
343 //          original LLDB driver class (the extra indirection is not necessarily
344 //          required).
345 //          Check the arguments that were passed to this program to make sure
346 //          they are
347 //          valid and to get their argument values (if any).
348 // Type:    Overridden.
349 // Args:    argc        - (R)   An integer that contains the count of arguments
350 // that follow in
351 //                              argv. The argc parameter is always greater than
352 //                              or equal to 1.
353 //          argv        - (R)   An array of null-terminated strings representing
354 //          command-line
355 //                              arguments entered by the user of the program. By
356 //                              convention,
357 //                              argv[0] is the command with which the program is
358 //                              invoked.
359 //          vpStdOut    - (R)   Pointer to a standard output stream.
360 //          vwbExiting  - (W)   True = *this want to exit, Reasons: help,
361 //          invalid arg(s),
362 //                              version information only.
363 //                              False = Continue to work, start debugger i.e.
364 //                              Command
365 //                              interpreter.
366 // Return:  lldb::SBError - LLDB current error status.
367 // Throws:  None.
368 //--
369 lldb::SBError CMIDriver::DoParseArgs(const int argc, const char *argv[],
370                                      FILE *vpStdOut, bool &vwbExiting) {
371   return ParseArgs(argc, argv, vpStdOut, vwbExiting);
372 }
373
374 //++
375 //------------------------------------------------------------------------------------
376 // Details: Check the arguments that were passed to this program to make sure
377 // they are
378 //          valid and to get their argument values (if any). The following are
379 //          options
380 //          that are only handled by *this driver:
381 //              --executable <file>
382 //              --source <file> or -s <file>
383 //          The application's options --interpreter and --executable in code act
384 //          very similar.
385 //          The --executable is necessary to differentiate whether the MI Driver
386 //          is being
387 //          used by a client (e.g. Eclipse) or from the command line. Eclipse
388 //          issues the option
389 //          --interpreter and also passes additional arguments which can be
390 //          interpreted as an
391 //          executable if called from the command line. Using --executable tells
392 //          the MI Driver
393 //          it is being called from the command line and to prepare to launch
394 //          the executable
395 //          argument for a debug session. Using --interpreter on the command
396 //          line does not
397 //          issue additional commands to initialise a debug session.
398 // Type:    Overridden.
399 // Args:    argc        - (R)   An integer that contains the count of arguments
400 // that follow in
401 //                              argv. The argc parameter is always greater than
402 //                              or equal to 1.
403 //          argv        - (R)   An array of null-terminated strings representing
404 //          command-line
405 //                              arguments entered by the user of the program. By
406 //                              convention,
407 //                              argv[0] is the command with which the program is
408 //                              invoked.
409 //          vpStdOut    - (R)   Pointer to a standard output stream.
410 //          vwbExiting  - (W)   True = *this want to exit, Reasons: help,
411 //          invalid arg(s),
412 //                              version information only.
413 //                              False = Continue to work, start debugger i.e.
414 //                              Command
415 //                              interpreter.
416 // Return:  lldb::SBError - LLDB current error status.
417 // Throws:  None.
418 //--
419 lldb::SBError CMIDriver::ParseArgs(const int argc, const char *argv[],
420                                    FILE *vpStdOut, bool &vwbExiting) {
421   lldb::SBError errStatus;
422   const bool bHaveArgs(argc >= 2);
423
424   // *** Add any args handled here to GetHelpOnCmdLineArgOptions() ***
425
426   // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
427   // Look for the command line options
428   bool bHaveExecutableFileNamePath = false;
429   bool bHaveExecutableLongOption = false;
430
431   if (bHaveArgs) {
432     // Search right to left to look for filenames
433     for (MIint i = argc - 1; i > 0; i--) {
434       const CMIUtilString strArg(argv[i]);
435       const CMICmdArgValFile argFile;
436
437       // Check for a filename
438       if (argFile.IsFilePath(strArg) ||
439           CMICmdArgValString(true, false, true).IsStringArg(strArg)) {
440         // Is this the command file for the '-s' or '--source' options?
441         const CMIUtilString strPrevArg(argv[i - 1]);
442         if (strPrevArg.compare("-s") == 0 ||
443             strPrevArg.compare("--source") == 0) {
444           m_strCmdLineArgCommandFileNamePath = strArg;
445           m_bHaveCommandFileNamePathOnCmdLine = true;
446           i--; // skip '-s' on the next loop
447           continue;
448         }
449         // Else, must be the executable
450         bHaveExecutableFileNamePath = true;
451         m_strCmdLineArgExecuteableFileNamePath = strArg;
452         m_bHaveExecutableFileNamePathOnCmdLine = true;
453       }
454       // Report error if no command file was specified for the '-s' or
455       // '--source' options
456       else if (strArg.compare("-s") == 0 || strArg.compare("--source") == 0) {
457         vwbExiting = true;
458         const CMIUtilString errMsg = CMIUtilString::Format(
459             MIRSRC(IDS_CMD_ARGS_ERR_VALIDATION_MISSING_INF), strArg.c_str());
460         errStatus.SetErrorString(errMsg.c_str());
461         break;
462       }
463       // This argument is also checked for in CMIDriverMgr::ParseArgs()
464       else if (strArg.compare("--executable") == 0) // Used to specify that
465                                                     // there is executable
466                                                     // argument also on the
467                                                     // command line
468       {                                             // See fn description.
469         bHaveExecutableLongOption = true;
470       }
471     }
472   }
473
474   if (bHaveExecutableFileNamePath && bHaveExecutableLongOption) {
475     SetDriverDebuggingArgExecutable();
476   }
477
478   return errStatus;
479 }
480
481 //++
482 //------------------------------------------------------------------------------------
483 // Details: A client can ask if *this driver is GDB/MI compatible.
484 // Type:    Overridden.
485 // Args:    None.
486 // Return:  True - GBD/MI compatible LLDB front end.
487 //          False - Not GBD/MI compatible LLDB front end.
488 // Throws:  None.
489 //--
490 bool CMIDriver::GetDriverIsGDBMICompatibleDriver() const { return true; }
491
492 //++
493 //------------------------------------------------------------------------------------
494 // Details: Start worker threads for the driver.
495 // Type:    Method.
496 // Args:    None.
497 // Return:  MIstatus::success - Functional succeeded.
498 //          MIstatus::failure - Functional failed.
499 // Throws:  None.
500 //--
501 bool CMIDriver::StartWorkerThreads() {
502   bool bOk = MIstatus::success;
503
504   // Grab the thread manager
505   CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
506
507   // Start the event polling thread
508   if (bOk && !rThreadMgr.ThreadStart<CMICmnLLDBDebugger>(m_rLldbDebugger)) {
509     const CMIUtilString errMsg = CMIUtilString::Format(
510         MIRSRC(IDS_THREADMGR_ERR_THREAD_FAIL_CREATE),
511         CMICmnThreadMgrStd::Instance().GetErrorDescription().c_str());
512     SetErrorDescriptionn(errMsg);
513     return MIstatus::failure;
514   }
515
516   return bOk;
517 }
518
519 //++
520 //------------------------------------------------------------------------------------
521 // Details: Stop worker threads for the driver.
522 // Type:    Method.
523 // Args:    None.
524 // Return:  MIstatus::success - Functional succeeded.
525 //          MIstatus::failure - Functional failed.
526 // Throws:  None.
527 //--
528 bool CMIDriver::StopWorkerThreads() {
529   CMICmnThreadMgrStd &rThreadMgr = CMICmnThreadMgrStd::Instance();
530   return rThreadMgr.ThreadAllTerminate();
531 }
532
533 //++
534 //------------------------------------------------------------------------------------
535 // Details: Call this function puts *this driver to work.
536 //          This function is used by the application's main thread.
537 // Type:    Overridden.
538 // Args:    None.
539 // Return:  MIstatus::success - Functional succeeded.
540 //          MIstatus::failure - Functional failed.
541 // Throws:  None.
542 //--
543 bool CMIDriver::DoMainLoop() {
544   if (!InitClientIDEToMIDriver()) // Init Eclipse IDE
545   {
546     SetErrorDescriptionn(MIRSRC(IDS_MI_INIT_ERR_CLIENT_USING_DRIVER));
547     return MIstatus::failure;
548   }
549
550   if (!StartWorkerThreads())
551     return MIstatus::failure;
552
553   bool bOk = MIstatus::success;
554
555   if (HaveExecutableFileNamePathOnCmdLine()) {
556     if (!LocalDebugSessionStartupExecuteCommands()) {
557       SetErrorDescription(MIRSRC(IDS_MI_INIT_ERR_LOCAL_DEBUG_SESSION));
558       bOk = MIstatus::failure;
559     }
560   }
561
562   // App is not quitting currently
563   m_bExitApp = false;
564
565   // Handle source file
566   if (m_bHaveCommandFileNamePathOnCmdLine) {
567     const bool bAsyncMode = false;
568     ExecuteCommandFile(bAsyncMode);
569   }
570
571   // While the app is active
572   while (bOk && !m_bExitApp) {
573     CMIUtilString errorText;
574     const char *pCmd = m_rStdin.ReadLine(errorText);
575     if (pCmd != nullptr) {
576       CMIUtilString lineText(pCmd);
577       if (!lineText.empty()) {
578         // Check that the handler thread is alive (otherwise we stuck here)
579         assert(CMICmnLLDBDebugger::Instance().ThreadIsActive());
580
581         {
582           // Lock Mutex before processing commands so that we don't disturb an
583           // event
584           // being processed
585           CMIUtilThreadLock lock(
586               CMICmnLLDBDebugSessionInfo::Instance().GetSessionMutex());
587           bOk = InterpretCommand(lineText);
588         }
589
590         // Draw prompt if desired
591         bOk = bOk && CMICmnStreamStdout::WritePrompt();
592
593         // Wait while the handler thread handles incoming events
594         CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
595       }
596     }
597   }
598
599   // Signal that the application is shutting down
600   DoAppQuit();
601
602   // Close and wait for the workers to stop
603   StopWorkerThreads();
604
605   return MIstatus::success;
606 }
607
608 //++
609 //------------------------------------------------------------------------------------
610 // Details: Set things in motion, set state etc that brings *this driver (and
611 // the
612 //          application) to a tidy shutdown.
613 //          This function is used by the application's main thread.
614 // Type:    Method.
615 // Args:    None.
616 // Return:  MIstatus::success - Functional succeeded.
617 //          MIstatus::failure - Functional failed.
618 // Throws:  None.
619 //--
620 bool CMIDriver::DoAppQuit() {
621   bool bYesQuit = true;
622
623   // Shutdown stuff, ready app for exit
624   {
625     CMIUtilThreadLock lock(m_threadMutex);
626     m_bDriverIsExiting = true;
627   }
628
629   return bYesQuit;
630 }
631
632 //++
633 //------------------------------------------------------------------------------------
634 // Details: *this driver passes text commands to a fall through driver is it
635 // does not
636 //          understand them (the LLDB driver).
637 //          This function is used by the application's main thread.
638 // Type:    Method.
639 // Args:    vTextLine           - (R) Text data representing a possible command.
640 //          vwbCmdYesValid      - (W) True = Command valid, false = command not
641 //          handled.
642 // Return:  MIstatus::success - Functional succeeded.
643 //          MIstatus::failure - Functional failed.
644 // Throws:  None.
645 //--
646 bool CMIDriver::InterpretCommandFallThruDriver(const CMIUtilString &vTextLine,
647                                                bool &vwbCmdYesValid) {
648   MIunused(vTextLine);
649   MIunused(vwbCmdYesValid);
650
651   // ToDo: Implement when less urgent work to be done or decide remove as not
652   // required
653   // bool bOk = MIstatus::success;
654   // bool bCmdNotUnderstood = true;
655   // if( bCmdNotUnderstood && GetEnableFallThru() )
656   //{
657   //  CMIUtilString errMsg;
658   //  bOk = DoFallThruToAnotherDriver( vStdInBuffer, errMsg );
659   //  if( !bOk )
660   //  {
661   //      errMsg = errMsg.StripCREndOfLine();
662   //      errMsg = errMsg.StripCRAll();
663   //      const CMIDriverBase * pOtherDriver = GetDriverToFallThruTo();
664   //      const char * pName = pOtherDriver->GetDriverName().c_str();
665   //      const char * pId = pOtherDriver->GetDriverId().c_str();
666   //      const CMIUtilString msg( CMIUtilString::Format( MIRSRC(
667   //      IDS_DRIVER_ERR_FALLTHRU_DRIVER_ERR ), pName, pId, errMsg.c_str() )
668   //);
669   //      m_pLog->WriteMsg( msg );
670   //  }
671   //}
672   //
673   // vwbCmdYesValid = bOk;
674   // CMIUtilString strNot;
675   // if( vwbCmdYesValid)
676   //  strNot = CMIUtilString::Format( "%s ", MIRSRC( IDS_WORD_NOT ) );
677   // const CMIUtilString msg( CMIUtilString::Format( MIRSRC(
678   // IDS_FALLTHRU_DRIVER_CMD_RECEIVED ), vTextLine.c_str(), strNot.c_str() ) );
679   // m_pLog->WriteLog( msg );
680
681   return MIstatus::success;
682 }
683
684 //++
685 //------------------------------------------------------------------------------------
686 // Details: Retrieve the name for *this driver.
687 // Type:    Overridden.
688 // Args:    None.
689 // Return:  CMIUtilString & - Driver name.
690 // Throws:  None.
691 //--
692 const CMIUtilString &CMIDriver::GetDriverName() const { return GetName(); }
693
694 //++
695 //------------------------------------------------------------------------------------
696 // Details: Get the unique ID for *this driver.
697 // Type:    Overridden.
698 // Args:    None.
699 // Return:  CMIUtilString & - Text description.
700 // Throws:  None.
701 //--
702 const CMIUtilString &CMIDriver::GetDriverId() const { return GetId(); }
703
704 //++
705 //------------------------------------------------------------------------------------
706 // Details: This function allows *this driver to call on another driver to
707 // perform work
708 //          should this driver not be able to handle the client data input.
709 //          SetDriverToFallThruTo() specifies the fall through to driver.
710 //          Check the error message if the function returns a failure.
711 // Type:    Overridden.
712 // Args:    vCmd        - (R) Command instruction to interpret.
713 //          vwErrMsg    - (W) Error description on command failing.
714 // Return:  MIstatus::success - Command succeeded.
715 //          MIstatus::failure - Command failed.
716 // Throws:  None.
717 //--
718 bool CMIDriver::DoFallThruToAnotherDriver(const CMIUtilString &vCmd,
719                                           CMIUtilString &vwErrMsg) {
720   bool bOk = MIstatus::success;
721
722   CMIDriverBase *pOtherDriver = GetDriverToFallThruTo();
723   if (pOtherDriver == nullptr)
724     return bOk;
725
726   return pOtherDriver->DoFallThruToAnotherDriver(vCmd, vwErrMsg);
727 }
728
729 //++
730 //------------------------------------------------------------------------------------
731 // Details: *this driver provides a file stream to other drivers on which *this
732 // driver
733 //          write's out to and they read as expected input. *this driver is
734 //          passing
735 //          through commands to the (child) pass through assigned driver.
736 // Type:    Overrdidden.
737 // Args:    None.
738 // Return:  FILE * - Pointer to stream.
739 // Throws:  None.
740 //--
741 FILE *CMIDriver::GetStdin() const {
742   // Note this fn is called on CMIDriverMgr register driver so stream has to be
743   // available before *this driver has been initialized! Flaw?
744
745   // This very likely to change later to a stream that the pass thru driver
746   // will read and we write to give it 'input'
747   return stdin;
748 }
749
750 //++
751 //------------------------------------------------------------------------------------
752 // Details: *this driver provides a file stream to other pass through assigned
753 // drivers
754 //          so they know what to write to.
755 // Type:    Overidden.
756 // Args:    None.
757 // Return:  FILE * - Pointer to stream.
758 // Throws:  None.
759 //--
760 FILE *CMIDriver::GetStdout() const {
761   // Note this fn is called on CMIDriverMgr register driver so stream has to be
762   // available before *this driver has been initialized! Flaw?
763
764   // Do not want to pass through driver to write to stdout
765   return NULL;
766 }
767
768 //++
769 //------------------------------------------------------------------------------------
770 // Details: *this driver provides a error file stream to other pass through
771 // assigned drivers
772 //          so they know what to write to.
773 // Type:    Overidden.
774 // Args:    None.
775 // Return:  FILE * - Pointer to stream.
776 // Throws:  None.
777 //--
778 FILE *CMIDriver::GetStderr() const {
779   // Note this fn is called on CMIDriverMgr register driver so stream has to be
780   // available before *this driver has been initialized! Flaw?
781
782   // This very likely to change later to a stream that the pass thru driver
783   // will write to and *this driver reads from to pass on the CMICmnLog object
784   return stderr;
785 }
786
787 //++
788 //------------------------------------------------------------------------------------
789 // Details: Set a unique ID for *this driver. It cannot be empty.
790 // Type:    Overridden.
791 // Args:    vId - (R) Text description.
792 // Return:  MIstatus::success - Functional succeeded.
793 //          MIstatus::failure - Functional failed.
794 // Throws:  None.
795 //--
796 bool CMIDriver::SetId(const CMIUtilString &vId) {
797   if (vId.empty()) {
798     SetErrorDescriptionn(MIRSRC(IDS_DRIVER_ERR_ID_INVALID), GetName().c_str(),
799                          vId.c_str());
800     return MIstatus::failure;
801   }
802
803   m_strDriverId = vId;
804   return MIstatus::success;
805 }
806
807 //++
808 //------------------------------------------------------------------------------------
809 // Details: Get the unique ID for *this driver.
810 // Type:    Overridden.
811 // Args:    None.
812 // Return:  CMIUtilString & - Text description.
813 // Throws:  None.
814 //--
815 const CMIUtilString &CMIDriver::GetId() const { return m_strDriverId; }
816
817 //++
818 //------------------------------------------------------------------------------------
819 // Details: Interpret the text data and match against current commands to see if
820 // there
821 //          is a match. If a match then the command is issued and actioned on.
822 //          The
823 //          text data if not understood by *this driver is past on to the Fall
824 //          Thru
825 //          driver.
826 //          This function is used by the application's main thread.
827 // Type:    Method.
828 // Args:    vTextLine   - (R) Text data representing a possible command.
829 // Return:  MIstatus::success - Functional succeeded.
830 //          MIstatus::failure - Functional failed.
831 // Throws:  None.
832 //--
833 bool CMIDriver::InterpretCommand(const CMIUtilString &vTextLine) {
834   const bool bNeedToRebroadcastStopEvent =
835       m_rLldbDebugger.CheckIfNeedToRebroadcastStopEvent();
836   bool bCmdYesValid = false;
837   bool bOk = InterpretCommandThisDriver(vTextLine, bCmdYesValid);
838   if (bOk && !bCmdYesValid)
839     bOk = InterpretCommandFallThruDriver(vTextLine, bCmdYesValid);
840
841   if (bNeedToRebroadcastStopEvent)
842     m_rLldbDebugger.RebroadcastStopEvent();
843
844   return bOk;
845 }
846
847 //++
848 //------------------------------------------------------------------------------------
849 // Details: Helper function for CMIDriver::InterpretCommandThisDriver.
850 //          Convert a CLI command to MI command (just wrap any CLI command
851 //          into "<tokens>-interpreter-exec command \"<CLI command>\"").
852 // Type:    Method.
853 // Args:    vTextLine   - (R) Text data representing a possible command.
854 // Return:  CMIUtilString   - The original MI command or converted CLI command.
855 //          MIstatus::failure - Functional failed.
856 // Throws:  None.
857 //--
858 CMIUtilString
859 CMIDriver::WrapCLICommandIntoMICommand(const CMIUtilString &vTextLine) const {
860   // Tokens contain following digits
861   static const CMIUtilString digits("0123456789");
862
863   // Consider an algorithm on the following example:
864   // 001-file-exec-and-symbols "/path/to/file"
865   //
866   // 1. Skip a command token
867   // For example:
868   // 001-file-exec-and-symbols "/path/to/file"
869   // 001target create "/path/to/file"
870   //    ^ -- command starts here (in both cases)
871   // Also possible case when command not found:
872   // 001
873   //    ^ -- i.e. only tokens are present (or empty string at all)
874   const size_t nCommandOffset = vTextLine.find_first_not_of(digits);
875
876   // 2. Check if command is empty
877   // For example:
878   // 001-file-exec-and-symbols "/path/to/file"
879   // 001target create "/path/to/file"
880   //    ^ -- command not empty (in both cases)
881   // or:
882   // 001
883   //    ^ -- command wasn't found
884   const bool bIsEmptyCommand = (nCommandOffset == CMIUtilString::npos);
885
886   // 3. Check and exit if it isn't a CLI command
887   // For example:
888   // 001-file-exec-and-symbols "/path/to/file"
889   // 001
890   //    ^ -- it isn't CLI command (in both cases)
891   // or:
892   // 001target create "/path/to/file"
893   //    ^ -- it's CLI command
894   const bool bIsCliCommand =
895       !bIsEmptyCommand && (vTextLine.at(nCommandOffset) != '-');
896   if (!bIsCliCommand)
897     return vTextLine;
898
899   // 4. Wrap CLI command to make it MI-compatible
900   //
901   // 001target create "/path/to/file"
902   // ^^^ -- token
903   const std::string vToken(vTextLine.begin(),
904                            vTextLine.begin() + nCommandOffset);
905   // 001target create "/path/to/file"
906   //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- CLI command
907   const CMIUtilString vCliCommand(std::string(vTextLine, nCommandOffset));
908
909   // 5. Escape special characters and embed the command in a string
910   // Result: it looks like -- target create \"/path/to/file\".
911   const std::string vShieldedCliCommand(vCliCommand.AddSlashes());
912
913   // 6. Turn the CLI command into an MI command, as in:
914   // 001-interpreter-exec command "target create \"/path/to/file\""
915   // ^^^ -- token
916   //    ^^^^^^^^^^^^^^^^^^^^^^^^^^^                               ^ -- wrapper
917   //                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -- shielded
918   //                               CLI command
919   return CMIUtilString::Format("%s-interpreter-exec command \"%s\"",
920                                vToken.c_str(), vShieldedCliCommand.c_str());
921 }
922
923 //++
924 //------------------------------------------------------------------------------------
925 // Details: Interpret the text data and match against current commands to see if
926 // there
927 //          is a match. If a match then the command is issued and actioned on.
928 //          If a
929 //          command cannot be found to match then vwbCmdYesValid is set to false
930 //          and
931 //          nothing else is done here.
932 //          This function is used by the application's main thread.
933 // Type:    Method.
934 // Args:    vTextLine           - (R) Text data representing a possible command.
935 //          vwbCmdYesValid      - (W) True = Command valid, false = command not
936 //          handled.
937 // Return:  MIstatus::success - Functional succeeded.
938 //          MIstatus::failure - Functional failed.
939 // Throws:  None.
940 //--
941 bool CMIDriver::InterpretCommandThisDriver(const CMIUtilString &vTextLine,
942                                            bool &vwbCmdYesValid) {
943   // Convert any CLI commands into MI commands
944   const CMIUtilString vMITextLine(WrapCLICommandIntoMICommand(vTextLine));
945
946   vwbCmdYesValid = false;
947   bool bCmdNotInCmdFactor = false;
948   SMICmdData cmdData;
949   CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
950   if (!rCmdMgr.CmdInterpret(vMITextLine, vwbCmdYesValid, bCmdNotInCmdFactor,
951                             cmdData))
952     return MIstatus::failure;
953
954   if (vwbCmdYesValid) {
955     // For debugging only
956     // m_pLog->WriteLog( cmdData.strMiCmdAll.c_str() );
957
958     return ExecuteCommand(cmdData);
959   }
960
961   // Check for escape character, may be cursor control characters
962   // This code is not necessary for application operation, just want to keep
963   // tabs on what
964   // has been given to the driver to try and interpret.
965   if (vMITextLine.at(0) == 27) {
966     CMIUtilString logInput(MIRSRC(IDS_STDIN_INPUT_CTRL_CHARS));
967     for (MIuint i = 0; i < vMITextLine.length(); i++) {
968       logInput += CMIUtilString::Format("%d ", vMITextLine.at(i));
969     }
970     m_pLog->WriteLog(logInput);
971     return MIstatus::success;
972   }
973
974   // Write to the Log that a 'command' was not valid.
975   // Report back to the MI client via MI result record.
976   CMIUtilString strNotInCmdFactory;
977   if (bCmdNotInCmdFactor)
978     strNotInCmdFactory = CMIUtilString::Format(
979         MIRSRC(IDS_DRIVER_CMD_NOT_IN_FACTORY), cmdData.strMiCmd.c_str());
980   const CMIUtilString strNot(
981       CMIUtilString::Format("%s ", MIRSRC(IDS_WORD_NOT)));
982   const CMIUtilString msg(CMIUtilString::Format(
983       MIRSRC(IDS_DRIVER_CMD_RECEIVED), vMITextLine.c_str(), strNot.c_str(),
984       strNotInCmdFactory.c_str()));
985   const CMICmnMIValueConst vconst = CMICmnMIValueConst(msg);
986   const CMICmnMIValueResult valueResult("msg", vconst);
987   const CMICmnMIResultRecord miResultRecord(
988       cmdData.strMiCmdToken, CMICmnMIResultRecord::eResultClass_Error,
989       valueResult);
990   const bool bOk = m_rStdOut.WriteMIResponse(miResultRecord.GetString());
991
992   // Proceed to wait for or execute next command
993   return bOk;
994 }
995
996 //++
997 //------------------------------------------------------------------------------------
998 // Details: Having previously had the potential command validated and found
999 // valid now
1000 //          get the command executed.
1001 //          This function is used by the application's main thread.
1002 // Type:    Method.
1003 // Args:    vCmdData    - (RW) Command meta data.
1004 // Return:  MIstatus::success - Functional succeeded.
1005 //          MIstatus::failure - Functional failed.
1006 // Throws:  None.
1007 //--
1008 bool CMIDriver::ExecuteCommand(const SMICmdData &vCmdData) {
1009   CMICmdMgr &rCmdMgr = CMICmdMgr::Instance();
1010   return rCmdMgr.CmdExecute(vCmdData);
1011 }
1012
1013 //++
1014 //------------------------------------------------------------------------------------
1015 // Details: Set the MI Driver's exit application flag. The application checks
1016 // this flag
1017 //          after every stdin line is read so the exit may not be instantaneous.
1018 //          If vbForceExit is false the MI Driver queries its state and
1019 //          determines if is
1020 //          should exit or continue operating depending on that running state.
1021 //          This is related to the running state of the MI driver.
1022 // Type:    Overridden.
1023 // Args:    None.
1024 // Return:  None.
1025 // Throws:  None.
1026 //--
1027 void CMIDriver::SetExitApplicationFlag(const bool vbForceExit) {
1028   if (vbForceExit) {
1029     CMIUtilThreadLock lock(m_threadMutex);
1030     m_bExitApp = true;
1031     return;
1032   }
1033
1034   // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1035   // Did we receive a SIGINT from the client during a running debug program, if
1036   // so then SIGINT is not to be taken as meaning kill the MI driver application
1037   // but halt the inferior program being debugged instead
1038   if (m_eCurrentDriverState == eDriverState_RunningDebugging) {
1039     InterpretCommand("-exec-interrupt");
1040     return;
1041   }
1042
1043   m_bExitApp = true;
1044 }
1045
1046 //++
1047 //------------------------------------------------------------------------------------
1048 // Details: Get the  MI Driver's exit exit application flag.
1049 //          This is related to the running state of the MI driver.
1050 // Type:    Method.
1051 // Args:    None.
1052 // Return:  bool    - True = MI Driver is shutting down, false = MI driver is
1053 // running.
1054 // Throws:  None.
1055 //--
1056 bool CMIDriver::GetExitApplicationFlag() const { return m_bExitApp; }
1057
1058 //++
1059 //------------------------------------------------------------------------------------
1060 // Details: Get the current running state of the MI Driver.
1061 // Type:    Method.
1062 // Args:    None.
1063 // Return:  DriverState_e   - The current running state of the application.
1064 // Throws:  None.
1065 //--
1066 CMIDriver::DriverState_e CMIDriver::GetCurrentDriverState() const {
1067   return m_eCurrentDriverState;
1068 }
1069
1070 //++
1071 //------------------------------------------------------------------------------------
1072 // Details: Set the current running state of the MI Driver to running and
1073 // currently not in
1074 //          a debug session.
1075 // Type:    Method.
1076 // Return:  MIstatus::success - Functionality succeeded.
1077 //          MIstatus::failure - Functionality failed.
1078 // Return:  DriverState_e   - The current running state of the application.
1079 // Throws:  None.
1080 //--
1081 bool CMIDriver::SetDriverStateRunningNotDebugging() {
1082   // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1083
1084   if (m_eCurrentDriverState == eDriverState_RunningNotDebugging)
1085     return MIstatus::success;
1086
1087   // Driver cannot be in the following states to set
1088   // eDriverState_RunningNotDebugging
1089   switch (m_eCurrentDriverState) {
1090   case eDriverState_NotRunning:
1091   case eDriverState_Initialising:
1092   case eDriverState_ShuttingDown: {
1093     SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1094     return MIstatus::failure;
1095   }
1096   case eDriverState_RunningDebugging:
1097   case eDriverState_RunningNotDebugging:
1098     break;
1099   case eDriverState_count:
1100     SetErrorDescription(
1101         CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE),
1102                               "SetDriverStateRunningNotDebugging()"));
1103     return MIstatus::failure;
1104   }
1105
1106   // Driver must be in this state to set eDriverState_RunningNotDebugging
1107   if (m_eCurrentDriverState != eDriverState_RunningDebugging) {
1108     SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1109     return MIstatus::failure;
1110   }
1111
1112   m_eCurrentDriverState = eDriverState_RunningNotDebugging;
1113
1114   return MIstatus::success;
1115 }
1116
1117 //++
1118 //------------------------------------------------------------------------------------
1119 // Details: Set the current running state of the MI Driver to running and
1120 // currently not in
1121 //          a debug session. The driver's state must in the state running and in
1122 //          a
1123 //          debug session to set this new state.
1124 // Type:    Method.
1125 // Return:  MIstatus::success - Functionality succeeded.
1126 //          MIstatus::failure - Functionality failed.
1127 // Return:  DriverState_e   - The current running state of the application.
1128 // Throws:  None.
1129 //--
1130 bool CMIDriver::SetDriverStateRunningDebugging() {
1131   // CODETAG_DEBUG_SESSION_RUNNING_PROG_RECEIVED_SIGINT_PAUSE_PROGRAM
1132
1133   if (m_eCurrentDriverState == eDriverState_RunningDebugging)
1134     return MIstatus::success;
1135
1136   // Driver cannot be in the following states to set
1137   // eDriverState_RunningDebugging
1138   switch (m_eCurrentDriverState) {
1139   case eDriverState_NotRunning:
1140   case eDriverState_Initialising:
1141   case eDriverState_ShuttingDown: {
1142     SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1143     return MIstatus::failure;
1144   }
1145   case eDriverState_RunningDebugging:
1146   case eDriverState_RunningNotDebugging:
1147     break;
1148   case eDriverState_count:
1149     SetErrorDescription(
1150         CMIUtilString::Format(MIRSRC(IDS_CODE_ERR_INVALID_ENUMERATION_VALUE),
1151                               "SetDriverStateRunningDebugging()"));
1152     return MIstatus::failure;
1153   }
1154
1155   // Driver must be in this state to set eDriverState_RunningDebugging
1156   if (m_eCurrentDriverState != eDriverState_RunningNotDebugging) {
1157     SetErrorDescription(MIRSRC(IDS_DRIVER_ERR_DRIVER_STATE_ERROR));
1158     return MIstatus::failure;
1159   }
1160
1161   m_eCurrentDriverState = eDriverState_RunningDebugging;
1162
1163   return MIstatus::success;
1164 }
1165
1166 //++
1167 //------------------------------------------------------------------------------------
1168 // Details: Prepare the client IDE so it will start working/communicating with
1169 // *this MI
1170 //          driver.
1171 // Type:    Method.
1172 // Args:    None.
1173 // Return:  MIstatus::success - Functionality succeeded.
1174 //          MIstatus::failure - Functionality failed.
1175 // Throws:  None.
1176 //--
1177 bool CMIDriver::InitClientIDEToMIDriver() const {
1178   // Put other IDE init functions here
1179   return InitClientIDEEclipse();
1180 }
1181
1182 //++
1183 //------------------------------------------------------------------------------------
1184 // Details: The IDE Eclipse when debugging locally expects "(gdb)\n" character
1185 //          sequence otherwise it refuses to communicate and times out. This
1186 //          should be
1187 //          sent to Eclipse before anything else.
1188 // Type:    Method.
1189 // Args:    None.
1190 // Return:  MIstatus::success - Functionality succeeded.
1191 //          MIstatus::failure - Functionality failed.
1192 // Throws:  None.
1193 //--
1194 bool CMIDriver::InitClientIDEEclipse() const {
1195   return CMICmnStreamStdout::WritePrompt();
1196 }
1197
1198 //++
1199 //------------------------------------------------------------------------------------
1200 // Details: Ask *this driver whether it found an executable in the MI Driver's
1201 // list of
1202 //          arguments which to open and debug. If so instigate commands to set
1203 //          up a debug
1204 //          session for that executable.
1205 // Type:    Method.
1206 // Args:    None.
1207 // Return:  bool - True = True = Yes executable given as one of the parameters
1208 // to the MI
1209 //                 Driver.
1210 //                 False = not found.
1211 // Throws:  None.
1212 //--
1213 bool CMIDriver::HaveExecutableFileNamePathOnCmdLine() const {
1214   return m_bHaveExecutableFileNamePathOnCmdLine;
1215 }
1216
1217 //++
1218 //------------------------------------------------------------------------------------
1219 // Details: Retrieve from *this driver executable file name path to start a
1220 // debug session
1221 //          with (if present see HaveExecutableFileNamePathOnCmdLine()).
1222 // Type:    Method.
1223 // Args:    None.
1224 // Return:  CMIUtilString & - Executeable file name path or empty string.
1225 // Throws:  None.
1226 //--
1227 const CMIUtilString &CMIDriver::GetExecutableFileNamePathOnCmdLine() const {
1228   return m_strCmdLineArgExecuteableFileNamePath;
1229 }
1230
1231 //++
1232 //------------------------------------------------------------------------------------
1233 // Details: Execute commands (by injecting them into the stdin line queue
1234 // container) and
1235 //          other code to set up the MI Driver such that is can take the
1236 //          executable
1237 //          argument passed on the command and create a debug session for it.
1238 // Type:    Method.
1239 // Args:    None.
1240 // Return:  MIstatus::success - Functionality succeeded.
1241 //          MIstatus::failure - Functionality failed.
1242 // Throws:  None.
1243 //--
1244 bool CMIDriver::LocalDebugSessionStartupExecuteCommands() {
1245   const CMIUtilString strCmd(CMIUtilString::Format(
1246       "-file-exec-and-symbols \"%s\"",
1247       m_strCmdLineArgExecuteableFileNamePath.AddSlashes().c_str()));
1248   bool bOk = CMICmnStreamStdout::TextToStdout(strCmd);
1249   bOk = bOk && InterpretCommand(strCmd);
1250   bOk = bOk && CMICmnStreamStdout::WritePrompt();
1251   return bOk;
1252 }
1253
1254 //++
1255 //------------------------------------------------------------------------------------
1256 // Details: Set the MI Driver into "its debugging an executable passed as an
1257 // argument"
1258 //          mode as against running via a client like Eclipse.
1259 // Type:    Method.
1260 // Args:    None.
1261 // Return:  None.
1262 // Throws:  None.
1263 //--
1264 void CMIDriver::SetDriverDebuggingArgExecutable() {
1265   m_bDriverDebuggingArgExecutable = true;
1266 }
1267
1268 //++
1269 //------------------------------------------------------------------------------------
1270 // Details: Retrieve the MI Driver state indicating if it is operating in "its
1271 // debugging
1272 //          an executable passed as an argument" mode as against running via a
1273 //          client
1274 //          like Eclipse.
1275 // Type:    Method.
1276 // Args:    None.
1277 // Return:  None.
1278 // Throws:  None.
1279 //--
1280 bool CMIDriver::IsDriverDebuggingArgExecutable() const {
1281   return m_bDriverDebuggingArgExecutable;
1282 }
1283
1284 //++
1285 //------------------------------------------------------------------------------------
1286 // Details: Execute commands from command source file in specified mode, and
1287 //          set exit-flag if needed.
1288 // Type:    Method.
1289 // Args:    vbAsyncMode       - (R) True = execute commands in asynchronous
1290 // mode, false = otherwise.
1291 // Return:  MIstatus::success - Function succeeded.
1292 //          MIstatus::failure - Function failed.
1293 // Throws:  None.
1294 //--
1295 bool CMIDriver::ExecuteCommandFile(const bool vbAsyncMode) {
1296   std::ifstream ifsStartScript(m_strCmdLineArgCommandFileNamePath.c_str());
1297   if (!ifsStartScript.is_open()) {
1298     const CMIUtilString errMsg(
1299         CMIUtilString::Format(MIRSRC(IDS_UTIL_FILE_ERR_OPENING_FILE_UNKNOWN),
1300                               m_strCmdLineArgCommandFileNamePath.c_str()));
1301     SetErrorDescription(errMsg.c_str());
1302     const bool bForceExit = true;
1303     SetExitApplicationFlag(bForceExit);
1304     return MIstatus::failure;
1305   }
1306
1307   // Switch lldb to synchronous mode
1308   CMICmnLLDBDebugSessionInfo &rSessionInfo(
1309       CMICmnLLDBDebugSessionInfo::Instance());
1310   const bool bAsyncSetting = rSessionInfo.GetDebugger().GetAsync();
1311   rSessionInfo.GetDebugger().SetAsync(vbAsyncMode);
1312
1313   // Execute commands from file
1314   bool bOk = MIstatus::success;
1315   CMIUtilString strCommand;
1316   while (!m_bExitApp && std::getline(ifsStartScript, strCommand)) {
1317     // Print command
1318     bOk = CMICmnStreamStdout::TextToStdout(strCommand);
1319
1320     // Skip if it's a comment or empty line
1321     if (strCommand.empty() || strCommand[0] == '#')
1322       continue;
1323
1324     // Execute if no error
1325     if (bOk) {
1326       CMIUtilThreadLock lock(rSessionInfo.GetSessionMutex());
1327       bOk = InterpretCommand(strCommand);
1328     }
1329
1330     // Draw the prompt after command will be executed (if enabled)
1331     bOk = bOk && CMICmnStreamStdout::WritePrompt();
1332
1333     // Exit if there is an error
1334     if (!bOk) {
1335       const bool bForceExit = true;
1336       SetExitApplicationFlag(bForceExit);
1337       break;
1338     }
1339
1340     // Wait while the handler thread handles incoming events
1341     CMICmnLLDBDebugger::Instance().WaitForHandleEvent();
1342   }
1343
1344   // Switch lldb back to initial mode
1345   rSessionInfo.GetDebugger().SetAsync(bAsyncSetting);
1346
1347   return bOk;
1348 }
1349
1350 //++
1351 //------------------------------------------------------------------------------------
1352 // Details: Gets called when lldb-mi gets a signal. Stops the process if it was
1353 // SIGINT.
1354 //
1355 // Type:    Method.
1356 // Args:    signal that was delivered
1357 // Return:  None.
1358 // Throws:  None.
1359 //--
1360 void CMIDriver::DeliverSignal(int signal) {
1361   if (signal == SIGINT &&
1362       (m_eCurrentDriverState == eDriverState_RunningDebugging))
1363     InterpretCommand("-exec-interrupt");
1364 }