summaryrefslogtreecommitdiff
path: root/tools/lldb-mi/MIDriverMain.cpp
blob: eac14127a16ab8d09a2405d11323652ae20231f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//===-- MIDriverMain.cpp ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

// Overview:    Defines the entry point for the console application.
//              The MI application (project name MI) runs in two modes:
//              An LLDB native driver mode where it acts no different from the
//              LLDB driver.
//              The other mode is the MI when it finds on the command line
//              the --interpreter option. Command line argument --help on its
//              own will give
//              help for the LLDB driver. If entered with --interpreter then MI
//              help will
//              provided.
//              To implement new MI commands derive a new command class from the
//              command base
//              class. To enable the new command for interpretation add the new
//              command class
//              to the command factory. The files of relevance are:
//                  MICmdCommands.cpp
//                  MICmdBase.h / .cpp
//                  MICmdCmd.h / .cpp

// Third party headers:
#include "lldb/API/SBHostOS.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
#include <atomic>
#include <csignal>
#include <stdio.h>

// In house headers:
#include "MICmnConfig.h"
#include "MICmnResources.h"
#include "MICmnStreamStdin.h"
#include "MIDriver.h"
#include "MIDriverMgr.h"
#include "MIUtilDebug.h"
#include "Platform.h"

#if defined(_MSC_VER)
#pragma warning(                                                               \
    once : 4530) // Warning C4530: C++ exception handler used, but unwind
                 // semantics are not enabled. Specify /EHsc
#endif           // _MSC_VER

// CODETAG_IOR_SIGNALS
//++
//------------------------------------------------------------------------------------
// Details: The SIGINT signal is sent to a process by its controlling terminal
// when a
//          user wishes to interrupt the process. This is typically initiated by
//          pressing
//          Control-C, but on some systems, the "delete" character or "break"
//          key can be
//          used.
//          Be aware this function may be called on another thread besides the
//          main thread.
// Type:    Function.
// Args:    vSigno  - (R) Signal number.
// Return:  None.
// Throws:  None.
//--
void sigint_handler(int vSigno) {
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
  signal(SIGINT, sigint_handler);
#endif
  static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
  CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
  lldb::SBDebugger *pDebugger = rDriverMgr.DriverGetTheDebugger();
  if (pDebugger != nullptr) {
    if (!g_interrupt_sent.test_and_set()) {
      pDebugger->DispatchInputInterrupt();
      g_interrupt_sent.clear();
    }
  }

  // Send signal to driver so that it can take suitable action
  rDriverMgr.DeliverSignal(vSigno);
}

//++
//------------------------------------------------------------------------------------
// Details: Init the MI driver system. Initialize the whole driver system which
// includes
//          both the original LLDB driver and the MI driver.
// Type:    Function.
// Args:    None.
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool DriverSystemInit() {
  bool bOk = MIstatus::success;
  CMIDriver &rMIDriver = CMIDriver::Instance();
  CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
  bOk = rDriverMgr.Initialize();

  // Register MIDriver first as it needs to initialize and be ready
  // for the Driver to get information from MIDriver when it initializes
  // (LLDB Driver is registered with the Driver Manager in MI's Initialize())
  bOk = bOk &&
        rDriverMgr.RegisterDriver(rMIDriver, "MIDriver"); // Will be main driver

  return bOk;
}

//++
//------------------------------------------------------------------------------------
// Details: Shutdown the debugger system. Release / terminate resources external
// to
//          specifically the MI driver.
// Type:    Function.
// Args:    vbAppExitOk - (R) True = No problems, false = App exiting with
// problems (investigate!).
// Return:  MIstatus::success - Functional succeeded.
//          MIstatus::failure - Functional failed.
// Throws:  None.
//--
bool DriverSystemShutdown(const bool vbAppExitOk) {
  bool bOk = MIstatus::success;

  // *** Order is important here ***
  CMIDriverMgr::Instance().Shutdown();
  return bOk;
}

//++
//------------------------------------------------------------------------------------
// Details: MI's application start point of execution. The application runs in
// two modes.
//          An LLDB native driver mode where it acts no different from the LLDB
//          driver.
//          The other mode is the MI when it finds on the command line
//          the --interpreter option. Command line argument --help on its own
//          will give
//          help for the LLDB driver. If entered with --interpreter then
//          application
//          help will provided.
// Type:    Method.
// Args:    argc    - (R) An integer that contains the count of arguments that
// follow in
//                        argv. The argc parameter is always greater than or
//                        equal to 1.
//          argv    - (R) An array of null-terminated strings representing
//          command-line
//                        arguments entered by the user of the program. By
//                        convention,
//                        argv[0] is the command with which the program is
//                        invoked.
// Return:  int -  0 =   Normal exit, program success.
//                >0    = Program success with status i.e. Control-C signal
//                status
//                <0    = Program failed.
//              -1      = Program failed reason not specified here, see MI log
//              file.
//              -1000   = Program failed did not initialize successfully.
// Throws:  None.
//--
int main(int argc, char const *argv[]) {
#if MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG
  CMIUtilDebug::WaitForDbgAttachInfinteLoop();
#endif // MICONFIG_DEBUG_SHOW_ATTACH_DBG_DLG

  llvm::StringRef ToolName = argv[0];
  llvm::sys::PrintStackTraceOnErrorSignal(ToolName);
  llvm::PrettyStackTraceProgram X(argc, argv);

  // *** Order is important here ***
  bool bOk = DriverSystemInit();
  if (!bOk) {
    DriverSystemShutdown(bOk);
    return -1000;
  }

  // CODETAG_IOR_SIGNALS
  signal(SIGINT, sigint_handler);

  bool bExiting = false;
  CMIDriverMgr &rDriverMgr = CMIDriverMgr::Instance();
  bOk = bOk && rDriverMgr.ParseArgs(argc, argv, bExiting);
  if (bOk && !bExiting)
    bOk = rDriverMgr.DriverParseArgs(argc, argv, stdout, bExiting);
  if (bOk && !bExiting)
    bOk = rDriverMgr.DriverMainLoop();

  // Logger and other resources shutdown now
  DriverSystemShutdown(bOk);

  const int appResult = bOk ? 0 : -1;

  return appResult;
}