1 //===-- MIDriverMgr.cpp -----------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Third Party Headers:
10 #include "lldb/API/SBError.h"
14 #include "MICmnLogMediumFile.h"
15 #include "MICmnResources.h"
16 #include "MICmnStreamStdout.h"
18 #include "MIDriverMgr.h"
19 #include "MIUtilSingletonHelper.h"
22 // Details: CMIDriverMgr constructor.
28 CMIDriverMgr::CMIDriverMgr() : m_pDriverCurrent(nullptr), m_bInMi2Mode(false) {}
31 // Details: CMIDriverMgr destructor.
37 CMIDriverMgr::~CMIDriverMgr() { Shutdown(); }
40 // Details: Initialize *this manager.
43 // Return: MIstatus::success - Functional succeeded.
44 // MIstatus::failure - Functional failed.
47 bool CMIDriverMgr::Initialize() {
48 m_clientUsageRefCnt++;
50 ClrErrorDescription();
53 return MIstatus::success;
55 bool bOk = MIstatus::success;
58 // Note initialisation order is important here as some resources depend on
60 MI::ModuleInit<CMICmnLog>(IDS_MI_INIT_ERR_LOG, bOk, errMsg);
61 MI::ModuleInit<CMICmnResources>(IDS_MI_INIT_ERR_RESOURCES, bOk, errMsg);
66 CMIUtilString strInitError(CMIUtilString::Format(
67 MIRSRC(IDS_MI_INIT_ERR_DRIVERMGR), errMsg.c_str()));
68 SetErrorDescription(strInitError);
69 return MIstatus::failure;
76 // Details: Unbind detach or release resources used by this server in general
78 // functionality shared between versions of any server interfaces
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.
87 bool CMIDriverMgr::Shutdown() {
88 // Do not want a ref counter because this function needs to be called how ever
90 // application stops running
91 // if( --m_clientUsageRefCnt > 0 )
92 // return MIstatus::success;
94 ClrErrorDescription();
97 return MIstatus::success;
99 m_bInitialized = false;
101 bool bOk = MIstatus::success;
102 CMIUtilString errMsg;
105 UnregisterDriverAll();
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);
112 SetErrorDescriptionn(MIRSRC(IDS_MI_SHTDWN_ERR_DRIVERMGR), errMsg.c_str());
118 // Details: Unregister all the Driver registered with *this manager. The manager
123 // Return: MIstatus::success - Functional succeeded.
124 // MIstatus::failure - Functional failed.
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();
137 m_mapDriverIdToDriver.clear();
138 m_pDriverCurrent = nullptr;
140 return MIstatus::success;
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
148 // the driver's init function which must be successful in order to
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.
158 bool CMIDriverMgr::RegisterDriver(const IDriver &vrDriver,
159 const CMIUtilString &vrDriverID) {
160 if (HaveDriverAlready(vrDriver))
161 return MIstatus::success;
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;
173 MapPairDriverIdToDriver_t pr(vrDriverID, pDriver);
174 m_mapDriverIdToDriver.insert(pr);
176 return MIstatus::success;
180 // Details: Query the Driver Manager to see if *this manager has the driver
184 // Args: vrDriver - (R) The driver to query.
185 // Return: True - registered.
186 // False - not registered.
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)
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
208 // the work previously.
210 // Args: vrDriver - (R) The driver to unregister.
211 // Return: MIstatus::success - Functional succeeded.
212 // MIstatus::failure - Functional failed.
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)
226 m_mapDriverIdToDriver.erase(it);
228 if (m_pDriverCurrent == pDrvr)
229 m_pDriverCurrent = nullptr;
231 return MIstatus::success;
235 // Details: Specify the driver to do work. The Driver Manager drives this
237 // previous driver doing work is not called anymore (so be sure the
239 // driver is in a tidy state before stopping it working).
241 // Args: vrADriver - (R) A lldb::SBBroadcaster/IDriver derived object.
242 // Return: MIstatus::success - Functional succeeded.
243 // MIstatus::failure - Functional failed.
246 bool CMIDriverMgr::SetUseThisDriverToDoWork(const IDriver &vrADriver) {
247 m_pDriverCurrent = const_cast<IDriver *>(&vrADriver);
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);
254 m_bInMi2Mode = m_pDriverCurrent->GetDriverIsGDBMICompatibleDriver();
256 return MIstatus::success;
260 // Details: Ask *this manager which driver is currently doing the work.
263 // Return: IDriver * - Pointer to a driver, NULL if there is no current working
267 CMIDriverMgr::IDriver *CMIDriverMgr::GetUseThisDriverToDoWork() const {
268 return m_pDriverCurrent;
272 // Details: Call this function puts *this driver to work.
275 // Return: MIstatus::success - Functional succeeded.
276 // MIstatus::failure - Functional failed.
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;
289 const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
290 CMICmnStreamStdout::Instance().Write(errMsg, true);
291 return MIstatus::failure;
294 return MIstatus::success;
298 // Details: Get the current driver to validate executable command line
301 // Args: argc - (R) An integer that contains the count of arguments
303 // argv. The argc parameter is always greater than
305 // argv - (R) An array of null-terminated strings representing
307 // arguments entered by the user of the program. By
309 // argv[0] is the command with which the program is
311 // vpStdOut - (R) Point to a standard output stream.
312 // vwbExiting - (W) True = *this want to exit, false = continue to
314 // Return: MIstatus::success - Functional succeeded.
315 // MIstatus::failure - Functional failed.
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;
326 const lldb::SBError error(
327 m_pDriverCurrent->DoParseArgs(argc, argv, vpStdOut, vwbExiting));
328 bool bOk = !error.Fail();
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(),
337 errMsg = CMIUtilString::Format(MIRSRC(IDS_DRIVER_ERR_PARSE_ARGS_UNKNOWN),
338 m_pDriverCurrent->GetName().c_str());
340 bOk = CMICmnStreamStdout::Instance().Write(errMsg, true);
347 // Details: Retrieve the current driver's last error condition.
350 // Return: CMIUtilString - Text description.
353 CMIUtilString CMIDriverMgr::DriverGetError() const {
354 if (m_pDriverCurrent != nullptr)
355 return m_pDriverCurrent->GetError();
357 const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
358 CMICmnStreamStdout::Instance().Write(errMsg, true);
361 return CMIUtilString();
365 // Details: Retrieve the current driver's name.
368 // Return: CMIUtilString - Driver name.
369 // Empty string = no current working driver specified.
372 CMIUtilString CMIDriverMgr::DriverGetName() const {
373 if (m_pDriverCurrent != nullptr)
374 return m_pDriverCurrent->GetName();
376 const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
377 CMICmnStreamStdout::Instance().Write(errMsg, true);
380 return CMIUtilString();
384 // Details: Retrieve the current driver's debugger object.
387 // Return: lldb::SBDebugger * - Ptr to driver's debugger object.
388 // - NULL = no current working driver specified.
391 lldb::SBDebugger *CMIDriverMgr::DriverGetTheDebugger() {
392 lldb::SBDebugger *pDebugger = nullptr;
393 if (m_pDriverCurrent != nullptr)
394 pDebugger = &m_pDriverCurrent->GetTheDebugger();
396 const CMIUtilString errMsg(MIRSRC(IDS_DRIVER_ERR_CURRENT_NOT_SET));
397 CMICmnStreamStdout::Instance().Write(errMsg, true);
404 // Details: Check the arguments given on the command line. The main purpose of
406 // function is to check for the presence of the --interpreter option.
408 // this option present tells *this manager to set the CMIDriver to do
410 // not use the LLDB driver. The following are options that are only
412 // the CMIDriverMgr are:
420 // The above arguments are not handled by any driver object except for
422 // The options --interpreter and --executable in code act very similar.
424 // --executable is necessary to differentiate whither the MI Driver is
426 // by a client i.e. Eclipse or from the command line. Eclipse issues
428 // --interpreter and also passes additional arguments which can be
430 // executable if called from the command line. Using --executable tells
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
436 // debug session. Using --interpreter on the command line does not
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.
442 // Args: argc - (R) An integer that contains the count of arguments
444 // argv. The argc parameter is always greater than
446 // argv - (R) An array of null-terminated strings representing
448 // arguments entered by the user of the program. By
450 // argv[0] is the command with which the program is
452 // vwbExiting - (W) True = *this want to exit, Reasons: help,
454 // version information only.
455 // False = Continue to work, start debugger i.e.
458 // Return: lldb::SBError - LLDB current error status.
461 bool CMIDriverMgr::ParseArgs(const int argc, const char *argv[],
463 bool bOk = MIstatus::success;
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);
472 // Print application arguments to the Log file
473 const bool bHaveArgs(argc >= 2);
474 CMIUtilString strArgs(MIRSRC(IDS_MI_APP_ARGS));
476 strArgs += MIRSRC(IDS_WORD_NONE);
477 bOk = bOk && m_pLog->Write(strArgs, CMICmnLog::eLogVerbosity_Log);
479 for (MIint i = 1; i < argc; i++) {
480 strArgs += CMIUtilString::Format("%d:'%s' ", i,
481 CMIUtilString::WithNullAsEmpty(argv[i]));
483 bOk = bOk && m_pLog->Write(strArgs, CMICmnLog::eLogVerbosity_Log);
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;
495 bHaveArgInterpret = true;
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]);
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;
510 if ("--version" == strArg) {
511 bHaveArgVersion = true;
513 if ("--versionLong" == strArg) {
514 bHaveArgVersionLong = true;
516 if ("--log" == strArg) {
519 if (0 == strArg.compare(0, 10, "--log-dir=")) {
520 strLogDir = strArg.substr(10, CMIUtilString::npos);
521 bHaveArgLogDir = true;
523 if (("--help" == strArg) || ("-h" == strArg)) {
530 CMICmnLog::Instance().SetEnabled(true);
533 if (bHaveArgLogDir) {
534 bOk = bOk && CMICmnLogMediumFile::Instance().SetDirectory(strLogDir);
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) {
545 CMICmnStreamStdout::Instance().WriteMIResponse(
546 MIRSRC(IDE_MI_VERSION_GDB));
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) {
555 bOk && CMICmnStreamStdout::Instance().WriteMIResponse(GetAppVersion());
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) {
564 CMICmnStreamStdout::Instance().WriteMIResponse(
565 GetHelpOnCmdLineArgOptions());
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);
583 const CMIUtilString msg(MIRSRC(IDS_DRIVER_ERR_NON_REGISTERED));
584 bOk = bOk && CMICmnStreamStdout::Instance().WriteMIResponse(msg);
592 // Details: Return formatted application version and name information.
595 // Return: CMIUtilString - Text data.
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()));
609 // Details: Return formatted help information on all the MI command line
613 // Return: CMIUtilString - Text data.
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++) {
640 // Details: Search the registered drivers and return the first driver which says
642 // GDB/MI compatible i.e. the CMIDriver class.
645 // Return: IDriver * - Ptr to driver, NULL = no driver found.
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;
654 IDriver *pDvr = (*it).second;
655 if (pDvr->GetDriverIsGDBMICompatibleDriver()) {
668 // Details: Search the registered drivers and return the first driver which says
670 // not GDB/MI compatible i.e. the LLDB Driver class.
673 // Return: IDriver * - Ptr to driver, NULL = no driver found.
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;
682 IDriver *pDvr = (*it).second;
683 if (!pDvr->GetDriverIsGDBMICompatibleDriver()) {
696 // Details: Search the registered drivers and return driver with the specified
699 // Args: vrDriverId - (R) ID of a driver.
700 // Return: IDriver * - Ptr to driver, NULL = no driver found.
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())
710 IDriver *pDriver = (*it).second;
716 // Details: Gets called when lldb-mi gets a signal. Passed signal to current
720 // Args: signal that was delivered
724 void CMIDriverMgr::DeliverSignal(int signal) {
725 if (m_pDriverCurrent != nullptr)
726 m_pDriverCurrent->DeliverSignal(signal);