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