Coverage Report

Created: 2022-01-18 06:27

/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/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 <cstdint>
30
#include <cstdio>
31
32
namespace lldb_private {
33
class Debugger;
34
namespace repro {
35
class DataRecorder;
36
}
37
}
38
39
namespace curses {
40
class Application;
41
typedef std::unique_ptr<Application> ApplicationAP;
42
} // namespace curses
43
44
namespace lldb_private {
45
46
class IOHandler {
47
public:
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
8.17k
  virtual bool IsActive() { return m_active && 
!m_done8.16k
; }
89
90
24.6k
  virtual void SetIsDone(bool b) { m_done = b; }
91
92
528
  virtual bool GetIsDone() { return m_done; }
93
94
0
  Type GetType() const { return m_type; }
95
96
11.2k
  virtual void Activate() { m_active = true; }
97
98
11.2k
  virtual void Deactivate() { m_active = false; }
99
100
0
  virtual void TerminalSizeChanged() {}
101
102
0
  virtual const char *GetPrompt() {
103
    // Prompt support isn't mandatory
104
0
    return nullptr;
105
0
  }
106
107
0
  virtual bool SetPrompt(llvm::StringRef prompt) {
108
    // Prompt support isn't mandatory
109
0
    return false;
110
0
  }
111
  bool SetPrompt(const char *) = delete;
112
113
0
  virtual ConstString GetControlSequence(char ch) { return ConstString(); }
114
115
0
  virtual const char *GetCommandPrefix() { return nullptr; }
116
117
0
  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
0
  Debugger &GetDebugger() { return m_debugger; }
138
139
2
  void *GetUserData() { return m_user_data; }
140
141
4
  void SetUserData(void *user_data) { m_user_data = user_data; }
142
143
12.3k
  Flags &GetFlags() { return m_flags; }
144
145
0
  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
89
  virtual void PrintAsync(Stream *stream, const char *s, size_t len) {
167
89
    stream->Write(s, len);
168
89
    stream->Flush();
169
89
  }
170
171
protected:
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
184
private:
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.
195
class IOHandlerDelegate {
196
public:
197
  enum class Completion { None, LLDBCommand, Expression };
198
199
  IOHandlerDelegate(Completion completion = Completion::None)
200
54.9k
      : m_completion(completion) {}
201
202
54.9k
  virtual ~IOHandlerDelegate() = default;
203
204
1.55k
  virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive) {}
205
206
1.55k
  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
6
  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
0
                                      int cursor_position) {
241
0
    return 0;
242
0
  }
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
6
                                         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
0
                                        StringList &lines) {
273
    // Impose no requirements for input to be considered complete.  subclasses
274
    // should do something more intelligent.
275
0
    return true;
276
0
  }
277
278
0
  virtual ConstString IOHandlerGetControlSequence(char ch) {
279
0
    return ConstString();
280
0
  }
281
282
2
  virtual const char *IOHandlerGetCommandPrefix() { return nullptr; }
283
284
1
  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
0
  virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; }
291
292
protected:
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.
300
class IOHandlerDelegateMultiline : public IOHandlerDelegate {
301
public:
302
  IOHandlerDelegateMultiline(const char *end_line,
303
                             Completion completion = Completion::None)
304
      : IOHandlerDelegate(completion),
305
43.0k
        m_end_line((end_line && end_line[0]) ? end_line : "") {}
306
307
43.0k
  ~IOHandlerDelegateMultiline() override = default;
308
309
0
  ConstString IOHandlerGetControlSequence(char ch) override {
310
0
    if (ch == 'd')
311
0
      return ConstString(m_end_line + "\n");
312
0
    return ConstString();
313
0
  }
314
315
  bool IOHandlerIsInputComplete(IOHandler &io_handler,
316
13
                                StringList &lines) override {
317
    // Determine whether the end of input signal has been entered
318
13
    const size_t num_lines = lines.GetSize();
319
13
    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
5
      lines.PopBack();
323
5
      return true;
324
5
    }
325
8
    return false;
326
13
  }
327
328
protected:
329
  const std::string m_end_line;
330
};
331
332
class IOHandlerEditline : public IOHandler {
333
public:
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
0
  ConstString GetControlSequence(char ch) override {
383
0
    return m_delegate.IOHandlerGetControlSequence(ch);
384
0
  }
385
386
2
  const char *GetCommandPrefix() override {
387
2
    return m_delegate.IOHandlerGetCommandPrefix();
388
2
  }
389
390
1
  const char *GetHelpPrologue() override {
391
1
    return m_delegate.IOHandlerGetHelpPrologue();
392
1
  }
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
0
  bool GetInterruptExits() { return m_interrupt_exits; }
411
412
0
  void SetInterruptExits(bool b) { m_interrupt_exits = b; }
413
414
0
  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
420
private:
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
432
protected:
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
  std::string m_line_buffer;
446
};
447
448
// The order of base classes is important. Look at the constructor of
449
// IOHandlerConfirm to see how.
450
class IOHandlerConfirm : public IOHandlerDelegate, public IOHandlerEditline {
451
public:
452
  IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
453
                   bool default_response);
