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