/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Core/Debugger.h
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- Debugger.h ----------------------------------------------*- 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 | | #ifndef LLDB_CORE_DEBUGGER_H |
10 | | #define LLDB_CORE_DEBUGGER_H |
11 | | |
12 | | #include <cstdint> |
13 | | |
14 | | #include <memory> |
15 | | #include <optional> |
16 | | #include <vector> |
17 | | |
18 | | #include "lldb/Core/DebuggerEvents.h" |
19 | | #include "lldb/Core/FormatEntity.h" |
20 | | #include "lldb/Core/IOHandler.h" |
21 | | #include "lldb/Core/SourceManager.h" |
22 | | #include "lldb/Core/UserSettingsController.h" |
23 | | #include "lldb/Host/HostThread.h" |
24 | | #include "lldb/Host/StreamFile.h" |
25 | | #include "lldb/Host/Terminal.h" |
26 | | #include "lldb/Target/ExecutionContext.h" |
27 | | #include "lldb/Target/Platform.h" |
28 | | #include "lldb/Target/TargetList.h" |
29 | | #include "lldb/Utility/Broadcaster.h" |
30 | | #include "lldb/Utility/ConstString.h" |
31 | | #include "lldb/Utility/Diagnostics.h" |
32 | | #include "lldb/Utility/FileSpec.h" |
33 | | #include "lldb/Utility/Status.h" |
34 | | #include "lldb/Utility/UserID.h" |
35 | | #include "lldb/lldb-defines.h" |
36 | | #include "lldb/lldb-enumerations.h" |
37 | | #include "lldb/lldb-forward.h" |
38 | | #include "lldb/lldb-private-enumerations.h" |
39 | | #include "lldb/lldb-private-types.h" |
40 | | #include "lldb/lldb-types.h" |
41 | | |
42 | | #include "llvm/ADT/ArrayRef.h" |
43 | | #include "llvm/ADT/StringMap.h" |
44 | | #include "llvm/ADT/StringRef.h" |
45 | | #include "llvm/Support/DynamicLibrary.h" |
46 | | #include "llvm/Support/FormatVariadic.h" |
47 | | #include "llvm/Support/Threading.h" |
48 | | |
49 | | #include <cassert> |
50 | | #include <cstddef> |
51 | | #include <cstdio> |
52 | | |
53 | | namespace llvm { |
54 | | class raw_ostream; |
55 | | class ThreadPool; |
56 | | } // namespace llvm |
57 | | |
58 | | namespace lldb_private { |
59 | | class Address; |
60 | | class CallbackLogHandler; |
61 | | class CommandInterpreter; |
62 | | class LogHandler; |
63 | | class Process; |
64 | | class Stream; |
65 | | class SymbolContext; |
66 | | class Target; |
67 | | |
68 | | namespace repro { |
69 | | class DataRecorder; |
70 | | } |
71 | | |
72 | | /// \class Debugger Debugger.h "lldb/Core/Debugger.h" |
73 | | /// A class to manage flag bits. |
74 | | /// |
75 | | /// Provides a global root objects for the debugger core. |
76 | | |
77 | | class Debugger : public std::enable_shared_from_this<Debugger>, |
78 | | public UserID, |
79 | | public Properties { |
80 | | public: |
81 | | /// Broadcaster event bits definitions. |
82 | | enum { |
83 | | eBroadcastBitProgress = (1 << 0), |
84 | | eBroadcastBitWarning = (1 << 1), |
85 | | eBroadcastBitError = (1 << 2), |
86 | | eBroadcastSymbolChange = (1 << 3), |
87 | | }; |
88 | | |
89 | | using DebuggerList = std::vector<lldb::DebuggerSP>; |
90 | | |
91 | | static ConstString GetStaticBroadcasterClass(); |
92 | | |
93 | | /// Get the public broadcaster for this debugger. |
94 | 538k | Broadcaster &GetBroadcaster() { return m_broadcaster; } |
95 | 0 | const Broadcaster &GetBroadcaster() const { return m_broadcaster; } |
96 | | |
97 | | ~Debugger() override; |
98 | | |
99 | | static lldb::DebuggerSP |
100 | | CreateInstance(lldb::LogOutputCallback log_callback = nullptr, |
101 | | void *baton = nullptr); |
102 | | |
103 | | static lldb::TargetSP FindTargetWithProcessID(lldb::pid_t pid); |
104 | | |
105 | | static lldb::TargetSP FindTargetWithProcess(Process *process); |
106 | | |
107 | | static void Initialize(LoadPluginCallbackType load_plugin_callback); |
108 | | |
109 | | static void Terminate(); |
110 | | |
111 | | static void SettingsInitialize(); |
112 | | |
113 | | static void SettingsTerminate(); |
114 | | |
115 | | static void Destroy(lldb::DebuggerSP &debugger_sp); |
116 | | |
117 | | static lldb::DebuggerSP FindDebuggerWithID(lldb::user_id_t id); |
118 | | |
119 | | static lldb::DebuggerSP |
120 | | FindDebuggerWithInstanceName(llvm::StringRef instance_name); |
121 | | |
122 | | static size_t GetNumDebuggers(); |
123 | | |
124 | | static lldb::DebuggerSP GetDebuggerAtIndex(size_t index); |
125 | | |
126 | | static bool FormatDisassemblerAddress(const FormatEntity::Entry *format, |
127 | | const SymbolContext *sc, |
128 | | const SymbolContext *prev_sc, |
129 | | const ExecutionContext *exe_ctx, |
130 | | const Address *addr, Stream &s); |
131 | | |
132 | | static void AssertCallback(llvm::StringRef message, llvm::StringRef backtrace, |
133 | | llvm::StringRef prompt); |
134 | | |
135 | | void Clear(); |
136 | | |
137 | | bool GetAsyncExecution(); |
138 | | |
139 | | void SetAsyncExecution(bool async); |
140 | | |
141 | 6.03k | lldb::FileSP GetInputFileSP() { return m_input_file_sp; } |
142 | | |
143 | 5.95k | lldb::StreamFileSP GetOutputStreamSP() { return m_output_stream_sp; } |
144 | | |
145 | 5.95k | lldb::StreamFileSP GetErrorStreamSP() { return m_error_stream_sp; } |
146 | | |
147 | 7.04k | File &GetInputFile() { return *m_input_file_sp; } |
148 | | |
149 | 24.9k | File &GetOutputFile() { return m_output_stream_sp->GetFile(); } |
150 | | |
151 | 0 | File &GetErrorFile() { return m_error_stream_sp->GetFile(); } |
152 | | |
153 | 733 | StreamFile &GetOutputStream() { return *m_output_stream_sp; } |
154 | | |
155 | 733 | StreamFile &GetErrorStream() { return *m_error_stream_sp; } |
156 | | |
157 | | repro::DataRecorder *GetInputRecorder(); |
158 | | |
159 | | Status SetInputString(const char *data); |
160 | | |
161 | | void SetInputFile(lldb::FileSP file); |
162 | | |
163 | | void SetOutputFile(lldb::FileSP file); |
164 | | |
165 | | void SetErrorFile(lldb::FileSP file); |
166 | | |
167 | | void SaveInputTerminalState(); |
168 | | |
169 | | void RestoreInputTerminalState(); |
170 | | |
171 | | lldb::StreamSP GetAsyncOutputStream(); |
172 | | |
173 | | lldb::StreamSP GetAsyncErrorStream(); |
174 | | |
175 | 76.0k | CommandInterpreter &GetCommandInterpreter() { |
176 | 76.0k | assert(m_command_interpreter_up.get()); |
177 | 76.0k | return *m_command_interpreter_up; |
178 | 76.0k | } |
179 | | |
180 | | ScriptInterpreter * |
181 | | GetScriptInterpreter(bool can_create = true, |
182 | | std::optional<lldb::ScriptLanguage> language = {}); |
183 | | |
184 | 3.13k | lldb::ListenerSP GetListener() { return m_listener_sp; } |
185 | | |
186 | | // This returns the Debugger's scratch source manager. It won't be able to |
187 | | // look up files in debug information, but it can look up files by absolute |
188 | | // path and display them to you. To get the target's source manager, call |
189 | | // GetSourceManager on the target instead. |
190 | | SourceManager &GetSourceManager(); |
191 | | |
192 | 422k | lldb::TargetSP GetSelectedTarget() { |
193 | 422k | return m_target_list.GetSelectedTarget(); |
194 | 422k | } |
195 | | |
196 | | ExecutionContext GetSelectedExecutionContext(); |
197 | | /// Get accessor for the target list. |
198 | | /// |
199 | | /// The target list is part of the global debugger object. This the single |
200 | | /// debugger shared instance to control where targets get created and to |
201 | | /// allow for tracking and searching for targets based on certain criteria. |
202 | | /// |
203 | | /// \return |
204 | | /// A global shared target list. |
205 | 27.3k | TargetList &GetTargetList() { return m_target_list; } |
206 | | |
207 | 38.2k | PlatformList &GetPlatformList() { return m_platform_list; } |
208 | | |
209 | | void DispatchInputInterrupt(); |
210 | | |
211 | | void DispatchInputEndOfFile(); |
212 | | |
213 | | // If any of the streams are not set, set them to the in/out/err stream of |
214 | | // the top most input reader to ensure they at least have something |
215 | | void AdoptTopIOHandlerFilesIfInvalid(lldb::FileSP &in, |
216 | | lldb::StreamFileSP &out, |
217 | | lldb::StreamFileSP &err); |
218 | | |
219 | | /// Run the given IO handler and return immediately. |
220 | | void RunIOHandlerAsync(const lldb::IOHandlerSP &reader_sp, |
221 | | bool cancel_top_handler = true); |
222 | | |
223 | | /// Run the given IO handler and block until it's complete. |
224 | | void RunIOHandlerSync(const lldb::IOHandlerSP &reader_sp); |
225 | | |
226 | | /// Remove the given IO handler if it's currently active. |
227 | | bool RemoveIOHandler(const lldb::IOHandlerSP &reader_sp); |
228 | | |
229 | | bool IsTopIOHandler(const lldb::IOHandlerSP &reader_sp); |
230 | | |
231 | | bool CheckTopIOHandlerTypes(IOHandler::Type top_type, |
232 | | IOHandler::Type second_top_type); |
233 | | |
234 | | void PrintAsync(const char *s, size_t len, bool is_stdout); |
235 | | |
236 | | llvm::StringRef GetTopIOHandlerControlSequence(char ch); |
237 | | |
238 | | const char *GetIOHandlerCommandPrefix(); |
239 | | |
240 | | const char *GetIOHandlerHelpPrologue(); |
241 | | |
242 | | void ClearIOHandlers(); |
243 | | |
244 | | bool EnableLog(llvm::StringRef channel, |
245 | | llvm::ArrayRef<const char *> categories, |
246 | | llvm::StringRef log_file, uint32_t log_options, |
247 | | size_t buffer_size, LogHandlerKind log_handler_kind, |
248 | | llvm::raw_ostream &error_stream); |
249 | | |
250 | | void SetLoggingCallback(lldb::LogOutputCallback log_callback, void *baton); |
251 | | |
252 | | // Properties Functions |
253 | | enum StopDisassemblyType { |
254 | | eStopDisassemblyTypeNever = 0, |
255 | | eStopDisassemblyTypeNoDebugInfo, |
256 | | eStopDisassemblyTypeNoSource, |
257 | | eStopDisassemblyTypeAlways |
258 | | }; |
259 | | |
260 | | Status SetPropertyValue(const ExecutionContext *exe_ctx, |
261 | | VarSetOperationType op, llvm::StringRef property_path, |
262 | | llvm::StringRef value) override; |
263 | | |
264 | | bool GetAutoConfirm() const; |
265 | | |
266 | | const FormatEntity::Entry *GetDisassemblyFormat() const; |
267 | | |
268 | | const FormatEntity::Entry *GetFrameFormat() const; |
269 | | |
270 | | const FormatEntity::Entry *GetFrameFormatUnique() const; |
271 | | |
272 | | uint64_t GetStopDisassemblyMaxSize() const; |
273 | | |
274 | | const FormatEntity::Entry *GetThreadFormat() const; |
275 | | |
276 | | const FormatEntity::Entry *GetThreadStopFormat() const; |
277 | | |
278 | | lldb::ScriptLanguage GetScriptLanguage() const; |
279 | | |
280 | | bool SetScriptLanguage(lldb::ScriptLanguage script_lang); |
281 | | |
282 | | lldb::LanguageType GetREPLLanguage() const; |
283 | | |
284 | | bool SetREPLLanguage(lldb::LanguageType repl_lang); |
285 | | |
286 | | uint64_t GetTerminalWidth() const; |
287 | | |
288 | | bool SetTerminalWidth(uint64_t term_width); |
289 | | |
290 | | llvm::StringRef GetPrompt() const; |
291 | | |
292 | | llvm::StringRef GetPromptAnsiPrefix() const; |
293 | | |
294 | | llvm::StringRef GetPromptAnsiSuffix() const; |
295 | | |
296 | | void SetPrompt(llvm::StringRef p); |
297 | | void SetPrompt(const char *) = delete; |
298 | | |
299 | | bool GetUseExternalEditor() const; |
300 | | bool SetUseExternalEditor(bool use_external_editor_p); |
301 | | |
302 | | llvm::StringRef GetExternalEditor() const; |
303 | | |
304 | | bool SetExternalEditor(llvm::StringRef editor); |
305 | | |
306 | | bool GetUseColor() const; |
307 | | |
308 | | bool SetUseColor(bool use_color); |
309 | | |
310 | | bool GetShowProgress() const; |
311 | | |
312 | | bool SetShowProgress(bool show_progress); |
313 | | |
314 | | llvm::StringRef GetShowProgressAnsiPrefix() const; |
315 | | |
316 | | llvm::StringRef GetShowProgressAnsiSuffix() const; |
317 | | |
318 | | bool GetUseAutosuggestion() const; |
319 | | |
320 | | llvm::StringRef GetAutosuggestionAnsiPrefix() const; |
321 | | |
322 | | llvm::StringRef GetAutosuggestionAnsiSuffix() const; |
323 | | |
324 | | bool GetShowDontUsePoHint() const; |
325 | | |
326 | | bool GetUseSourceCache() const; |
327 | | |
328 | | bool SetUseSourceCache(bool use_source_cache); |
329 | | |
330 | | bool GetHighlightSource() const; |
331 | | |
332 | | lldb::StopShowColumn GetStopShowColumn() const; |
333 | | |
334 | | llvm::StringRef GetStopShowColumnAnsiPrefix() const; |
335 | | |
336 | | llvm::StringRef GetStopShowColumnAnsiSuffix() const; |
337 | | |
338 | | uint64_t GetStopSourceLineCount(bool before) const; |
339 | | |
340 | | StopDisassemblyType GetStopDisassemblyDisplay() const; |
341 | | |
342 | | uint64_t GetDisassemblyLineCount() const; |
343 | | |
344 | | llvm::StringRef GetStopShowLineMarkerAnsiPrefix() const; |
345 | | |
346 | | llvm::StringRef GetStopShowLineMarkerAnsiSuffix() const; |
347 | | |
348 | | bool GetAutoOneLineSummaries() const; |
349 | | |
350 | | bool GetAutoIndent() const; |
351 | | |
352 | | bool SetAutoIndent(bool b); |
353 | | |
354 | | bool GetPrintDecls() const; |
355 | | |
356 | | bool SetPrintDecls(bool b); |
357 | | |
358 | | uint64_t GetTabSize() const; |
359 | | |
360 | | bool SetTabSize(uint64_t tab_size); |
361 | | |
362 | | lldb::DWIMPrintVerbosity GetDWIMPrintVerbosity() const; |
363 | | |
364 | | bool GetEscapeNonPrintables() const; |
365 | | |
366 | | bool GetNotifyVoid() const; |
367 | | |
368 | 1.82k | const std::string &GetInstanceName() { return m_instance_name; } |
369 | | |
370 | | bool LoadPlugin(const FileSpec &spec, Status &error); |
371 | | |
372 | | void RunIOHandlers(); |
373 | | |
374 | | bool IsForwardingEvents(); |
375 | | |
376 | | void EnableForwardEvents(const lldb::ListenerSP &listener_sp); |
377 | | |
378 | | void CancelForwardEvents(const lldb::ListenerSP &listener_sp); |
379 | | |
380 | 1.85k | bool IsHandlingEvents() const { return m_event_handler_thread.IsJoinable(); } |
381 | | |
382 | | Status RunREPL(lldb::LanguageType language, const char *repl_options); |
383 | | |
384 | | /// Interruption in LLDB: |
385 | | /// |
386 | | /// This is a voluntary interruption mechanism, not preemptive. Parts of lldb |
387 | | /// that do work that can be safely interrupted call |
388 | | /// Debugger::InterruptRequested and if that returns true, they should return |
389 | | /// at a safe point, shortcutting the rest of the work they were to do. |
390 | | /// |
391 | | /// lldb clients can both offer a CommandInterpreter (through |
392 | | /// RunCommandInterpreter) and use the SB API's for their own purposes, so it |
393 | | /// is convenient to separate "interrupting the CommandInterpreter execution" |
394 | | /// and interrupting the work it is doing with the SB API's. So there are two |
395 | | /// ways to cause an interrupt: |
396 | | /// * CommandInterpreter::InterruptCommand: Interrupts the command currently |
397 | | /// running in the command interpreter IOHandler thread |
398 | | /// * Debugger::RequestInterrupt: Interrupts are active on anything but the |
399 | | /// CommandInterpreter thread till CancelInterruptRequest is called. |
400 | | /// |
401 | | /// Since the two checks are mutually exclusive, however, it's also convenient |
402 | | /// to have just one function to check the interrupt state. |
403 | | |
404 | | /// Bump the "interrupt requested" count on the debugger to support |
405 | | /// cooperative interruption. If this is non-zero, InterruptRequested will |
406 | | /// return true. Interruptible operations are expected to query the |
407 | | /// InterruptRequested API periodically, and interrupt what they were doing |
408 | | /// if it returns \b true. |
409 | | /// |
410 | | void RequestInterrupt(); |
411 | | |
412 | | /// Decrement the "interrupt requested" counter. |
413 | | void CancelInterruptRequest(); |
414 | | |
415 | | /// This is the correct way to query the state of Interruption. |
416 | | /// If you are on the RunCommandInterpreter thread, it will check the |
417 | | /// command interpreter state, and if it is on another thread it will |
418 | | /// check the debugger Interrupt Request state. |
419 | | /// \param[in] cur_func |
420 | | /// For reporting if the interruption was requested. Don't provide this by |
421 | | /// hand, use INTERRUPT_REQUESTED so this gets done consistently. |
422 | | /// |
423 | | /// \param[in] formatv |
424 | | /// A formatv string for the interrupt message. If the elements of the |
425 | | /// message are expensive to compute, you can use the no-argument form of |
426 | | /// InterruptRequested, then make up the report using REPORT_INTERRUPTION. |
427 | | /// |
428 | | /// \return |
429 | | /// A boolean value, if \b true an interruptible operation should interrupt |
430 | | /// itself. |
431 | | template <typename... Args> |
432 | | bool InterruptRequested(const char *cur_func, const char *formatv, |
433 | 1.24M | Args &&...args) { |
434 | 1.24M | bool ret_val = InterruptRequested(); |
435 | 1.24M | if (ret_val) { |
436 | 6 | if (!formatv) |
437 | 0 | formatv = "Unknown message"; |
438 | 6 | if (!cur_func) |
439 | 0 | cur_func = "<UNKNOWN>"; |
440 | 6 | ReportInterruption(InterruptionReport( |
441 | 6 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); |
442 | 6 | } |
443 | 1.24M | return ret_val; |
444 | 1.24M | } bool lldb_private::Debugger::InterruptRequested<unsigned long>(char const*, char const*, unsigned long&&) Line | Count | Source | 433 | 2.37k | Args &&...args) { | 434 | 2.37k | bool ret_val = InterruptRequested(); | 435 | 2.37k | if (ret_val) { | 436 | 1 | if (!formatv) | 437 | 0 | formatv = "Unknown message"; | 438 | 1 | if (!cur_func) | 439 | 0 | cur_func = "<UNKNOWN>"; | 440 | 1 | ReportInterruption(InterruptionReport( | 441 | 1 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); | 442 | 1 | } | 443 | 2.37k | return ret_val; | 444 | 2.37k | } |
bool lldb_private::Debugger::InterruptRequested<unsigned long long, unsigned long&>(char const*, char const*, unsigned long long&&, unsigned long&) Line | Count | Source | 433 | 3.27k | Args &&...args) { | 434 | 3.27k | bool ret_val = InterruptRequested(); | 435 | 3.27k | if (ret_val) { | 436 | 0 | if (!formatv) | 437 | 0 | formatv = "Unknown message"; | 438 | 0 | if (!cur_func) | 439 | 0 | cur_func = "<UNKNOWN>"; | 440 | 0 | ReportInterruption(InterruptionReport( | 441 | 0 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); | 442 | 0 | } | 443 | 3.27k | return ret_val; | 444 | 3.27k | } |
bool lldb_private::Debugger::InterruptRequested<>(char const*, char const*) Line | Count | Source | 433 | 1.24M | Args &&...args) { | 434 | 1.24M | bool ret_val = InterruptRequested(); | 435 | 1.24M | if (ret_val) { | 436 | 5 | if (!formatv) | 437 | 0 | formatv = "Unknown message"; | 438 | 5 | if (!cur_func) | 439 | 0 | cur_func = "<UNKNOWN>"; | 440 | 5 | ReportInterruption(InterruptionReport( | 441 | 5 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); | 442 | 5 | } | 443 | 1.24M | return ret_val; | 444 | 1.24M | } |
bool lldb_private::Debugger::InterruptRequested<unsigned int&, unsigned long const&>(char const*, char const*, unsigned int&, unsigned long const&) Line | Count | Source | 433 | 22 | Args &&...args) { | 434 | 22 | bool ret_val = InterruptRequested(); | 435 | 22 | if (ret_val) { | 436 | 0 | if (!formatv) | 437 | 0 | formatv = "Unknown message"; | 438 | 0 | if (!cur_func) | 439 | 0 | cur_func = "<UNKNOWN>"; | 440 | 0 | ReportInterruption(InterruptionReport( | 441 | 0 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); | 442 | 0 | } | 443 | 22 | return ret_val; | 444 | 22 | } |
bool lldb_private::Debugger::InterruptRequested<unsigned long&, unsigned long const&>(char const*, char const*, unsigned long&, unsigned long const&) Line | Count | Source | 433 | 1.26k | Args &&...args) { | 434 | 1.26k | bool ret_val = InterruptRequested(); | 435 | 1.26k | if (ret_val) { | 436 | 0 | if (!formatv) | 437 | 0 | formatv = "Unknown message"; | 438 | 0 | if (!cur_func) | 439 | 0 | cur_func = "<UNKNOWN>"; | 440 | 0 | ReportInterruption(InterruptionReport( | 441 | 0 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); | 442 | 0 | } | 443 | 1.26k | return ret_val; | 444 | 1.26k | } |
bool lldb_private::Debugger::InterruptRequested<unsigned int&, unsigned long&>(char const*, char const*, unsigned int&, unsigned long&) Line | Count | Source | 433 | 50 | Args &&...args) { | 434 | 50 | bool ret_val = InterruptRequested(); | 435 | 50 | if (ret_val) { | 436 | 0 | if (!formatv) | 437 | 0 | formatv = "Unknown message"; | 438 | 0 | if (!cur_func) | 439 | 0 | cur_func = "<UNKNOWN>"; | 440 | 0 | ReportInterruption(InterruptionReport( | 441 | 0 | cur_func, llvm::formatv(formatv, std::forward<Args>(args)...))); | 442 | 0 | } | 443 | 50 | return ret_val; | 444 | 50 | } |
|
445 | | |
446 | | /// This handy define will keep you from having to generate a report for the |
447 | | /// interruption by hand. Use this except in the case where the arguments to |
448 | | /// the message description are expensive to compute. |
449 | | #define INTERRUPT_REQUESTED(debugger, ...) \ |
450 | 1.24M | (debugger).InterruptRequested(__func__, __VA_ARGS__) |
451 | | |
452 | | // This form just queries for whether to interrupt, and does no reporting: |
453 | | bool InterruptRequested(); |
454 | | |
455 | | // FIXME: Do we want to capture a backtrace at the interruption point? |
456 | | class InterruptionReport { |
457 | | public: |
458 | | InterruptionReport(std::string function_name, std::string description) |
459 | | : m_function_name(std::move(function_name)), |
460 | | m_description(std::move(description)), |
461 | | m_interrupt_time(std::chrono::system_clock::now()), |
462 | 0 | m_thread_id(llvm::get_threadid()) {} |
463 | | |
464 | | InterruptionReport(std::string function_name, |
465 | | const llvm::formatv_object_base &payload); |
466 | | |
467 | | template <typename... Args> |
468 | | InterruptionReport(std::string function_name, const char *format, |
469 | | Args &&...args) |
470 | 0 | : InterruptionReport( |
471 | 0 | function_name, |
472 | 0 | llvm::formatv(format, std::forward<Args>(args)...)) {} |
473 | | |
474 | | std::string m_function_name; |
475 | | std::string m_description; |
476 | | const std::chrono::time_point<std::chrono::system_clock> m_interrupt_time; |
477 | | const uint64_t m_thread_id; |
478 | | }; |
479 | | void ReportInterruption(const InterruptionReport &report); |
480 | | #define REPORT_INTERRUPTION(debugger, ...) \ |
481 | 0 | (debugger).ReportInterruption( \ |
482 | 0 | Debugger::InterruptionReport(__func__, __VA_ARGS__)) |
483 | | |
484 | | static DebuggerList DebuggersRequestingInterruption(); |
485 | | |
486 | | public: |
487 | | // This is for use in the command interpreter, when you either want the |
488 | | // selected target, or if no target is present you want to prime the dummy |
489 | | // target with entities that will be copied over to new targets. |
490 | | Target &GetSelectedOrDummyTarget(bool prefer_dummy = false); |
491 | 4.04k | Target &GetDummyTarget() { return *m_dummy_target_sp; } |
492 | | |
493 | 26.6k | lldb::BroadcasterManagerSP GetBroadcasterManager() { |
494 | 26.6k | return m_broadcaster_manager_sp; |
495 | 26.6k | } |
496 | | |
497 | | /// Shared thread poll. Use only with ThreadPoolTaskGroup. |
498 | | static llvm::ThreadPool &GetThreadPool(); |
499 | | |
500 | | /// Report warning events. |
501 | | /// |
502 | | /// Warning events will be delivered to any debuggers that have listeners |
503 | | /// for the eBroadcastBitWarning. |
504 | | /// |
505 | | /// \param[in] message |
506 | | /// The warning message to be reported. |
507 | | /// |
508 | | /// \param [in] debugger_id |
509 | | /// If this optional parameter has a value, it indicates the unique |
510 | | /// debugger identifier that this diagnostic should be delivered to. If |
511 | | /// this optional parameter does not have a value, the diagnostic event |
512 | | /// will be delivered to all debuggers. |
513 | | /// |
514 | | /// \param [in] once |
515 | | /// If a pointer is passed to a std::once_flag, then it will be used to |
516 | | /// ensure the given warning is only broadcast once. |
517 | | static void |
518 | | ReportWarning(std::string message, |
519 | | std::optional<lldb::user_id_t> debugger_id = std::nullopt, |
520 | | std::once_flag *once = nullptr); |
521 | | |
522 | | /// Report error events. |
523 | | /// |
524 | | /// Error events will be delivered to any debuggers that have listeners |
525 | | /// for the eBroadcastBitError. |
526 | | /// |
527 | | /// \param[in] message |
528 | | /// The error message to be reported. |
529 | | /// |
530 | | /// \param [in] debugger_id |
531 | | /// If this optional parameter has a value, it indicates the unique |
532 | | /// debugger identifier that this diagnostic should be delivered to. If |
533 | | /// this optional parameter does not have a value, the diagnostic event |
534 | | /// will be delivered to all debuggers. |
535 | | /// |
536 | | /// \param [in] once |
537 | | /// If a pointer is passed to a std::once_flag, then it will be used to |
538 | | /// ensure the given error is only broadcast once. |
539 | | static void |
540 | | ReportError(std::string message, |
541 | | std::optional<lldb::user_id_t> debugger_id = std::nullopt, |
542 | | std::once_flag *once = nullptr); |
543 | | |
544 | | /// Report info events. |
545 | | /// |
546 | | /// Unlike warning and error events, info events are not broadcast but are |
547 | | /// logged for diagnostic purposes. |
548 | | /// |
549 | | /// \param[in] message |
550 | | /// The info message to be reported. |
551 | | /// |
552 | | /// \param [in] debugger_id |
553 | | /// If this optional parameter has a value, it indicates this diagnostic is |
554 | | /// associated with a unique debugger instance. |
555 | | /// |
556 | | /// \param [in] once |
557 | | /// If a pointer is passed to a std::once_flag, then it will be used to |
558 | | /// ensure the given info is only logged once. |
559 | | static void |
560 | | ReportInfo(std::string message, |
561 | | std::optional<lldb::user_id_t> debugger_id = std::nullopt, |
562 | | std::once_flag *once = nullptr); |
563 | | |
564 | | static void ReportSymbolChange(const ModuleSpec &module_spec); |
565 | | |
566 | | void |
567 | | SetDestroyCallback(lldb_private::DebuggerDestroyCallback destroy_callback, |
568 | | void *baton); |
569 | | |
570 | | /// Manually start the global event handler thread. It is useful to plugins |
571 | | /// that directly use the \a lldb_private namespace and want to use the |
572 | | /// debugger's default event handler thread instead of defining their own. |
573 | | bool StartEventHandlerThread(); |
574 | | |
575 | | /// Manually stop the debugger's default event handler. |
576 | | void StopEventHandlerThread(); |
577 | | |
578 | | /// Force flushing the process's pending stdout and stderr to the debugger's |
579 | | /// asynchronous stdout and stderr streams. |
580 | | void FlushProcessOutput(Process &process, bool flush_stdout, |
581 | | bool flush_stderr); |
582 | | |
583 | 8.63k | SourceManager::SourceFileCache &GetSourceFileCache() { |
584 | 8.63k | return m_source_file_cache; |
585 | 8.63k | } |
586 | | |
587 | | protected: |
588 | | friend class CommandInterpreter; |
589 | | friend class REPL; |
590 | | friend class Progress; |
591 | | |
592 | | /// Report progress events. |
593 | | /// |
594 | | /// Progress events will be delivered to any debuggers that have listeners |
595 | | /// for the eBroadcastBitProgress. This function is called by the |
596 | | /// lldb_private::Progress class to deliver the events to any debuggers that |
597 | | /// qualify. |
598 | | /// |
599 | | /// \param [in] progress_id |
600 | | /// The unique integer identifier for the progress to report. |
601 | | /// |
602 | | /// \param[in] message |
603 | | /// The title of the progress dialog to display in the UI. |
604 | | /// |
605 | | /// \param [in] completed |
606 | | /// The amount of work completed. If \a completed is zero, then this event |
607 | | /// is a progress started event. If \a completed is equal to \a total, then |
608 | | /// this event is a progress end event. Otherwise completed indicates the |
609 | | /// current progress compare to the total value. |
610 | | /// |
611 | | /// \param [in] total |
612 | | /// The total amount of work units that need to be completed. If this value |
613 | | /// is UINT64_MAX, then an indeterminate progress indicator should be |
614 | | /// displayed. |
615 | | /// |
616 | | /// \param [in] debugger_id |
617 | | /// If this optional parameter has a value, it indicates the unique |
618 | | /// debugger identifier that this progress should be delivered to. If this |
619 | | /// optional parameter does not have a value, the progress will be |
620 | | /// delivered to all debuggers. |
621 | | static void ReportProgress(uint64_t progress_id, std::string title, |
622 | | std::string details, uint64_t completed, |
623 | | uint64_t total, |
624 | | std::optional<lldb::user_id_t> debugger_id); |
625 | | |
626 | | static void ReportDiagnosticImpl(DiagnosticEventData::Type type, |
627 | | std::string message, |
628 | | std::optional<lldb::user_id_t> debugger_id, |
629 | | std::once_flag *once); |
630 | | |
631 | | void HandleDestroyCallback(); |
632 | | |
633 | | void PrintProgress(const ProgressEventData &data); |
634 | | |
635 | | void PushIOHandler(const lldb::IOHandlerSP &reader_sp, |
636 | | bool cancel_top_handler = true); |
637 | | |
638 | | bool PopIOHandler(const lldb::IOHandlerSP &reader_sp); |
639 | | |
640 | | bool HasIOHandlerThread() const; |
641 | | |
642 | | bool StartIOHandlerThread(); |
643 | | |
644 | | void StopIOHandlerThread(); |
645 | | |
646 | | // Sets the IOHandler thread to the new_thread, and returns |
647 | | // the previous IOHandler thread. |
648 | | HostThread SetIOHandlerThread(HostThread &new_thread); |
649 | | |
650 | | void JoinIOHandlerThread(); |
651 | | |
652 | | bool IsIOHandlerThreadCurrentThread() const; |
653 | | |
654 | | lldb::thread_result_t IOHandlerThread(); |
655 | | |
656 | | lldb::thread_result_t DefaultEventHandler(); |
657 | | |
658 | | void HandleBreakpointEvent(const lldb::EventSP &event_sp); |
659 | | |
660 | | void HandleProcessEvent(const lldb::EventSP &event_sp); |
661 | | |
662 | | void HandleThreadEvent(const lldb::EventSP &event_sp); |
663 | | |
664 | | void HandleProgressEvent(const lldb::EventSP &event_sp); |
665 | | |
666 | | void HandleDiagnosticEvent(const lldb::EventSP &event_sp); |
667 | | |
668 | | // Ensures two threads don't attempt to flush process output in parallel. |
669 | | std::mutex m_output_flush_mutex; |
670 | | |
671 | | void InstanceInitialize(); |
672 | | |
673 | | // these should never be NULL |
674 | | lldb::FileSP m_input_file_sp; |
675 | | lldb::StreamFileSP m_output_stream_sp; |
676 | | lldb::StreamFileSP m_error_stream_sp; |
677 | | |
678 | | /// Used for shadowing the input file when capturing a reproducer. |
679 | | repro::DataRecorder *m_input_recorder; |
680 | | |
681 | | lldb::BroadcasterManagerSP m_broadcaster_manager_sp; // The debugger acts as a |
682 | | // broadcaster manager of |
683 | | // last resort. |
684 | | // It needs to get constructed before the target_list or any other member |
685 | | // that might want to broadcast through the debugger. |
686 | | |
687 | | TerminalState m_terminal_state; |
688 | | TargetList m_target_list; |
689 | | |
690 | | PlatformList m_platform_list; |
691 | | lldb::ListenerSP m_listener_sp; |
692 | | std::unique_ptr<SourceManager> m_source_manager_up; // This is a scratch |
693 | | // source manager that we |
694 | | // return if we have no |
695 | | // targets. |
696 | | SourceManager::SourceFileCache m_source_file_cache; // All the source managers |
697 | | // for targets created in |
698 | | // this debugger used this |
699 | | // shared |
700 | | // source file cache. |
701 | | std::unique_ptr<CommandInterpreter> m_command_interpreter_up; |
702 | | |
703 | | std::recursive_mutex m_script_interpreter_mutex; |
704 | | std::array<lldb::ScriptInterpreterSP, lldb::eScriptLanguageUnknown> |
705 | | m_script_interpreters; |
706 | | |
707 | | IOHandlerStack m_io_handler_stack; |
708 | | std::recursive_mutex m_io_handler_synchronous_mutex; |
709 | | |
710 | | std::optional<uint64_t> m_current_event_id; |
711 | | |
712 | | llvm::StringMap<std::weak_ptr<LogHandler>> m_stream_handlers; |
713 | | std::shared_ptr<CallbackLogHandler> m_callback_handler_sp; |
714 | | const std::string m_instance_name; |
715 | | static LoadPluginCallbackType g_load_plugin_callback; |
716 | | typedef std::vector<llvm::sys::DynamicLibrary> LoadedPluginsList; |
717 | | LoadedPluginsList m_loaded_plugins; |
718 | | HostThread m_event_handler_thread; |
719 | | HostThread m_io_handler_thread; |
720 | | Broadcaster m_sync_broadcaster; ///< Private debugger synchronization. |
721 | | Broadcaster m_broadcaster; ///< Public Debugger event broadcaster. |
722 | | lldb::ListenerSP m_forward_listener_sp; |
723 | | llvm::once_flag m_clear_once; |
724 | | lldb::TargetSP m_dummy_target_sp; |
725 | | Diagnostics::CallbackID m_diagnostics_callback_id; |
726 | | |
727 | | lldb_private::DebuggerDestroyCallback m_destroy_callback = nullptr; |
728 | | void *m_destroy_callback_baton = nullptr; |
729 | | |
730 | | uint32_t m_interrupt_requested = 0; ///< Tracks interrupt requests |
731 | | std::mutex m_interrupt_mutex; |
732 | | |
733 | | // Events for m_sync_broadcaster |
734 | | enum { |
735 | | eBroadcastBitEventThreadIsListening = (1 << 0), |
736 | | }; |
737 | | |
738 | | private: |
739 | | // Use Debugger::CreateInstance() to get a shared pointer to a new debugger |
740 | | // object |
741 | | Debugger(lldb::LogOutputCallback m_log_callback, void *baton); |
742 | | |
743 | | Debugger(const Debugger &) = delete; |
744 | | const Debugger &operator=(const Debugger &) = delete; |
745 | | }; |
746 | | |
747 | | } // namespace lldb_private |
748 | | |
749 | | #endif // LLDB_CORE_DEBUGGER_H |