454
455
  ~IOHandlerConfirm() override;
456
457
12
  bool GetResponse() const { return m_user_response; }
458
459
  void IOHandlerComplete(IOHandler &io_handler,
460
                         CompletionRequest &request) override;
461
462
  void IOHandlerInputComplete(IOHandler &io_handler,
463
                              std::string &data) override;
464
465
protected:
466
  const bool m_default_response;
467
  bool m_user_response;
468
};
469
470
class IOHandlerStack {
471
public:
472
5.95k
  IOHandlerStack() = default;
473
474
6.40k
  size_t GetSize() const {
475
6.40k
    std::lock_guard<std::recursive_mutex> guard(m_mutex);
476
6.40k
    return m_stack.size();
477
6.40k
  }
478
479
10.6k
  void Push(const lldb::IOHandlerSP &sp) {
480
10.6k
    if (sp) {
481
10.6k
      std::lock_guard<std::recursive_mutex> guard(m_mutex);
482
10.6k
      sp->SetPopped(false);
483
10.6k
      m_stack.push_back(sp);
484
      // Set m_top the non-locking IsTop() call
485
10.6k
      m_top = sp.get();
486
10.6k
    }
487
10.6k
  }
488
489
22.6k
  bool IsEmpty() const {
490
22.6k
    std::lock_guard<std::recursive_mutex> guard(m_mutex);
491
22.6k
    return m_stack.empty();
492
22.6k
  }
493
494
41.5k
  lldb::IOHandlerSP Top() {
495
41.5k
    lldb::IOHandlerSP sp;
496
41.5k
    {
497
41.5k
      std::lock_guard<std::recursive_mutex> guard(m_mutex);
498
41.5k
      if (!m_stack.empty())
499
14.2k
        sp = m_stack.back();
500
41.5k
    }
501
41.5k
    return sp;
502
41.5k
  }
503
504
10.6k
  void Pop() {
505
10.6k
    std::lock_guard<std::recursive_mutex> guard(m_mutex);
506
10.6k
    if (!m_stack.empty()) {
507
10.6k
      lldb::IOHandlerSP sp(m_stack.back());
508
10.6k
      m_stack.pop_back();
509
10.6k
      sp->SetPopped(true);
510
10.6k
    }
511
    // Set m_top the non-locking IsTop() call
512
513
10.6k
    m_top = (m_stack.empty() ? 
nullptr10.0k
:
m_stack.back().get()601
);
514
10.6k
  }
515
516
47.2k
  std::recursive_mutex &GetMutex() { return m_mutex; }
517
518
0
  bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const {
519
0
    return m_top == io_handler_sp.get();
520
0
  }
521
522
  bool CheckTopIOHandlerTypes(IOHandler::Type top_type,
523
0
                              IOHandler::Type second_top_type) {
524
0
    std::lock_guard<std::recursive_mutex> guard(m_mutex);
525
0
    const size_t num_io_handlers = m_stack.size();
526
0
    return (num_io_handlers >= 2 &&
527
0
            m_stack[num_io_handlers - 1]->GetType() == top_type &&
528
0
            m_stack[num_io_handlers - 2]->GetType() == second_top_type);
529
0
  }
530
531
0
  ConstString GetTopIOHandlerControlSequence(char ch) {
532
0
    return ((m_top != nullptr) ? m_top->GetControlSequence(ch) : ConstString());
533
0
  }
534
535
23
  const char *GetTopIOHandlerCommandPrefix() {
536
23
    return ((m_top != nullptr) ? 
m_top->GetCommandPrefix()2
:
nullptr21
);
537
23
  }
538
539
12
  const char *GetTopIOHandlerHelpPrologue() {
540
12
    return ((m_top != nullptr) ? 
m_top->GetHelpPrologue()1
:
nullptr11
);
541
12
  }
542
543
  void PrintAsync(Stream *stream, const char *s, size_t len);
544
545
protected:
546
  typedef std::vector<lldb::IOHandlerSP> collection;
547
  collection m_stack;
548
  mutable std::recursive_mutex m_mutex;
549
  IOHandler *m_top = nullptr;
550
551
private:
552
  IOHandlerStack(const IOHandlerStack &) = delete;
553
  const IOHandlerStack &operator=(const IOHandlerStack &) = delete;
554
};
555
556
} // namespace lldb_private
557
558
#endif // LLDB_CORE_IOHANDLER_H