Coverage Report

Created: 2023-09-30 09:22

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