File indexing completed on 2026-05-10 08:42:45
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLDB_CORE_IOHANDLER_H
0010 #define LLDB_CORE_IOHANDLER_H
0011
0012 #include "lldb/Host/Config.h"
0013 #include "lldb/Utility/CompletionRequest.h"
0014 #include "lldb/Utility/Flags.h"
0015 #include "lldb/Utility/Predicate.h"
0016 #include "lldb/Utility/Stream.h"
0017 #include "lldb/Utility/StringList.h"
0018 #include "lldb/lldb-defines.h"
0019 #include "lldb/lldb-forward.h"
0020 #include "llvm/ADT/StringRef.h"
0021
0022 #include <memory>
0023 #include <mutex>
0024 #include <optional>
0025 #include <string>
0026 #include <vector>
0027
0028 #include <cstdint>
0029 #include <cstdio>
0030
0031 namespace lldb_private {
0032 class Debugger;
0033 }
0034
0035 namespace curses {
0036 class Application;
0037 typedef std::unique_ptr<Application> ApplicationAP;
0038 }
0039
0040 namespace lldb_private {
0041
0042 class IOHandler {
0043 public:
0044 enum class Type {
0045 CommandInterpreter,
0046 CommandList,
0047 Confirm,
0048 Curses,
0049 Expression,
0050 REPL,
0051 ProcessIO,
0052 PythonInterpreter,
0053 LuaInterpreter,
0054 PythonCode,
0055 Other
0056 };
0057
0058 IOHandler(Debugger &debugger, IOHandler::Type type);
0059
0060 IOHandler(Debugger &debugger, IOHandler::Type type,
0061 const lldb::FileSP &input_sp, const lldb::StreamFileSP &output_sp,
0062 const lldb::StreamFileSP &error_sp, uint32_t flags);
0063
0064 virtual ~IOHandler();
0065
0066
0067
0068 virtual void Run() = 0;
0069
0070
0071
0072
0073
0074 virtual void Cancel() = 0;
0075
0076
0077
0078
0079 virtual bool Interrupt() = 0;
0080
0081 virtual void GotEOF() = 0;
0082
0083 bool IsActive() { return m_active && !m_done; }
0084
0085 void SetIsDone(bool b) { m_done = b; }
0086
0087 bool GetIsDone() { return m_done; }
0088
0089 Type GetType() const { return m_type; }
0090
0091 virtual void Activate() { m_active = true; }
0092
0093 virtual void Deactivate() { m_active = false; }
0094
0095 virtual void TerminalSizeChanged() {}
0096
0097 virtual const char *GetPrompt() {
0098
0099 return nullptr;
0100 }
0101
0102 virtual bool SetPrompt(llvm::StringRef prompt) {
0103
0104 return false;
0105 }
0106 bool SetPrompt(const char *) = delete;
0107
0108 virtual llvm::StringRef GetControlSequence(char ch) { return {}; }
0109
0110 virtual const char *GetCommandPrefix() { return nullptr; }
0111
0112 virtual const char *GetHelpPrologue() { return nullptr; }
0113
0114 int GetInputFD();
0115
0116 int GetOutputFD();
0117
0118 int GetErrorFD();
0119
0120 FILE *GetInputFILE();
0121
0122 FILE *GetOutputFILE();
0123
0124 FILE *GetErrorFILE();
0125
0126 lldb::FileSP GetInputFileSP();
0127
0128 lldb::StreamFileSP GetOutputStreamFileSP();
0129
0130 lldb::StreamFileSP GetErrorStreamFileSP();
0131
0132 Debugger &GetDebugger() { return m_debugger; }
0133
0134 void *GetUserData() { return m_user_data; }
0135
0136 void SetUserData(void *user_data) { m_user_data = user_data; }
0137
0138 Flags &GetFlags() { return m_flags; }
0139
0140 const Flags &GetFlags() const { return m_flags; }
0141
0142
0143
0144
0145
0146
0147 bool GetIsInteractive();
0148
0149
0150
0151
0152
0153
0154
0155 bool GetIsRealTerminal();
0156
0157 void SetPopped(bool b);
0158
0159 void WaitForPop();
0160
0161 virtual void PrintAsync(const char *s, size_t len, bool is_stdout);
0162
0163 std::recursive_mutex &GetOutputMutex() { return m_output_mutex; }
0164
0165 protected:
0166 Debugger &m_debugger;
0167 lldb::FileSP m_input_sp;
0168 lldb::StreamFileSP m_output_sp;
0169 lldb::StreamFileSP m_error_sp;
0170 std::recursive_mutex m_output_mutex;
0171 Predicate<bool> m_popped;
0172 Flags m_flags;
0173 Type m_type;
0174 void *m_user_data;
0175 bool m_done;
0176 bool m_active;
0177
0178 private:
0179 IOHandler(const IOHandler &) = delete;
0180 const IOHandler &operator=(const IOHandler &) = delete;
0181 };
0182
0183
0184
0185
0186
0187
0188
0189 class IOHandlerDelegate {
0190 public:
0191 enum class Completion { None, LLDBCommand, Expression };
0192
0193 IOHandlerDelegate(Completion completion = Completion::None)
0194 : m_completion(completion) {}
0195
0196 virtual ~IOHandlerDelegate() = default;
0197
0198 virtual void IOHandlerActivated(IOHandler &io_handler, bool interactive) {}
0199
0200 virtual void IOHandlerDeactivated(IOHandler &io_handler) {}
0201
0202 virtual std::optional<std::string> IOHandlerSuggestion(IOHandler &io_handler,
0203 llvm::StringRef line);
0204
0205 virtual void IOHandlerComplete(IOHandler &io_handler,
0206 CompletionRequest &request);
0207
0208 virtual const char *IOHandlerGetFixIndentationCharacters() { return nullptr; }
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232 virtual int IOHandlerFixIndentation(IOHandler &io_handler,
0233 const StringList &lines,
0234 int cursor_position) {
0235 return 0;
0236 }
0237
0238
0239
0240
0241
0242
0243
0244
0245 virtual void IOHandlerInputComplete(IOHandler &io_handler,
0246 std::string &data) = 0;
0247
0248 virtual void IOHandlerInputInterrupted(IOHandler &io_handler,
0249 std::string &data) {}
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265 virtual bool IOHandlerIsInputComplete(IOHandler &io_handler,
0266 StringList &lines) {
0267
0268
0269 return true;
0270 }
0271
0272 virtual llvm::StringRef IOHandlerGetControlSequence(char ch) { return {}; }
0273
0274 virtual const char *IOHandlerGetCommandPrefix() { return nullptr; }
0275
0276 virtual const char *IOHandlerGetHelpPrologue() { return nullptr; }
0277
0278
0279
0280
0281
0282 virtual bool IOHandlerInterrupt(IOHandler &io_handler) { return false; }
0283
0284 protected:
0285 Completion m_completion;
0286 };
0287
0288
0289
0290
0291
0292 class IOHandlerDelegateMultiline : public IOHandlerDelegate {
0293 public:
0294 IOHandlerDelegateMultiline(llvm::StringRef end_line,
0295 Completion completion = Completion::None)
0296 : IOHandlerDelegate(completion), m_end_line(end_line.str() + "\n") {}
0297
0298 ~IOHandlerDelegateMultiline() override = default;
0299
0300 llvm::StringRef IOHandlerGetControlSequence(char ch) override {
0301 if (ch == 'd')
0302 return m_end_line;
0303 return {};
0304 }
0305
0306 bool IOHandlerIsInputComplete(IOHandler &io_handler,
0307 StringList &lines) override {
0308
0309 const size_t num_lines = lines.GetSize();
0310 const llvm::StringRef end_line =
0311 llvm::StringRef(m_end_line).drop_back(1);
0312 if (num_lines > 0 && llvm::StringRef(lines[num_lines - 1]) == end_line) {
0313
0314
0315 lines.PopBack();
0316 return true;
0317 }
0318 return false;
0319 }
0320
0321 protected:
0322 const std::string m_end_line;
0323 };
0324
0325 class IOHandlerEditline : public IOHandler {
0326 public:
0327 IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
0328 const char *editline_name,
0329 llvm::StringRef prompt, llvm::StringRef continuation_prompt,
0330 bool multi_line, bool color,
0331 uint32_t line_number_start,
0332
0333
0334 IOHandlerDelegate &delegate);
0335
0336 IOHandlerEditline(Debugger &debugger, IOHandler::Type type,
0337 const lldb::FileSP &input_sp,
0338 const lldb::StreamFileSP &output_sp,
0339 const lldb::StreamFileSP &error_sp, uint32_t flags,
0340 const char *editline_name,
0341 llvm::StringRef prompt, llvm::StringRef continuation_prompt,
0342 bool multi_line, bool color,
0343 uint32_t line_number_start,
0344
0345
0346 IOHandlerDelegate &delegate);
0347
0348 IOHandlerEditline(Debugger &, IOHandler::Type, const char *, const char *,
0349 const char *, bool, bool, uint32_t,
0350 IOHandlerDelegate &) = delete;
0351
0352 IOHandlerEditline(Debugger &, IOHandler::Type, const lldb::FileSP &,
0353 const lldb::StreamFileSP &, const lldb::StreamFileSP &,
0354 uint32_t, const char *, const char *, const char *, bool,
0355 bool, uint32_t, IOHandlerDelegate &) = delete;
0356
0357 ~IOHandlerEditline() override;
0358
0359 void Run() override;
0360
0361 void Cancel() override;
0362
0363 bool Interrupt() override;
0364
0365 void GotEOF() override;
0366
0367 void Activate() override;
0368
0369 void Deactivate() override;
0370
0371 void TerminalSizeChanged() override;
0372
0373 llvm::StringRef GetControlSequence(char ch) override {
0374 return m_delegate.IOHandlerGetControlSequence(ch);
0375 }
0376
0377 const char *GetCommandPrefix() override {
0378 return m_delegate.IOHandlerGetCommandPrefix();
0379 }
0380
0381 const char *GetHelpPrologue() override {
0382 return m_delegate.IOHandlerGetHelpPrologue();
0383 }
0384
0385 const char *GetPrompt() override;
0386
0387 bool SetPrompt(llvm::StringRef prompt) override;
0388 bool SetPrompt(const char *prompt) = delete;
0389
0390 const char *GetContinuationPrompt();
0391
0392 void SetContinuationPrompt(llvm::StringRef prompt);
0393 void SetContinuationPrompt(const char *) = delete;
0394
0395 bool GetLine(std::string &line, bool &interrupted);
0396
0397 bool GetLines(StringList &lines, bool &interrupted);
0398
0399 void SetBaseLineNumber(uint32_t line);
0400
0401 bool GetInterruptExits() { return m_interrupt_exits; }
0402
0403 void SetInterruptExits(bool b) { m_interrupt_exits = b; }
0404
0405 StringList GetCurrentLines() const;
0406
0407 uint32_t GetCurrentLineIndex() const;
0408
0409 void PrintAsync(const char *s, size_t len, bool is_stdout) override;
0410
0411 private:
0412 #if LLDB_ENABLE_LIBEDIT
0413 bool IsInputCompleteCallback(Editline *editline, StringList &lines);
0414
0415 int FixIndentationCallback(Editline *editline, const StringList &lines,
0416 int cursor_position);
0417
0418 std::optional<std::string> SuggestionCallback(llvm::StringRef line);
0419
0420 void AutoCompleteCallback(CompletionRequest &request);
0421 #endif
0422
0423 protected:
0424 #if LLDB_ENABLE_LIBEDIT
0425 std::unique_ptr<Editline> m_editline_up;
0426 #endif
0427 IOHandlerDelegate &m_delegate;
0428 std::string m_prompt;
0429 std::string m_continuation_prompt;
0430 StringList *m_current_lines_ptr;
0431 uint32_t m_base_line_number;
0432 uint32_t m_curr_line_idx;
0433 bool m_multi_line;
0434 bool m_color;
0435 bool m_interrupt_exits;
0436 std::string m_line_buffer;
0437 };
0438
0439
0440
0441 class IOHandlerConfirm : public IOHandlerDelegate, public IOHandlerEditline {
0442 public:
0443 IOHandlerConfirm(Debugger &debugger, llvm::StringRef prompt,
0444 bool default_response);
0445
0446 ~IOHandlerConfirm() override;
0447
0448 bool GetResponse() const { return m_user_response; }
0449
0450 void IOHandlerComplete(IOHandler &io_handler,
0451 CompletionRequest &request) override;
0452
0453 void IOHandlerInputComplete(IOHandler &io_handler,
0454 std::string &data) override;
0455
0456 protected:
0457 const bool m_default_response;
0458 bool m_user_response;
0459 };
0460
0461 class IOHandlerStack {
0462 public:
0463 IOHandlerStack() = default;
0464
0465 size_t GetSize() const {
0466 std::lock_guard<std::recursive_mutex> guard(m_mutex);
0467 return m_stack.size();
0468 }
0469
0470 void Push(const lldb::IOHandlerSP &sp) {
0471 if (sp) {
0472 std::lock_guard<std::recursive_mutex> guard(m_mutex);
0473 sp->SetPopped(false);
0474 m_stack.push_back(sp);
0475
0476 m_top = sp.get();
0477 }
0478 }
0479
0480 bool IsEmpty() const {
0481 std::lock_guard<std::recursive_mutex> guard(m_mutex);
0482 return m_stack.empty();
0483 }
0484
0485 lldb::IOHandlerSP Top() {
0486 lldb::IOHandlerSP sp;
0487 {
0488 std::lock_guard<std::recursive_mutex> guard(m_mutex);
0489 if (!m_stack.empty())
0490 sp = m_stack.back();
0491 }
0492 return sp;
0493 }
0494
0495 void Pop() {
0496 std::lock_guard<std::recursive_mutex> guard(m_mutex);
0497 if (!m_stack.empty()) {
0498 lldb::IOHandlerSP sp(m_stack.back());
0499 m_stack.pop_back();
0500 sp->SetPopped(true);
0501 }
0502
0503
0504 m_top = (m_stack.empty() ? nullptr : m_stack.back().get());
0505 }
0506
0507 std::recursive_mutex &GetMutex() { return m_mutex; }
0508
0509 bool IsTop(const lldb::IOHandlerSP &io_handler_sp) const {
0510 return m_top == io_handler_sp.get();
0511 }
0512
0513 bool CheckTopIOHandlerTypes(IOHandler::Type top_type,
0514 IOHandler::Type second_top_type) {
0515 std::lock_guard<std::recursive_mutex> guard(m_mutex);
0516 const size_t num_io_handlers = m_stack.size();
0517 return (num_io_handlers >= 2 &&
0518 m_stack[num_io_handlers - 1]->GetType() == top_type &&
0519 m_stack[num_io_handlers - 2]->GetType() == second_top_type);
0520 }
0521
0522 llvm::StringRef GetTopIOHandlerControlSequence(char ch) {
0523 return ((m_top != nullptr) ? m_top->GetControlSequence(ch)
0524 : llvm::StringRef());
0525 }
0526
0527 const char *GetTopIOHandlerCommandPrefix() {
0528 return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr);
0529 }
0530
0531 const char *GetTopIOHandlerHelpPrologue() {
0532 return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr);
0533 }
0534
0535 bool PrintAsync(const char *s, size_t len, bool is_stdout);
0536
0537 protected:
0538 typedef std::vector<lldb::IOHandlerSP> collection;
0539 collection m_stack;
0540 mutable std::recursive_mutex m_mutex;
0541 IOHandler *m_top = nullptr;
0542
0543 private:
0544 IOHandlerStack(const IOHandlerStack &) = delete;
0545 const IOHandlerStack &operator=(const IOHandlerStack &) = delete;
0546 };
0547
0548 }
0549
0550 #endif