LLDB mainline
IOHandler.h
Go to the documentation of this file.
1//===-- IOHandler.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_IOHANDLER_H
10#define LLDB_CORE_IOHANDLER_H
11
12#include "lldb/Host/Config.h"
14#include "lldb/Utility/Flags.h"
16#include "lldb/Utility/Stream.h"
18#include "lldb/lldb-defines.h"
19#include "lldb/lldb-forward.h"
20#include "llvm/ADT/StringRef.h"
21
22#include <memory>
23#include <mutex>
24#include <optional>
25#include <string>
26#include <vector>
27
28#include <cstdint>
29#include <cstdio>
30
31namespace lldb_private {
32class Debugger;
33} // namespace lldb_private
34
35namespace lldb_private {
36
37class IOHandler {
38public:
52
53 IOHandler(Debugger &debugger, IOHandler::Type type);
54
55 IOHandler(Debugger &debugger, IOHandler::Type type,
56 const lldb::FileSP &input_sp,
57 const lldb::LockableStreamFileSP &output_sp,
58 const lldb::LockableStreamFileSP &error_sp, uint32_t flags);
59
60 virtual ~IOHandler();
61
62 // Each IOHandler gets to run until it is done. It should read data from the
63 // "in" and place output into "out" and "err and return when done.
64 virtual void Run() = 0;
65
66 // Called when an input reader should relinquish its control so another can
67 // be pushed onto the IO handler stack, or so the current IO handler can pop
68 // itself off the stack
69
70 virtual void Cancel() = 0;
71
72 // Called when CTRL+C is pressed which usually causes
73 // Debugger::DispatchInputInterrupt to be called.
74
75 virtual bool Interrupt() = 0;
76
77 virtual void GotEOF() = 0;
78
79 bool IsActive() { return m_active && !m_done; }
80
81 void SetIsDone(bool b) { m_done = b; }
82
83 bool GetIsDone() { return m_done; }
84
85 Type GetType() const { return m_type; }
86
87 virtual void Activate() { m_active = true; }
88
89 virtual void Deactivate() { m_active = false; }
90
91 virtual void TerminalSizeChanged() {}
92
93 virtual void Refresh() {}
94
95 virtual const char *GetPrompt() {
96 // Prompt support isn't mandatory
97 return nullptr;
98 }
99
100 virtual bool SetPrompt(llvm::StringRef prompt) {
101 // Prompt support isn't mandatory
102 return false;
103 }
104
105 virtual bool SetUseColor(bool use_color) {
106 // Color support isn't mandatory.
107 return false;
108 };
109
110 bool SetPrompt(const char *) = delete;
111
112 virtual llvm::StringRef GetControlSequence(char ch) { return {}; }
113
114 virtual const char *GetCommandPrefix() { return nullptr; }
115
116 virtual const char *GetHelpPrologue() { return nullptr; }
117
118 int GetInputFD();
119
120 int GetOutputFD();
121
122 int GetErrorFD();
123
125
127
129
131
132 void *GetUserData() { return m_user_data; }
133
134 void SetUserData(void *user_data) { m_user_data = user_data; }
135
136 Flags &GetFlags() { return m_flags; }
137
138 const Flags &GetFlags() const { return m_flags; }
139
140 /// Check if the input is being supplied interactively by a user
141 ///
142 /// This will return true if the input stream is a terminal (tty or
143 /// pty) and can cause IO handlers to do different things (like
144 /// for a confirmation when deleting all breakpoints).
145 bool GetIsInteractive();
146
147 /// Check if the input is coming from a real terminal.
148 ///
149 /// A real terminal has a valid size with a certain number of rows
150 /// and columns. If this function returns true, then terminal escape
151 /// sequences are expected to work (cursor movement escape sequences,
152 /// clearing lines, etc).
153 bool GetIsRealTerminal();
154
155 void SetPopped(bool b);
156
157 void WaitForPop();
158
159 virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
160
161protected:
170 bool m_done;
172
173private:
174 IOHandler(const IOHandler &) = delete;
175 const IOHandler &operator=(const IOHandler &) = delete;
176};
177
178/// A delegate class for use with IOHandler subclasses.
179///
180/// The IOHandler delegate is designed to be mixed into classes so
181/// they can use an IOHandler subclass to fetch input and notify the
182/// object that inherits from this delegate class when a token is
183/// received.
185public:
187
189 : m_completion(completion) {}
190
191 virtual ~IOHandlerDelegate() = default;
192
193 virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive) {}
194
195 virtual void IOHandlerDeactivated(IOHandler &io_handler) {}
196
197 virtual std::optional<std::string> IOHandlerSuggestion(IOHandler &io_handler,
198 llvm::StringRef line);
199
200 virtual void IOHandlerComplete(IOHandler &io_handler,
201 CompletionRequest &request);
202
203 virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; }
204
205 /// Called when a new line is created or one of an identified set of
206 /// indentation characters is typed.
207 ///
208 /// This function determines how much indentation should be added
209 /// or removed to match the recommended amount for the final line.
210 ///
211 /// \param[in] io_handler
212 /// The IOHandler that responsible for input.
213 ///
214 /// \param[in] lines
215 /// The current input up to the line to be corrected. Lines
216 /// following the line containing the cursor are not included.
217 ///
218 /// \param[in] cursor_position
219 /// The number of characters preceding the cursor on the final
220 /// line at the time.
221 ///
222 /// \return
223 /// Returns an integer describing the number of spaces needed
224 /// to correct the indentation level. Positive values indicate
225 /// that spaces should be added, while negative values represent
226 /// spaces that should be removed.
227 virtual int IOHandlerFixIndentation(IOHandler &io_handler,
228 const StringList &lines,
229 int cursor_position) {
230 return 0;
231 }
232
233 /// Called when a line or lines have been retrieved.
234 ///
235 /// This function can handle the current line and possibly call
236 /// IOHandler::SetIsDone(true) when the IO handler is done like when
237 /// "quit" is entered as a command, of when an empty line is
238 /// received. It is up to the delegate to determine when a line
239 /// should cause a IOHandler to exit.
240 virtual void IOHandlerInputComplete(IOHandler &io_handler,
241 std::string &data) = 0;
242
243 virtual void IOHandlerInputInterrupted(IOHandler &io_handler,
244 std::string &data) {}
245
246 /// Called to determine whether typing enter after the last line in
247 /// \a lines should end input. This function will not be called on
248 /// IOHandler objects that are getting single lines.
249 /// \param[in] io_handler
250 /// The IOHandler that responsible for updating the lines.
251 ///
252 /// \param[in] lines
253 /// The current multi-line content. May be altered to provide
254 /// alternative input when complete.
255 ///
256 /// \return
257 /// Return an boolean to indicate whether input is complete,
258 /// true indicates that no additional input is necessary, while
259 /// false indicates that more input is required.
260 virtual bool IOHandlerIsInputComplete(IOHandler &io_handler,
261 StringList &lines) {
262 // Impose no requirements for input to be considered complete. subclasses
263 // should do something more intelligent.
264 return true;
265 }
266
267 virtual llvm::StringRef IOHandlerGetControlSequence(char ch) { return {}; }
268
269 virtual const char *IOHandlerGetCommandPrefix() { return nullptr; }
270
271 virtual const char *IOHandlerGetHelpPrologue() { return nullptr; }
272
273 // Intercept the IOHandler::Interrupt() calls and do something.
274 //
275 // Return true if the interrupt was handled, false if the IOHandler should
276 // continue to try handle the interrupt itself.
277 virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; }
278
279protected:
280 Completion m_completion; // Support for common builtin completions
281};
282
283// IOHandlerDelegateMultiline
284//
285// A IOHandlerDelegate that handles terminating multi-line input when
286// the last line is equal to "end_line" which is specified in the constructor.
288public:
289 IOHandlerDelegateMultiline(llvm::StringRef end_line,
290 Completion completion = Completion::None)
291 : IOHandlerDelegate(completion), m_end_line(end_line.str() + "\n") {}
292
293 ~IOHandlerDelegateMultiline() override = default;
294
295 llvm::StringRef IOHandlerGetControlSequence(char ch) override {
296 if (ch == 'd')
297 return m_end_line;
298 return {};
299 }
300
302 StringList &lines) override {
303 // Determine whether the end of input signal has been entered
304 const size_t num_lines = lines.GetSize();
305 const llvm::StringRef end_line =
306 llvm::StringRef(m_end_line).drop_back(1); // Drop '\n'
307 if (num_lines > 0 && llvm::StringRef(lines[num_lines - 1]) == end_line) {
308 // Remove the terminal line from "lines" so it doesn't appear in the
309 // resulting input and return true to indicate we are done getting lines
310 lines.PopBack();
311 return true;
312 }
313 return false;
314 }
315
316protected:
317 const std::string m_end_line;
318};
319
321public:
323 const char *editline_name, // Used for saving history files
324 llvm::StringRef prompt, llvm::StringRef continuation_prompt,
325 bool multi_line, bool color,
326 uint32_t line_number_start, // If non-zero show line numbers
327 // starting at
328 // 'line_number_start'
329 IOHandlerDelegate &delegate);
330
332 const lldb::FileSP &input_sp,
333 const lldb::LockableStreamFileSP &output_sp,
334 const lldb::LockableStreamFileSP &error_sp, uint32_t flags,
335 const char *editline_name, // Used for saving history files
336 llvm::StringRef prompt, llvm::StringRef continuation_prompt,
337 bool multi_line, bool color,
338 uint32_t line_number_start, // If non-zero show line numbers
339 // starting at
340 // 'line_number_start'
341 IOHandlerDelegate &delegate);
342
343 IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *,
344 const char *, bool, bool, uint32_t,
345 IOHandlerDelegate &) = delete;
346
349 const lldb::LockableStreamFileSP &, uint32_t, const char *,
350 const char *, const char *, bool, bool, uint32_t,
351 IOHandlerDelegate &) = delete;
352
353 ~IOHandlerEditline() override;
354
355 void Run() override;
356
357 void Cancel() override;
358
359 bool Interrupt() override;
360
361 void GotEOF() override;
362
363 void Activate() override;
364
365 void Deactivate() override;
366
367 void TerminalSizeChanged() override;
368
369 llvm::StringRef GetControlSequence(char ch) override {
370 return m_delegate.IOHandlerGetControlSequence(ch);
371 }
372
373 const char *GetCommandPrefix() override {
374 return m_delegate.IOHandlerGetCommandPrefix();
375 }
376
377 const char *GetHelpPrologue() override {
378 return m_delegate.IOHandlerGetHelpPrologue();
379 }
380
381 const char *GetPrompt() override;
382
383 bool SetPrompt(llvm::StringRef prompt) override;
384 bool SetPrompt(const char *prompt) = delete;
385
386 bool SetUseColor(bool use_color) override;
387
388 const char *GetContinuationPrompt();
389
390 void SetContinuationPrompt(llvm::StringRef prompt);
391 void SetContinuationPrompt(const char *) = delete;
392
393 bool GetLine(std::string &line, bool &interrupted);
394
395 bool GetLines(StringList &lines, bool &interrupted);
396
397 void SetBaseLineNumber(uint32_t line);
398
400
402
404
405 uint32_t GetCurrentLineIndex() const;
406
407 void PrintAsync(const char *s, size_t len, bool is_stdout) override;
408
409 void Refresh() override;
410
411private:
412#if LLDB_ENABLE_LIBEDIT
413 bool IsInputCompleteCallback(Editline *editline, StringList &lines);
414
415 int FixIndentationCallback(Editline *editline, const StringList &lines,
416 int cursor_position);
417
418 std::optional<std::string> SuggestionCallback(llvm::StringRef line);
419
420 void AutoCompleteCallback(CompletionRequest &request);
421
422 void RedrawCallback();
423#endif
424
425protected:
426#if LLDB_ENABLE_LIBEDIT
427 std::unique_ptr<Editline> m_editline_up;
428#endif
430 std::string m_prompt;
433 uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt
438 std::string m_line_buffer;
439};
440
441// The order of base classes is important. Look at the constructor of
442// IOHandlerConfirm to see how.
444public:
445 IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
446 bool default_response);
447
449
450 bool GetResponse() const { return m_user_response; }
451
452 void IOHandlerComplete(IOHandler &io_handler,
453 CompletionRequest &request) override;
454
455 void IOHandlerInputComplete(IOHandler &io_handler,
456 std::string &data) override;
457
458protected:
461};
462
464public:
465 IOHandlerStack() = default;
466
467 size_t GetSize() const {
468 std::lock_guard<std::recursive_mutex> guard(m_mutex);
469 return m_stack.size();
470 }
471
472 void Push(const lldb::IOHandlerSP &sp) {
473 if (sp) {
474 std::lock_guard<std::recursive_mutex> guard(m_mutex);
475 sp->SetPopped(false);
476 m_stack.push_back(sp);
477 // Set m_top the non-locking IsTop() call
478 m_top = sp.get();
479 }
480 }
481
482 bool IsEmpty() const {
483 std::lock_guard<std::recursive_mutex> guard(m_mutex);
484 return m_stack.empty();
485 }
486
489 {
490 std::lock_guard<std::recursive_mutex> guard(m_mutex);
491 if (!m_stack.empty())
492 sp = m_stack.back();
493 }
494 return sp;
495 }
496
497 void Pop() {
498 std::lock_guard<std::recursive_mutex> guard(m_mutex);
499 if (!m_stack.empty()) {
501 m_stack.pop_back();
502 sp->SetPopped(true);
503 }
504 // Set m_top the non-locking IsTop() call
505
506 m_top = (m_stack.empty() ? nullptr : m_stack.back().get());
507 }
508
509 std::recursive_mutex &GetMutex() { return m_mutex; }
510
511 bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const {
512 return m_top == io_handler_sp.get();
513 }
514
516 IOHandler::Type second_top_type) {
517 std::lock_guard<std::recursive_mutex> guard(m_mutex);
518 const size_t num_io_handlers = m_stack.size();
519 return (num_io_handlers >= 2 &&
520 m_stack[num_io_handlers - 1]->GetType() == top_type &&
521 m_stack[num_io_handlers - 2]->GetType() == second_top_type);
522 }
523
524 llvm::StringRef GetTopIOHandlerControlSequence(char ch) {
525 return ((m_top != nullptr) ? m_top->GetControlSequence(ch)
526 : llvm::StringRef());
527 }
528
530 return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr);
531 }
532
534 return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr);
535 }
536
537 bool PrintAsync(const char *s, size_t len, bool is_stdout);
538
539protected:
540 typedef std::vector<lldb::IOHandlerSP> collection;
542 mutable std::recursive_mutex m_mutex;
543 IOHandler *m_top = nullptr;
544
545private:
547 const IOHandlerStack &operator=(const IOHandlerStack &) = delete;
548};
549
550} // namespace lldb_private
551
552#endif // LLDB_CORE_IOHANDLER_H
"lldb/Utility/ArgCompletionRequest.h"
A class to manage flag bits.
Definition Debugger.h:80
Instances of Editline provide an abstraction over libedit's EditLine facility.
Definition Editline.h:155
A class to manage flags.
Definition Flags.h:22
IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt, bool default_response)
void IOHandlerInputComplete(IOHandler &io_handler, std::string &data) override
Called when a line or lines have been retrieved.
void IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request) override
bool IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines) override
Called to determine whether typing enter after the last line in lines should end input.
Definition IOHandler.h:301
llvm::StringRef IOHandlerGetControlSequence(char ch) override
Definition IOHandler.h:295
~IOHandlerDelegateMultiline() override=default
IOHandlerDelegateMultiline(llvm::StringRef end_line, Completion completion=Completion::None)
Definition IOHandler.h:289
A delegate class for use with IOHandler subclasses.
Definition IOHandler.h:184
virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive)
Definition IOHandler.h:193
virtual void IOHandlerComplete(IOHandler &io_handler, CompletionRequest &request)
virtual const char * IOHandlerGetFixIndentationCharacters()
Definition IOHandler.h:203
virtual llvm::StringRef IOHandlerGetControlSequence(char ch)
Definition IOHandler.h:267
virtual const char * IOHandlerGetHelpPrologue()
Definition IOHandler.h:271
virtual void IOHandlerInputComplete(IOHandler &io_handler, std::string &data)=0
Called when a line or lines have been retrieved.
virtual bool IOHandlerInterrupt(IOHandler &io_handler)
Definition IOHandler.h:277
virtual void IOHandlerDeactivated(IOHandler &io_handler)
Definition IOHandler.h:195
virtual bool IOHandlerIsInputComplete(IOHandler &io_handler, StringList &lines)
Called to determine whether typing enter after the last line in lines should end input.
Definition IOHandler.h:260
virtual std::optional< std::string > IOHandlerSuggestion(IOHandler &io_handler, llvm::StringRef line)
virtual ~IOHandlerDelegate()=default
IOHandlerDelegate(Completion completion=Completion::None)
Definition IOHandler.h:188
virtual int IOHandlerFixIndentation(IOHandler &io_handler, const StringList &lines, int cursor_position)
Called when a new line is created or one of an identified set of indentation characters is typed.
Definition IOHandler.h:227
virtual const char * IOHandlerGetCommandPrefix()
Definition IOHandler.h:269
virtual void IOHandlerInputInterrupted(IOHandler &io_handler, std::string &data)
Definition IOHandler.h:243
void PrintAsync(const char *s, size_t len, bool is_stdout) override
bool SetPrompt(llvm::StringRef prompt) override
const char * GetHelpPrologue() override
Definition IOHandler.h:377
bool GetLine(std::string &line, bool &interrupted)
const char * GetCommandPrefix() override
Definition IOHandler.h:373
void TerminalSizeChanged() override
bool GetLines(StringList &lines, bool &interrupted)
IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &, const lldb::LockableStreamFileSP &, const lldb::LockableStreamFileSP &, uint32_t, const char *, const char *, const char *, bool, bool, uint32_t, IOHandlerDelegate &)=delete
bool SetPrompt(const char *prompt)=delete
llvm::StringRef GetControlSequence(char ch) override
Definition IOHandler.h:369
void SetContinuationPrompt(const char *)=delete
void SetBaseLineNumber(uint32_t line)
IOHandlerEditline(Debugger &debugger, IOHandler::Type type, const char *editline_name, llvm::StringRef prompt, llvm::StringRef continuation_prompt, bool multi_line, bool color, uint32_t line_number_start, IOHandlerDelegate &delegate)
void SetContinuationPrompt(llvm::StringRef prompt)
IOHandlerDelegate & m_delegate
Definition IOHandler.h:429
bool SetUseColor(bool use_color) override
const char * GetPrompt() override
uint32_t GetCurrentLineIndex() const
StringList GetCurrentLines() const
IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *, const char *, bool, bool, uint32_t, IOHandlerDelegate &)=delete
const char * GetTopIOHandlerHelpPrologue()
Definition IOHandler.h:533
const IOHandlerStack & operator=(const IOHandlerStack &)=delete
bool PrintAsync(const char *s, size_t len, bool is_stdout)
lldb::IOHandlerSP Top()
Definition IOHandler.h:487
llvm::StringRef GetTopIOHandlerControlSequence(char ch)
Definition IOHandler.h:524
bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const
Definition IOHandler.h:511
void Push(const lldb::IOHandlerSP &sp)
Definition IOHandler.h:472
std::recursive_mutex & GetMutex()
Definition IOHandler.h:509
IOHandlerStack(const IOHandlerStack &)=delete
bool CheckTopIOHandlerTypes(IOHandler::Type top_type, IOHandler::Type second_top_type)
Definition IOHandler.h:515
std::recursive_mutex m_mutex
Definition IOHandler.h:542
std::vector< lldb::IOHandlerSP > collection
Definition IOHandler.h:540
const char * GetTopIOHandlerCommandPrefix()
Definition IOHandler.h:529
virtual void TerminalSizeChanged()
Definition IOHandler.h:91
virtual bool SetUseColor(bool use_color)
Definition IOHandler.h:105
const Flags & GetFlags() const
Definition IOHandler.h:138
virtual void PrintAsync(const char *s, size_t len, bool is_stdout)
Predicate< bool > m_popped
Definition IOHandler.h:166
virtual bool SetPrompt(llvm::StringRef prompt)
Definition IOHandler.h:100
virtual void Run()=0
virtual const char * GetHelpPrologue()
Definition IOHandler.h:116
virtual void Activate()
Definition IOHandler.h:87
virtual void Cancel()=0
bool GetIsRealTerminal()
Check if the input is coming from a real terminal.
virtual const char * GetPrompt()
Definition IOHandler.h:95
lldb::FileSP GetInputFileSP()
Definition IOHandler.cpp:91
virtual bool Interrupt()=0
Debugger & GetDebugger()
Definition IOHandler.h:130
const IOHandler & operator=(const IOHandler &)=delete
Type GetType() const
Definition IOHandler.h:85
virtual void Deactivate()
Definition IOHandler.h:89
virtual void GotEOF()=0
lldb::LockableStreamFileSP m_output_sp
Definition IOHandler.h:164
virtual llvm::StringRef GetControlSequence(char ch)
Definition IOHandler.h:112
lldb::LockableStreamFileSP m_error_sp
Definition IOHandler.h:165
virtual const char * GetCommandPrefix()
Definition IOHandler.h:114
virtual void Refresh()
Definition IOHandler.h:93
IOHandler(Debugger &debugger, IOHandler::Type type)
Definition IOHandler.cpp:55
bool GetIsInteractive()
Check if the input is being supplied interactively by a user.
Definition IOHandler.cpp:97
lldb::FileSP m_input_sp
Definition IOHandler.h:163
bool SetPrompt(const char *)=delete
lldb::LockableStreamFileSP GetErrorStreamFileSP()
Definition IOHandler.cpp:95
IOHandler(const IOHandler &)=delete
lldb::LockableStreamFileSP GetOutputStreamFileSP()
Definition IOHandler.cpp:93
void SetUserData(void *user_data)
Definition IOHandler.h:134
void SetIsDone(bool b)
Definition IOHandler.h:81
A C++ wrapper class for providing threaded access to a value of type T.
Definition Predicate.h:42
A class that represents a running process on the host machine.
std::shared_ptr< lldb_private::IOHandler > IOHandlerSP
std::shared_ptr< lldb_private::LockableStreamFile > LockableStreamFileSP
std::shared_ptr< lldb_private::File > FileSP