]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/tools/lldb-mi/MIDriverMgr.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / tools / lldb-mi / MIDriverMgr.cpp
1 //===-- MIDriverMgr.cpp -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8
9 // Third Party Headers:
10 #include "lldb/API/SBError.h"
11
12 // In-house headers:
13 #include "MICmnLog.h"
14 #include "MICmnLogMediumFile.h"
15 #include "MICmnResources.h"
16 #include "MICmnStreamStdout.h"
17 #include "MIDriver.h"
18 #include "MIDriverMgr.h"
19 #include "MIUtilSingletonHelper.h"
20
21 //++
22 // Details: CMIDriverMgr constructor.
23 // Type:    Method.
24 // Args:    None.
25 // Return:  None.
26 // Throws:  None.
27 //--
28 CMIDriverMgr::CMIDriverMgr() : m_pDriverCurrent(nullptr), m_bInMi2Mode(false) {}
29
30 //++
31 // Details: CMIDriverMgr destructor.
32 // Type:    Overridden.
33 // Args:    None.
34 // Return:  None.
35 // Throws:  None.
36 //--
37 CMIDriverMgr::~CMIDriverMgr() { Shutdown(); }
38
39 //++
40 // Details: Initialize *this manager.
41 // Type:    Method.
42 // Args:    None.
43 // Return:  MIstatus::success - Functional succeeded.
44 //          MIstatus::failure - Functional failed.
45 // Throws:  None.
46 //--
47 bool CMIDriverMgr::Initialize() {
48   m_clientUsageRefCnt++;
49
50   ClrErrorDescription();
51
52   if (m_bInitialized)
53     return MIstatus::success;
54
55   bool bOk = MIstatus::success;
56   CMIUtilString errMsg;
57
58   // Note initialisation order is important here as some resources depend on
59   // previous
60   MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
61   MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
62
63   m_bInitialized = bOk;
64
65   if (!bOk) {
66     CMIUtilString strInitError(CMIUtilString::Format(
67         MIRSRC(IDS_MI_INIT_ERR_DRIVERMGR), errMsg.c_str()));
68     SetErrorDescription(strInitError);
69     return MIstatus::failure;
70   }
71
72   return bOk;
73 }
74
75 //++
76 // Details: Unbind detach or release resources used by this server in general
77 // common
78 //          functionality shared between versions of any server interfaces
79 //          implemented.
80 // Type:    Method.
81 // Args:    vbAppExitOk - (R) True = No problems, false = App exiting with
82 // problems (investigate!).
83 // Return:  MIstatus::success - Functional succeeded.
84 //          MIstatus::failure - Functional failed.
85 // Throws:  None.
86 //--
87 bool CMIDriverMgr::Shutdown() {
88   // Do not want a ref counter because this function needs to be called how ever
89   // this
90   // application stops running
91   // if( --m_clientUsageRefCnt > 0 )
92   //  return MIstatus::success;
93
94   ClrErrorDescription();
95
96   if (!m_bInitialized)
97     return MIstatus::success;
98
99   m_bInitialized = false;
100
101   bool bOk = MIstatus::success;
102   CMIUtilString errMsg;
103
104   // Tidy up
105   UnregisterDriverAll();
106
107   // Note shutdown order is important here
108   MI::ModuleShutdown<CMICmnResources>(IDE_MI_SHTDWN_ERR_RESOURCES, bOk, errMsg);
109   MI::ModuleShutdown<CMICmnLog>(IDS_MI_SHTDWN_ERR_LOG, bOk, errMsg);
110
111   if (!bOk) {
112     SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_DRIVERMGR), errMsg.c_str());
113   }
114
115   return bOk;
116 }
117 //++
118 // Details: Unregister all the Driver registered with *this manager. The manager
119 // also
120 //          deletes
121 // Type:    Method.
122 // Args:    None.
123 // Return:  MIstatus::success - Functional succeeded.
124 //          MIstatus::failure - Functional failed.
125 // Throws:  None.
126 //--
127 bool CMIDriverMgr::UnregisterDriverAll() {
128   MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
129   while (it != m_mapDriverIdToDriver.end()) {
130     IDriver *pDriver = (*it).second;
131     pDriver->DoShutdown();
132
133     // Next
134     ++it;
135   }
136
137   m_mapDriverIdToDriver.clear();
138   m_pDriverCurrent = nullptr;
139
140   return MIstatus::success;
141 }
142
143 //++
144 // Details: Register a driver with *this Driver Manager. Call
145 // SetUseThisDriverToDoWork()
146 //          inform the manager which driver is the one to the work. The manager
147 //          calls
148 //          the driver's init function which must be successful in order to
149 //          complete the
150 //          registration.
151 // Type:    Method.
152 // Args:    vrDriver    - (R) The driver to register.
153 //          vrDriverID  - (R) The driver's ID to lookup by.
154 // Return:  MIstatus::success - Functional succeeded.
155 //          MIstatus::failure - Functional failed.
156 // Throws:  None.
157 //--
158 bool CMIDriverMgr::RegisterDriver(const IDriver &vrDriver,
159                                   const CMIUtilString &vrDriverID) {
160   if (HaveDriverAlready(vrDriver))
161     return MIstatus::success;
162
163   IDriver *pDriver = const_cast<IDriver *>(&vrDriver);
164   if (!pDriver->SetId(vrDriverID))
165     return MIstatus::failure;
166   if (!pDriver->DoInitialize()) {
167     SetErrorDescriptionn(MIRSRC(IDS_DRIVERMGR_DRIVER_ERR_INIT),
168                          pDriver->GetName().c_str(), vrDriverID.c_str(),
169                          pDriver->GetError().c_str());
170     return MIstatus::failure;
171   }
172
173   MapPairDriverIdToDriver_t pr(vrDriverID, pDriver);
174   m_mapDriverIdToDriver.insert(pr);
175
176   return MIstatus::success;
177 }
178
179 //++
180 // Details: Query the Driver Manager to see if *this manager has the driver
181 // already
182 //          registered.
183 // Type:    Method.
184 // Args:    vrDriver    - (R) The driver to query.
185 // Return:  True - registered.
186 //          False - not registered.
187 // Throws:  None.
188 //--
189 bool CMIDriverMgr::HaveDriverAlready(const IDriver &vrDriver) const {
190   MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
191   while (it != m_mapDriverIdToDriver.end()) {
192     const IDriver *pDrvr = (*it).second;
193     if (pDrvr == &vrDriver)
194       return true;
195
196     // Next
197     ++it;
198   }
199
200   return false;
201 }
202
203 //++
204 // Details: Unregister a driver from the Driver Manager. Call the
205 // SetUseThisDriverToDoWork()
206 //          function to define another driver to do work if the one being
207 //          unregistered did
208 //          the work previously.
209 // Type:    Method.
210 // Args:    vrDriver    - (R) The driver to unregister.
211 // Return:  MIstatus::success - Functional succeeded.
212 //          MIstatus::failure - Functional failed.
213 // Throws:  None.
214 //--
215 bool CMIDriverMgr::UnregisterDriver(const IDriver &vrDriver) {
216   const IDriver *pDrvr = nullptr;
217   MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
218   while (it != m_mapDriverIdToDriver.end()) {
219     pDrvr = (*it).second;
220     if (pDrvr == &vrDriver)
221       break;
222
223     // Next
224     ++it;
225   }
226   m_mapDriverIdToDriver.erase(it);
227
228   if (m_pDriverCurrent == pDrvr)
229     m_pDriverCurrent = nullptr;
230
231   return MIstatus::success;
232 }
233
234 //++
235 // Details: Specify the driver to do work. The Driver Manager drives this
236 // driver. Any
237 //          previous driver doing work is not called anymore (so be sure the
238 //          previous
239 //          driver is in a tidy state before stopping it working).
240 // Type:    Method.
241 // Args:    vrADriver   - (R) A lldb::SBBroadcaster/IDriver derived object.
242 // Return:  MIstatus::success - Functional succeeded.
243 //          MIstatus::failure - Functional failed.
244 // Throws:  None.
245 //--
246 bool CMIDriverMgr::SetUseThisDriverToDoWork(const IDriver &vrADriver) {
247   m_pDriverCurrent = const_cast<IDriver *>(&vrADriver);
248
249   const CMIUtilString msg(
250       CMIUtilString::Format(MIRSRC(IDS_DRIVER_SAY_DRIVER_USING),
251                             m_pDriverCurrent->GetName().c_str()));
252   m_pLog->Write(msg, CMICmnLog::eLogVerbosity_Log);
253
254   m_bInMi2Mode = m_pDriverCurrent->GetDriverIsGDBMICompatibleDriver();
255
256   return MIstatus::success;
257 }
258
259 //++
260 // Details: Ask *this manager which driver is currently doing the work.
261 // Type:    Method.
262 // Args:    None.
263 // Return:  IDriver * - Pointer to a driver, NULL if there is no current working
264 // driver.
265 // Throws:  None.
266 //--
267 CMIDriverMgr::IDriver *CMIDriverMgr::GetUseThisDriverToDoWork() const {
268   return m_pDriverCurrent;
269 }
270
271 //++
272 // Details: Call this function puts *this driver to work.
273 // Type:    Method.
274 // Args:    None.
275 // Return:  MIstatus::success - Functional succeeded.
276 //          MIstatus::failure - Functional failed.
277 // Throws:  None.
278 //--
279 bool CMIDriverMgr::DriverMainLoop() {
280   if (m_pDriverCurrent != nullptr) {
281     if (!m_pDriverCurrent->DoMainLoop()) {
282       const CMIUtilString errMsg(
283           CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_MAINLOOP),
284                                 m_pDriverCurrent->GetError().c_str()));
285       CMICmnStreamStdout::Instance().Write(errMsg, true);
286       return MIstatus::failure;
287     }
288   } else {
289     const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
290     CMICmnStreamStdout::Instance().Write(errMsg, true);
291     return MIstatus::failure;
292   }
293
294   return MIstatus::success;
295 }
296
297 //++
298 // Details: Get the current driver to validate executable command line
299 // arguments.
300 // Type:    Method.
301 // Args:    argc        - (R)   An integer that contains the count of arguments
302 // that follow in
303 //                              argv. The argc parameter is always greater than
304 //                              or equal to 1.
305 //          argv        - (R)   An array of null-terminated strings representing
306 //          command-line
307 //                              arguments entered by the user of the program. By
308 //                              convention,
309 //                              argv[0] is the command with which the program is
310 //                              invoked.
311 //          vpStdOut    - (R)   Point to a standard output stream.
312 //          vwbExiting  - (W)   True = *this want to exit, false = continue to
313 //          work.
314 // Return:  MIstatus::success - Functional succeeded.
315 //          MIstatus::failure - Functional failed.
316 // Throws:  None.
317 //--
318 bool CMIDriverMgr::DriverParseArgs(const int argc, const char *argv[],
319                                    FILE *vpStdOut, bool &vwbExiting) {
320   if (m_pDriverCurrent == nullptr) {
321     const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
322     CMICmnStreamStdout::Instance().Write(errMsg, true);
323     return MIstatus::failure;
324   }
325
326   const lldb::SBError error(
327       m_pDriverCurrent->DoParseArgs(argc, argv, vpStdOut, vwbExiting));
328   bool bOk = !error.Fail();
329   if (!bOk) {
330     CMIUtilString errMsg;
331     const char *pErrorCstr = error.GetCString();
332     if (pErrorCstr != nullptr)
333       errMsg = CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_PARSE_ARGS),
334                                      m_pDriverCurrent->GetName().c_str(),
335                                      pErrorCstr);
336     else
337       errMsg = CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_PARSE_ARGS_UNKNOWN),
338                                      m_pDriverCurrent->GetName().c_str());
339
340     bOk = CMICmnStreamStdout::Instance().Write(errMsg, true);
341   }
342
343   return bOk;
344 }
345
346 //++
347 // Details: Retrieve the current driver's last error condition.
348 // Type:    Method.
349 // Args:    None.
350 // Return:  CMIUtilString - Text description.
351 // Throws:  None.
352 //--
353 CMIUtilString CMIDriverMgr::DriverGetError() const {
354   if (m_pDriverCurrent != nullptr)
355     return m_pDriverCurrent->GetError();
356   else {
357     const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
358     CMICmnStreamStdout::Instance().Write(errMsg, true);
359   }
360
361   return CMIUtilString();
362 }
363
364 //++
365 // Details: Retrieve the current driver's name.
366 // Type:    Method.
367 // Args:    None.
368 // Return:  CMIUtilString - Driver name.
369 //                          Empty string = no current working driver specified.
370 // Throws:  None.
371 //--
372 CMIUtilString CMIDriverMgr::DriverGetName() const {
373   if (m_pDriverCurrent != nullptr)
374     return m_pDriverCurrent->GetName();
375   else {
376     const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
377     CMICmnStreamStdout::Instance().Write(errMsg, true);
378   }
379
380   return CMIUtilString();
381 }
382
383 //++
384 // Details: Retrieve the current driver's debugger object.
385 // Type:    Method.
386 // Args:    None.
387 // Return:  lldb::SBDebugger * - Ptr to driver's debugger object.
388 //                             - NULL = no current working driver specified.
389 // Throws:  None.
390 //--
391 lldb::SBDebugger *CMIDriverMgr::DriverGetTheDebugger() {
392   lldb::SBDebugger *pDebugger = nullptr;
393   if (m_pDriverCurrent != nullptr)
394     pDebugger = &m_pDriverCurrent->GetTheDebugger();
395   else {
396     const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
397     CMICmnStreamStdout::Instance().Write(errMsg, true);
398   }
399
400   return pDebugger;
401 }
402
403 //++
404 // Details: Check the arguments given on the command line. The main purpose of
405 // this
406 //          function is to check for the presence of the --interpreter option.
407 //          Having
408 //          this option present tells *this manager to set the CMIDriver to do
409 //          work. If
410 //          not use the LLDB driver. The following are options that are only
411 //          handled by
412 //          the CMIDriverMgr are:
413 //              --help or -h
414 //              --interpreter
415 //              --version
416 //              --versionLong
417 //              --log
418 //              --executable
419 //              --log-dir
420 //          The above arguments are not handled by any driver object except for
421 //          --executable.
422 //          The options --interpreter and --executable in code act very similar.
423 //          The
424 //          --executable is necessary to differentiate whither the MI Driver is
425 //          being using
426 //          by a client i.e. Eclipse or from the command line. Eclipse issues
427 //          the option
428 //          --interpreter and also passes additional arguments which can be
429 //          interpreted as an
430 //          executable if called from the command line. Using --executable tells
431 //          the MI
432 //          Driver is being called the command line and that the executable
433 //          argument is indeed
434 //          a specified executable an so actions commands to set up the
435 //          executable for a
436 //          debug session. Using --interpreter on the command line does not
437 //          action additional
438 //          commands to initialise a debug session and so be able to launch the
439 //          process. The directory
440 //          where the log file is created is specified using --log-dir.
441 // Type:    Method.
442 // Args:    argc        - (R)   An integer that contains the count of arguments
443 // that follow in
444 //                              argv. The argc parameter is always greater than
445 //                              or equal to 1.
446 //          argv        - (R)   An array of null-terminated strings representing
447 //          command-line
448 //                              arguments entered by the user of the program. By
449 //                              convention,
450 //                              argv[0] is the command with which the program is
451 //                              invoked.
452 //          vwbExiting  - (W)   True = *this want to exit, Reasons: help,
453 //          invalid arg(s),
454 //                              version information only.
455 //                              False = Continue to work, start debugger i.e.
456 //                              Command
457 //                              interpreter.
458 // Return:  lldb::SBError - LLDB current error status.
459 // Throws:  None.
460 //--
461 bool CMIDriverMgr::ParseArgs(const int argc, const char *argv[],
462                              bool &vwbExiting) {
463   bool bOk = MIstatus::success;
464
465   vwbExiting = false;
466
467   // Print MI application path to the Log file
468   const CMIUtilString appPath(
469       CMIUtilString::Format(MIRSRC(IDS_MI_APP_FILEPATHNAME), argv[0]));
470   bOk = m_pLog->Write(appPath, CMICmnLog::eLogVerbosity_Log);
471
472   // Print application arguments to the Log file
473   const bool bHaveArgs(argc >= 2);
474   CMIUtilString strArgs(MIRSRC(IDS_MI_APP_ARGS));
475   if (!bHaveArgs) {
476     strArgs += MIRSRC(IDS_WORD_NONE);
477     bOk = bOk && m_pLog->Write(strArgs, CMICmnLog::eLogVerbosity_Log);
478   } else {
479     for (MIint i = 1; i < argc; i++) {
480       strArgs += CMIUtilString::Format("%d:'%s' ", i,
481                                        CMIUtilString::WithNullAsEmpty(argv[i]));
482     }
483     bOk = bOk && m_pLog->Write(strArgs, CMICmnLog::eLogVerbosity_Log);
484   }
485
486   // Look for the command line options
487   bool bHaveArgInterpret = false;
488   bool bHaveArgVersion = false;
489   bool bHaveArgVersionLong = false;
490   bool bHaveArgLog = false;
491   bool bHaveArgLogDir = false;
492   bool bHaveArgHelp = false;
493   CMIUtilString strLogDir;
494
495   bHaveArgInterpret = true;
496   if (bHaveArgs) {
497     // CODETAG_MIDRIVE_CMD_LINE_ARG_HANDLING
498     for (MIint i = 1; i < argc; i++) {
499       // *** Add args to help in GetHelpOnCmdLineArgOptions() ***
500       const CMIUtilString strArg(argv[i]);
501
502       // Argument "--executable" is also check for in CMIDriver::ParseArgs()
503       if (("--interpreter" == strArg) || // Given by the client such as Eclipse
504           ("--executable" == strArg))    // Used to specify that there
505                                          // is executable argument also
506                                          // on the command line
507       {                                  // See fn description.
508         bHaveArgInterpret = true;
509       }
510       if ("--version" == strArg) {
511         bHaveArgVersion = true;
512       }
513       if ("--versionLong" == strArg) {
514         bHaveArgVersionLong = true;
515       }
516       if ("--log" == strArg) {
517         bHaveArgLog = true;
518       }
519       if (0 == strArg.compare(0, 10, "--log-dir=")) {
520         strLogDir = strArg.substr(10, CMIUtilString::npos);
521         bHaveArgLogDir = true;
522       }
523       if (("--help" == strArg) || ("-h" == strArg)) {
524         bHaveArgHelp = true;
525       }
526     }
527   }
528
529   if (bHaveArgLog) {
530     CMICmnLog::Instance().SetEnabled(true);
531   }
532
533   if (bHaveArgLogDir) {
534     bOk = bOk && CMICmnLogMediumFile::Instance().SetDirectory(strLogDir);
535   }
536
537   // Todo: Remove this output when MI is finished. It is temporary to persuade
538   // Eclipse plugin to work.
539   //       Eclipse reads this literally and will not work unless it gets this
540   //       exact version text.
541   // Handle --version option (ignore the --interpreter option if present)
542   if (bHaveArgVersion) {
543     vwbExiting = true;
544     bOk = bOk &&
545           CMICmnStreamStdout::Instance().WriteMIResponse(
546               MIRSRC(IDE_MI_VERSION_GDB));
547     return bOk;
548   }
549
550   // Todo: Make this the --version when the above --version version is removed
551   // Handle --versionlong option (ignore the --interpreter option if present)
552   if (bHaveArgVersionLong) {
553     vwbExiting = true;
554     bOk =
555         bOk && CMICmnStreamStdout::Instance().WriteMIResponse(GetAppVersion());
556     return bOk;
557   }
558
559   // Both '--help' and '--interpreter' means give help for MI only. Without
560   // '--interpreter' help the LLDB driver is working and so help is for that.
561   if (bHaveArgHelp && bHaveArgInterpret) {
562     vwbExiting = true;
563     bOk = bOk &&
564           CMICmnStreamStdout::Instance().WriteMIResponse(
565               GetHelpOnCmdLineArgOptions());
566     return bOk;
567   }
568
569   // This makes the assumption that there is at least one MI compatible
570   // driver registered and one LLDB driver registered and the CMIDriver
571   // is the first one found.
572   // ToDo: Implement a better solution that handle any order, any number
573   // of drivers. Or this 'feature' may be removed if deemed not required.
574   IDriver *pLldbDriver = GetFirstNonMIDriver();
575   IDriver *pMi2Driver = GetFirstMIDriver();
576   if (bHaveArgInterpret && (pMi2Driver != nullptr))
577     bOk = bOk && SetUseThisDriverToDoWork(*pMi2Driver);
578   else if (pLldbDriver != nullptr)
579     bOk = bOk && SetUseThisDriverToDoWork(*pLldbDriver);
580   else {
581     if (bOk) {
582       vwbExiting = true;
583       const CMIUtilString msg(MIRSRC(IDS_DRIVER_ERR_NON_REGISTERED));
584       bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse(msg);
585     }
586   }
587
588   return bOk;
589 }
590
591 //++
592 // Details: Return formatted application version and name information.
593 // Type:    Method.
594 // Args:    None.
595 // Return:  CMIUtilString - Text data.
596 // Throws:  None.
597 //--
598 CMIUtilString CMIDriverMgr::GetAppVersion() const {
599   const CMIUtilString strProj(MIRSRC(IDS_PROJNAME));
600   const CMIUtilString strVsn(CMIDriver::Instance().GetVersionDescription());
601   const CMIUtilString strGdb(MIRSRC(IDE_MI_VERSION_GDB));
602   const CMIUtilString strVrsnInfo(CMIUtilString::Format(
603       "%s\n%s\n%s", strProj.c_str(), strVsn.c_str(), strGdb.c_str()));
604
605   return strVrsnInfo;
606 }
607
608 //++
609 // Details: Return formatted help information on all the MI command line
610 // options.
611 // Type:    Method.
612 // Args:    None.
613 // Return:  CMIUtilString - Text data.
614 // Throws:  None.
615 //--
616 CMIUtilString CMIDriverMgr::GetHelpOnCmdLineArgOptions() const {
617   const CMIUtilString pHelp[] = {
618       MIRSRC(IDE_MI_APP_DESCRIPTION), MIRSRC(IDE_MI_APP_INFORMATION),
619       MIRSRC(IDE_MI_APP_ARG_USAGE), MIRSRC(IDE_MI_APP_ARG_HELP),
620       MIRSRC(IDE_MI_APP_ARG_VERSION), MIRSRC(IDE_MI_APP_ARG_VERSION_LONG),
621       MIRSRC(IDE_MI_APP_ARG_INTERPRETER), MIRSRC(IDE_MI_APP_ARG_SOURCE),
622       MIRSRC(IDE_MI_APP_ARG_EXECUTEABLE),
623       MIRSRC(IDE_MI_APP_ARG_SYNCHRONOUS),
624       CMIUtilString::Format(
625           MIRSRC(IDE_MI_APP_ARG_APP_LOG),
626           CMICmnLogMediumFile::Instance().GetFileName().c_str()),
627       MIRSRC(IDE_MI_APP_ARG_APP_LOG_DIR), MIRSRC(IDE_MI_APP_ARG_EXECUTABLE),
628       MIRSRC(IDS_CMD_QUIT_HELP), MIRSRC(IDE_MI_APP_ARG_EXAMPLE)};
629   const MIuint nHelpItems = sizeof pHelp / sizeof pHelp[0];
630   CMIUtilString strHelp;
631   for (MIuint i = 0; i < nHelpItems; i++) {
632     strHelp += pHelp[i];
633     strHelp += "\n\n";
634   }
635
636   return strHelp;
637 }
638
639 //++
640 // Details: Search the registered drivers and return the first driver which says
641 // it is
642 //          GDB/MI compatible i.e. the CMIDriver class.
643 // Type:    Method.
644 // Args:    None.
645 // Return:  IDriver * - Ptr to driver, NULL = no driver found.
646 // Throws:  None.
647 //--
648 CMIDriverMgr::IDriver *CMIDriverMgr::GetFirstMIDriver() const {
649   IDriver *pDriver = nullptr;
650   MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
651   while (it != m_mapDriverIdToDriver.end()) {
652     const CMIUtilString &rDrvId = (*it).first;
653     MIunused(rDrvId);
654     IDriver *pDvr = (*it).second;
655     if (pDvr->GetDriverIsGDBMICompatibleDriver()) {
656       pDriver = pDvr;
657       break;
658     }
659
660     // Next
661     ++it;
662   }
663
664   return pDriver;
665 }
666
667 //++
668 // Details: Search the registered drivers and return the first driver which says
669 // it is
670 //          not GDB/MI compatible i.e. the LLDB Driver class.
671 // Type:    Method.
672 // Args:    None.
673 // Return:  IDriver * - Ptr to driver, NULL = no driver found.
674 // Throws:  None.
675 //--
676 CMIDriverMgr::IDriver *CMIDriverMgr::GetFirstNonMIDriver() const {
677   IDriver *pDriver = nullptr;
678   MapDriverIdToDriver_t::const_iterator it = m_mapDriverIdToDriver.begin();
679   while (it != m_mapDriverIdToDriver.end()) {
680     const CMIUtilString &rDrvId = (*it).first;
681     MIunused(rDrvId);
682     IDriver *pDvr = (*it).second;
683     if (!pDvr->GetDriverIsGDBMICompatibleDriver()) {
684       pDriver = pDvr;
685       break;
686     }
687
688     // Next
689     ++it;
690   }
691
692   return pDriver;
693 }
694
695 //++
696 // Details: Search the registered drivers and return driver with the specified
697 // ID.
698 // Type:    Method.
699 // Args:    vrDriverId  - (R) ID of a driver.
700 // Return:  IDriver * - Ptr to driver, NULL = no driver found.
701 // Throws:  None.
702 //--
703 CMIDriverMgr::IDriver *
704 CMIDriverMgr::GetDriver(const CMIUtilString &vrDriverId) const {
705   MapDriverIdToDriver_t::const_iterator it =
706       m_mapDriverIdToDriver.find(vrDriverId);
707   if (it == m_mapDriverIdToDriver.end())
708     return nullptr;
709
710   IDriver *pDriver = (*it).second;
711
712   return pDriver;
713 }
714
715 //++
716 // Details: Gets called when lldb-mi gets a signal. Passed signal to current
717 // driver.
718 //
719 // Type:    Method.
720 // Args:    signal that was delivered
721 // Return:  None.
722 // Throws:  None.
723 //--
724 void CMIDriverMgr::DeliverSignal(int signal) {
725   if (m_pDriverCurrent != nullptr)
726     m_pDriverCurrent->DeliverSignal(signal);
727 }