mirror of
https://github.com/opnsense/src.git
synced 2026-02-28 04:10:49 -05:00
830 lines
23 KiB
C++
830 lines
23 KiB
C++
//===-- IOHandler.h ---------------------------------------------*- C++ -*-===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef liblldb_IOHandler_h_
|
|
#define liblldb_IOHandler_h_
|
|
|
|
// C Includes
|
|
#include <string.h>
|
|
|
|
// C++ Includes
|
|
#include <memory>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
// Other libraries and framework includes
|
|
// Project includes
|
|
#include "lldb/lldb-public.h"
|
|
#include "lldb/lldb-enumerations.h"
|
|
#include "lldb/Core/ConstString.h"
|
|
#include "lldb/Core/Error.h"
|
|
#include "lldb/Core/Flags.h"
|
|
#include "lldb/Core/Stream.h"
|
|
#include "lldb/Core/StringList.h"
|
|
#include "lldb/Core/ValueObjectList.h"
|
|
#include "lldb/Host/Mutex.h"
|
|
#include "lldb/Host/Predicate.h"
|
|
|
|
namespace curses
|
|
{
|
|
class Application;
|
|
typedef std::unique_ptr<Application> ApplicationAP;
|
|
} // namespace curses
|
|
|
|
namespace lldb_private {
|
|
|
|
class IOHandler
|
|
{
|
|
public:
|
|
enum class Type {
|
|
CommandInterpreter,
|
|
CommandList,
|
|
Confirm,
|
|
Curses,
|
|
Expression,
|
|
REPL,
|
|
ProcessIO,
|
|
PythonInterpreter,
|
|
PythonCode,
|
|
Other
|
|
};
|
|
|
|
IOHandler (Debugger &debugger,
|
|
IOHandler::Type type);
|
|
|
|
IOHandler (Debugger &debugger,
|
|
IOHandler::Type type,
|
|
const lldb::StreamFileSP &input_sp,
|
|
const lldb::StreamFileSP &output_sp,
|
|
const lldb::StreamFileSP &error_sp,
|
|
uint32_t flags);
|
|
|
|
virtual
|
|
~IOHandler ();
|
|
|
|
// Each IOHandler gets to run until it is done. It should read data
|
|
// from the "in" and place output into "out" and "err and return
|
|
// when done.
|
|
virtual void
|
|
Run () = 0;
|
|
|
|
// Called when an input reader should relinquish its control so another
|
|
// can be pushed onto the IO handler stack, or so the current IO
|
|
// handler can pop itself off the stack
|
|
|
|
virtual void
|
|
Cancel () = 0;
|
|
|
|
// Called when CTRL+C is pressed which usually causes
|
|
// Debugger::DispatchInputInterrupt to be called.
|
|
|
|
virtual bool
|
|
Interrupt () = 0;
|
|
|
|
virtual void
|
|
GotEOF() = 0;
|
|
|
|
virtual bool
|
|
IsActive ()
|
|
{
|
|
return m_active && !m_done;
|
|
}
|
|
|
|
virtual void
|
|
SetIsDone (bool b)
|
|
{
|
|
m_done = b;
|
|
}
|
|
|
|
virtual bool
|
|
GetIsDone ()
|
|
{
|
|
return m_done;
|
|
}
|
|
|
|
Type
|
|
GetType () const
|
|
{
|
|
return m_type;
|
|
}
|
|
|
|
virtual void
|
|
Activate ()
|
|
{
|
|
m_active = true;
|
|
}
|
|
|
|
virtual void
|
|
Deactivate ()
|
|
{
|
|
m_active = false;
|
|
}
|
|
|
|
virtual const char *
|
|
GetPrompt ()
|
|
{
|
|
// Prompt support isn't mandatory
|
|
return nullptr;
|
|
}
|
|
|
|
virtual bool
|
|
SetPrompt (const char *prompt)
|
|
{
|
|
// Prompt support isn't mandatory
|
|
return false;
|
|
}
|
|
|
|
virtual ConstString
|
|
GetControlSequence (char ch)
|
|
{
|
|
return ConstString();
|
|
}
|
|
|
|
virtual const char *
|
|
GetCommandPrefix ()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
virtual const char *
|
|
GetHelpPrologue()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
int
|
|
GetInputFD();
|
|
|
|
int
|
|
GetOutputFD();
|
|
|
|
int
|
|
GetErrorFD();
|
|
|
|
FILE *
|
|
GetInputFILE();
|
|
|
|
FILE *
|
|
GetOutputFILE();
|
|
|
|
FILE *
|
|
GetErrorFILE();
|
|
|
|
lldb::StreamFileSP &
|
|
GetInputStreamFile();
|
|
|
|
lldb::StreamFileSP &
|
|
GetOutputStreamFile();
|
|
|
|
lldb::StreamFileSP &
|
|
GetErrorStreamFile();
|
|
|
|
Debugger &
|
|
GetDebugger()
|
|
{
|
|
return m_debugger;
|
|
}
|
|
|
|
void *
|
|
GetUserData ()
|
|
{
|
|
return m_user_data;
|
|
}
|
|
|
|
void
|
|
SetUserData (void *user_data)
|
|
{
|
|
m_user_data = user_data;
|
|
}
|
|
|
|
Flags &
|
|
GetFlags ()
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
const Flags &
|
|
GetFlags () const
|
|
{
|
|
return m_flags;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Check if the input is being supplied interactively by a user
|
|
///
|
|
/// This will return true if the input stream is a terminal (tty or
|
|
/// pty) and can cause IO handlers to do different things (like
|
|
/// for a confirmation when deleting all breakpoints).
|
|
//------------------------------------------------------------------
|
|
bool
|
|
GetIsInteractive ();
|
|
|
|
//------------------------------------------------------------------
|
|
/// Check if the input is coming from a real terminal.
|
|
///
|
|
/// A real terminal has a valid size with a certain number of rows
|
|
/// and columns. If this function returns true, then terminal escape
|
|
/// sequences are expected to work (cursor movement escape sequences,
|
|
/// clearing lines, etc).
|
|
//------------------------------------------------------------------
|
|
bool
|
|
GetIsRealTerminal ();
|
|
|
|
void
|
|
SetPopped (bool b);
|
|
|
|
void
|
|
WaitForPop ();
|
|
|
|
virtual void
|
|
PrintAsync (Stream *stream, const char *s, size_t len)
|
|
{
|
|
stream->Write (s, len);
|
|
stream->Flush();
|
|
}
|
|
|
|
protected:
|
|
Debugger &m_debugger;
|
|
lldb::StreamFileSP m_input_sp;
|
|
lldb::StreamFileSP m_output_sp;
|
|
lldb::StreamFileSP m_error_sp;
|
|
Predicate<bool> m_popped;
|
|
Flags m_flags;
|
|
Type m_type;
|
|
void *m_user_data;
|
|
bool m_done;
|
|
bool m_active;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN (IOHandler);
|
|
};
|
|
|
|
//------------------------------------------------------------------
|
|
/// A delegate class for use with IOHandler subclasses.
|
|
///
|
|
/// The IOHandler delegate is designed to be mixed into classes so
|
|
/// they can use an IOHandler subclass to fetch input and notify the
|
|
/// object that inherits from this delegate class when a token is
|
|
/// received.
|
|
//------------------------------------------------------------------
|
|
class IOHandlerDelegate
|
|
{
|
|
public:
|
|
enum class Completion {
|
|
None,
|
|
LLDBCommand,
|
|
Expression
|
|
};
|
|
|
|
IOHandlerDelegate (Completion completion = Completion::None) :
|
|
m_completion(completion),
|
|
m_io_handler_done (false)
|
|
{
|
|
}
|
|
|
|
virtual
|
|
~IOHandlerDelegate() = default;
|
|
|
|
virtual void
|
|
IOHandlerActivated (IOHandler &io_handler)
|
|
{
|
|
}
|
|
|
|
virtual void
|
|
IOHandlerDeactivated (IOHandler &io_handler)
|
|
{
|
|
}
|
|
|
|
virtual int
|
|
IOHandlerComplete (IOHandler &io_handler,
|
|
const char *current_line,
|
|
const char *cursor,
|
|
const char *last_char,
|
|
int skip_first_n_matches,
|
|
int max_matches,
|
|
StringList &matches);
|
|
|
|
virtual const char *
|
|
IOHandlerGetFixIndentationCharacters ()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Called when a new line is created or one of an identified set of
|
|
/// indentation characters is typed.
|
|
///
|
|
/// This function determines how much indentation should be added
|
|
/// or removed to match the recommended amount for the final line.
|
|
///
|
|
/// @param[in] io_handler
|
|
/// The IOHandler that responsible for input.
|
|
///
|
|
/// @param[in] lines
|
|
/// The current input up to the line to be corrected. Lines
|
|
/// following the line containing the cursor are not included.
|
|
///
|
|
/// @param[in] cursor_position
|
|
/// The number of characters preceding the cursor on the final
|
|
/// line at the time.
|
|
///
|
|
/// @return
|
|
/// Returns an integer describing the number of spaces needed
|
|
/// to correct the indentation level. Positive values indicate
|
|
/// that spaces should be added, while negative values represent
|
|
/// spaces that should be removed.
|
|
//------------------------------------------------------------------
|
|
virtual int
|
|
IOHandlerFixIndentation (IOHandler &io_handler,
|
|
const StringList &lines,
|
|
int cursor_position)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Called when a line or lines have been retrieved.
|
|
///
|
|
/// This function can handle the current line and possibly call
|
|
/// IOHandler::SetIsDone(true) when the IO handler is done like when
|
|
/// "quit" is entered as a command, of when an empty line is
|
|
/// received. It is up to the delegate to determine when a line
|
|
/// should cause a IOHandler to exit.
|
|
//------------------------------------------------------------------
|
|
virtual void
|
|
IOHandlerInputComplete (IOHandler &io_handler, std::string &data) = 0;
|
|
|
|
virtual void
|
|
IOHandlerInputInterrupted (IOHandler &io_handler, std::string &data)
|
|
{
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
/// Called to determine whether typing enter after the last line in
|
|
/// \a lines should end input. This function will not be called on
|
|
/// IOHandler objects that are getting single lines.
|
|
/// @param[in] io_handler
|
|
/// The IOHandler that responsible for updating the lines.
|
|
///
|
|
/// @param[in] lines
|
|
/// The current multi-line content. May be altered to provide
|
|
/// alternative input when complete.
|
|
///
|
|
/// @return
|
|
/// Return an boolean to indicate whether input is complete,
|
|
/// true indicates that no additional input is necessary, while
|
|
/// false indicates that more input is required.
|
|
//------------------------------------------------------------------
|
|
virtual bool
|
|
IOHandlerIsInputComplete (IOHandler &io_handler,
|
|
StringList &lines)
|
|
{
|
|
// Impose no requirements for input to be considered
|
|
// complete. subclasses should do something more intelligent.
|
|
return true;
|
|
}
|
|
|
|
virtual ConstString
|
|
IOHandlerGetControlSequence (char ch)
|
|
{
|
|
return ConstString();
|
|
}
|
|
|
|
virtual const char *
|
|
IOHandlerGetCommandPrefix ()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
virtual const char *
|
|
IOHandlerGetHelpPrologue ()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
//------------------------------------------------------------------
|
|
// Intercept the IOHandler::Interrupt() calls and do something.
|
|
//
|
|
// Return true if the interrupt was handled, false if the IOHandler
|
|
// should continue to try handle the interrupt itself.
|
|
//------------------------------------------------------------------
|
|
virtual bool
|
|
IOHandlerInterrupt (IOHandler &io_handler)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
protected:
|
|
Completion m_completion; // Support for common builtin completions
|
|
bool m_io_handler_done;
|
|
};
|
|
|
|
//----------------------------------------------------------------------
|
|
// IOHandlerDelegateMultiline
|
|
//
|
|
// A IOHandlerDelegate that handles terminating multi-line input when
|
|
// the last line is equal to "end_line" which is specified in the
|
|
// constructor.
|
|
//----------------------------------------------------------------------
|
|
class IOHandlerDelegateMultiline :
|
|
public IOHandlerDelegate
|
|
{
|
|
public:
|
|
IOHandlerDelegateMultiline (const char *end_line,
|
|
Completion completion = Completion::None) :
|
|
IOHandlerDelegate (completion),
|
|
m_end_line((end_line && end_line[0]) ? end_line : "")
|
|
{
|
|
}
|
|
|
|
~IOHandlerDelegateMultiline() override = default;
|
|
|
|
ConstString
|
|
IOHandlerGetControlSequence (char ch) override
|
|
{
|
|
if (ch == 'd')
|
|
return ConstString (m_end_line + "\n");
|
|
return ConstString();
|
|
}
|
|
|
|
bool
|
|
IOHandlerIsInputComplete (IOHandler &io_handler,
|
|
StringList &lines) override
|
|
{
|
|
// Determine whether the end of input signal has been entered
|
|
const size_t num_lines = lines.GetSize();
|
|
if (num_lines > 0 && lines[num_lines - 1] == m_end_line)
|
|
{
|
|
// Remove the terminal line from "lines" so it doesn't appear in
|
|
// the resulting input and return true to indicate we are done
|
|
// getting lines
|
|
lines.PopBack();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
protected:
|
|
const std::string m_end_line;
|
|
};
|
|
|
|
class IOHandlerEditline : public IOHandler
|
|
{
|
|
public:
|
|
IOHandlerEditline (Debugger &debugger,
|
|
IOHandler::Type type,
|
|
const char *editline_name, // Used for saving history files
|
|
const char *prompt,
|
|
const char *continuation_prompt,
|
|
bool multi_line,
|
|
bool color_prompts,
|
|
uint32_t line_number_start, // If non-zero show line numbers starting at 'line_number_start'
|
|
IOHandlerDelegate &delegate);
|
|
|
|
IOHandlerEditline (Debugger &debugger,
|
|
IOHandler::Type type,
|
|
const lldb::StreamFileSP &input_sp,
|
|
const lldb::StreamFileSP &output_sp,
|
|
const lldb::StreamFileSP &error_sp,
|
|
uint32_t flags,
|
|
const char *editline_name, // Used for saving history files
|
|
const char *prompt,
|
|
const char *continuation_prompt,
|
|
bool multi_line,
|
|
bool color_prompts,
|
|
uint32_t line_number_start, // If non-zero show line numbers starting at 'line_number_start'
|
|
IOHandlerDelegate &delegate);
|
|
|
|
~IOHandlerEditline() override;
|
|
|
|
void
|
|
Run () override;
|
|
|
|
void
|
|
Cancel () override;
|
|
|
|
bool
|
|
Interrupt () override;
|
|
|
|
void
|
|
GotEOF() override;
|
|
|
|
void
|
|
Activate () override;
|
|
|
|
void
|
|
Deactivate () override;
|
|
|
|
ConstString
|
|
GetControlSequence (char ch) override
|
|
{
|
|
return m_delegate.IOHandlerGetControlSequence (ch);
|
|
}
|
|
|
|
const char *
|
|
GetCommandPrefix () override
|
|
{
|
|
return m_delegate.IOHandlerGetCommandPrefix ();
|
|
}
|
|
|
|
const char *
|
|
GetHelpPrologue () override
|
|
{
|
|
return m_delegate.IOHandlerGetHelpPrologue ();
|
|
}
|
|
|
|
const char *
|
|
GetPrompt () override;
|
|
|
|
bool
|
|
SetPrompt (const char *prompt) override;
|
|
|
|
const char *
|
|
GetContinuationPrompt ();
|
|
|
|
void
|
|
SetContinuationPrompt (const char *prompt);
|
|
|
|
bool
|
|
GetLine (std::string &line, bool &interrupted);
|
|
|
|
bool
|
|
GetLines (StringList &lines, bool &interrupted);
|
|
|
|
void
|
|
SetBaseLineNumber (uint32_t line);
|
|
|
|
bool
|
|
GetInterruptExits ()
|
|
{
|
|
return m_interrupt_exits;
|
|
}
|
|
|
|
void
|
|
SetInterruptExits (bool b)
|
|
{
|
|
m_interrupt_exits = b;
|
|
}
|
|
|
|
const StringList *
|
|
GetCurrentLines () const
|
|
{
|
|
return m_current_lines_ptr;
|
|
}
|
|
|
|
uint32_t
|
|
GetCurrentLineIndex () const;
|
|
|
|
void
|
|
PrintAsync (Stream *stream, const char *s, size_t len) override;
|
|
|
|
private:
|
|
#ifndef LLDB_DISABLE_LIBEDIT
|
|
static bool
|
|
IsInputCompleteCallback (Editline *editline,
|
|
StringList &lines,
|
|
void *baton);
|
|
|
|
static int
|
|
FixIndentationCallback (Editline *editline,
|
|
const StringList &lines,
|
|
int cursor_position,
|
|
void *baton);
|
|
|
|
static int AutoCompleteCallback (const char *current_line,
|
|
const char *cursor,
|
|
const char *last_char,
|
|
int skip_first_n_matches,
|
|
int max_matches,
|
|
StringList &matches,
|
|
void *baton);
|
|
#endif
|
|
|
|
protected:
|
|
#ifndef LLDB_DISABLE_LIBEDIT
|
|
std::unique_ptr<Editline> m_editline_ap;
|
|
#endif
|
|
IOHandlerDelegate &m_delegate;
|
|
std::string m_prompt;
|
|
std::string m_continuation_prompt;
|
|
StringList *m_current_lines_ptr;
|
|
uint32_t m_base_line_number; // If non-zero, then show line numbers in prompt
|
|
uint32_t m_curr_line_idx;
|
|
bool m_multi_line;
|
|
bool m_color_prompts;
|
|
bool m_interrupt_exits;
|
|
bool m_editing; // Set to true when fetching a line manually (not using libedit)
|
|
};
|
|
|
|
// The order of base classes is important. Look at the constructor of IOHandlerConfirm
|
|
// to see how.
|
|
class IOHandlerConfirm :
|
|
public IOHandlerDelegate,
|
|
public IOHandlerEditline
|
|
{
|
|
public:
|
|
IOHandlerConfirm (Debugger &debugger,
|
|
const char *prompt,
|
|
bool default_response);
|
|
|
|
~IOHandlerConfirm() override;
|
|
|
|
bool
|
|
GetResponse () const
|
|
{
|
|
return m_user_response;
|
|
}
|
|
|
|
int
|
|
IOHandlerComplete (IOHandler &io_handler,
|
|
const char *current_line,
|
|
const char *cursor,
|
|
const char *last_char,
|
|
int skip_first_n_matches,
|
|
int max_matches,
|
|
StringList &matches) override;
|
|
|
|
void
|
|
IOHandlerInputComplete (IOHandler &io_handler, std::string &data) override;
|
|
|
|
protected:
|
|
const bool m_default_response;
|
|
bool m_user_response;
|
|
};
|
|
|
|
class IOHandlerCursesGUI :
|
|
public IOHandler
|
|
{
|
|
public:
|
|
IOHandlerCursesGUI (Debugger &debugger);
|
|
|
|
~IOHandlerCursesGUI () override;
|
|
|
|
void
|
|
Run () override;
|
|
|
|
void
|
|
Cancel () override;
|
|
|
|
bool
|
|
Interrupt () override;
|
|
|
|
void
|
|
GotEOF() override;
|
|
|
|
void
|
|
Activate () override;
|
|
|
|
void
|
|
Deactivate () override;
|
|
|
|
protected:
|
|
curses::ApplicationAP m_app_ap;
|
|
};
|
|
|
|
class IOHandlerCursesValueObjectList :
|
|
public IOHandler
|
|
{
|
|
public:
|
|
IOHandlerCursesValueObjectList (Debugger &debugger, ValueObjectList &valobj_list);
|
|
|
|
~IOHandlerCursesValueObjectList() override;
|
|
|
|
void
|
|
Run () override;
|
|
|
|
void
|
|
GotEOF() override;
|
|
|
|
protected:
|
|
ValueObjectList m_valobj_list;
|
|
};
|
|
|
|
class IOHandlerStack
|
|
{
|
|
public:
|
|
IOHandlerStack () :
|
|
m_stack(),
|
|
m_mutex(Mutex::eMutexTypeRecursive),
|
|
m_top (nullptr)
|
|
{
|
|
}
|
|
|
|
~IOHandlerStack() = default;
|
|
|
|
size_t
|
|
GetSize () const
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
return m_stack.size();
|
|
}
|
|
|
|
void
|
|
Push (const lldb::IOHandlerSP& sp)
|
|
{
|
|
if (sp)
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
sp->SetPopped (false);
|
|
m_stack.push_back (sp);
|
|
// Set m_top the non-locking IsTop() call
|
|
m_top = sp.get();
|
|
}
|
|
}
|
|
|
|
bool
|
|
IsEmpty () const
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
return m_stack.empty();
|
|
}
|
|
|
|
lldb::IOHandlerSP
|
|
Top ()
|
|
{
|
|
lldb::IOHandlerSP sp;
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
if (!m_stack.empty())
|
|
sp = m_stack.back();
|
|
}
|
|
return sp;
|
|
}
|
|
|
|
void
|
|
Pop ()
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
if (!m_stack.empty())
|
|
{
|
|
lldb::IOHandlerSP sp (m_stack.back());
|
|
m_stack.pop_back();
|
|
sp->SetPopped (true);
|
|
}
|
|
// Set m_top the non-locking IsTop() call
|
|
|
|
m_top = (m_stack.empty() ? nullptr : m_stack.back().get());
|
|
}
|
|
|
|
Mutex &
|
|
GetMutex()
|
|
{
|
|
return m_mutex;
|
|
}
|
|
|
|
bool
|
|
IsTop (const lldb::IOHandlerSP &io_handler_sp) const
|
|
{
|
|
return m_top == io_handler_sp.get();
|
|
}
|
|
|
|
bool
|
|
CheckTopIOHandlerTypes (IOHandler::Type top_type, IOHandler::Type second_top_type)
|
|
{
|
|
Mutex::Locker locker (m_mutex);
|
|
const size_t num_io_handlers = m_stack.size();
|
|
return (num_io_handlers >= 2 &&
|
|
m_stack[num_io_handlers-1]->GetType() == top_type &&
|
|
m_stack[num_io_handlers-2]->GetType() == second_top_type);
|
|
}
|
|
|
|
ConstString
|
|
GetTopIOHandlerControlSequence (char ch)
|
|
{
|
|
return ((m_top != nullptr) ? m_top->GetControlSequence(ch) : ConstString());
|
|
}
|
|
|
|
const char *
|
|
GetTopIOHandlerCommandPrefix()
|
|
{
|
|
return ((m_top != nullptr) ? m_top->GetCommandPrefix() : nullptr);
|
|
}
|
|
|
|
const char *
|
|
GetTopIOHandlerHelpPrologue()
|
|
{
|
|
return ((m_top != nullptr) ? m_top->GetHelpPrologue() : nullptr);
|
|
}
|
|
|
|
void
|
|
PrintAsync (Stream *stream, const char *s, size_t len);
|
|
|
|
protected:
|
|
typedef std::vector<lldb::IOHandlerSP> collection;
|
|
collection m_stack;
|
|
mutable Mutex m_mutex;
|
|
IOHandler *m_top;
|
|
|
|
private:
|
|
DISALLOW_COPY_AND_ASSIGN (IOHandlerStack);
|
|
};
|
|
|
|
} // namespace lldb_private
|
|
|
|
#endif // liblldb_IOHandler_h_
|