blob: 80a054b32ce653fa36158b13d4663d68f74f3600 [file] [log] [blame]
//===-- ScriptInterpreter.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLDB_INTERPRETER_SCRIPTINTERPRETER_H
#define LLDB_INTERPRETER_SCRIPTINTERPRETER_H
#include "lldb/API/SBData.h"
#include "lldb/API/SBError.h"
#include "lldb/Breakpoint/BreakpointOptions.h"
#include "lldb/Core/Communication.h"
#include "lldb/Core/PluginInterface.h"
#include "lldb/Core/SearchFilter.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Host/PseudoTerminal.h"
#include "lldb/Interpreter/ScriptedProcessInterface.h"
#include "lldb/Utility/Broadcaster.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-private.h"
namespace lldb_private {
class ScriptInterpreterLocker {
public:
ScriptInterpreterLocker() = default;
virtual ~ScriptInterpreterLocker() = default;
private:
ScriptInterpreterLocker(const ScriptInterpreterLocker &) = delete;
const ScriptInterpreterLocker &
operator=(const ScriptInterpreterLocker &) = delete;
};
class ExecuteScriptOptions {
public:
ExecuteScriptOptions() = default;
bool GetEnableIO() const { return m_enable_io; }
bool GetSetLLDBGlobals() const { return m_set_lldb_globals; }
// If this is true then any exceptions raised by the script will be
// cleared with PyErr_Clear(). If false then they will be left for
// the caller to clean up
bool GetMaskoutErrors() const { return m_maskout_errors; }
ExecuteScriptOptions &SetEnableIO(bool enable) {
m_enable_io = enable;
return *this;
}
ExecuteScriptOptions &SetSetLLDBGlobals(bool set) {
m_set_lldb_globals = set;
return *this;
}
ExecuteScriptOptions &SetMaskoutErrors(bool maskout) {
m_maskout_errors = maskout;
return *this;
}
private:
bool m_enable_io = true;
bool m_set_lldb_globals = true;
bool m_maskout_errors = true;
};
class LoadScriptOptions {
public:
LoadScriptOptions() = default;
bool GetInitSession() const { return m_init_session; }
bool GetSilent() const { return m_silent; }
LoadScriptOptions &SetInitSession(bool b) {
m_init_session = b;
return *this;
}
LoadScriptOptions &SetSilent(bool b) {
m_silent = b;
return *this;
}
private:
bool m_init_session = false;
bool m_silent = false;
};
class ScriptInterpreterIORedirect {
public:
/// Create an IO redirect. If IO is enabled, this will redirects the output
/// to the command return object if set or to the debugger otherwise. If IO
/// is disabled, it will redirect all IO to /dev/null.
static llvm::Expected<std::unique_ptr<ScriptInterpreterIORedirect>>
Create(bool enable_io, Debugger &debugger, CommandReturnObject *result);
~ScriptInterpreterIORedirect();
lldb::FileSP GetInputFile() const { return m_input_file_sp; }
lldb::FileSP GetOutputFile() const { return m_output_file_sp->GetFileSP(); }
lldb::FileSP GetErrorFile() const { return m_error_file_sp->GetFileSP(); }
/// Flush our output and error file handles.
void Flush();
private:
ScriptInterpreterIORedirect(std::unique_ptr<File> input,
std::unique_ptr<File> output);
ScriptInterpreterIORedirect(Debugger &debugger, CommandReturnObject *result);
lldb::FileSP m_input_file_sp;
lldb::StreamFileSP m_output_file_sp;
lldb::StreamFileSP m_error_file_sp;
Communication m_communication;
bool m_disconnect;
};
class ScriptInterpreter : public PluginInterface {
public:
enum ScriptReturnType {
eScriptReturnTypeCharPtr,
eScriptReturnTypeBool,
eScriptReturnTypeShortInt,
eScriptReturnTypeShortIntUnsigned,
eScriptReturnTypeInt,
eScriptReturnTypeIntUnsigned,
eScriptReturnTypeLongInt,
eScriptReturnTypeLongIntUnsigned,
eScriptReturnTypeLongLong,
eScriptReturnTypeLongLongUnsigned,
eScriptReturnTypeFloat,
eScriptReturnTypeDouble,
eScriptReturnTypeChar,
eScriptReturnTypeCharStrOrNone,
eScriptReturnTypeOpaqueObject
};
ScriptInterpreter(
Debugger &debugger, lldb::ScriptLanguage script_lang,
lldb::ScriptedProcessInterfaceUP scripted_process_interface_up =
std::make_unique<ScriptedProcessInterface>());
~ScriptInterpreter() override = default;
virtual bool Interrupt() { return false; }
virtual bool ExecuteOneLine(
llvm::StringRef command, CommandReturnObject *result,
const ExecuteScriptOptions &options = ExecuteScriptOptions()) = 0;
virtual void ExecuteInterpreterLoop() = 0;
virtual bool ExecuteOneLineWithReturn(
llvm::StringRef in_string, ScriptReturnType return_type, void *ret_value,
const ExecuteScriptOptions &options = ExecuteScriptOptions()) {
return true;
}
virtual Status ExecuteMultipleLines(
const char *in_string,
const ExecuteScriptOptions &options = ExecuteScriptOptions()) {
Status error;
error.SetErrorString("not implemented");
return error;
}
virtual Status
ExportFunctionDefinitionToInterpreter(StringList &function_def) {
Status error;
error.SetErrorString("not implemented");
return error;
}
virtual Status GenerateBreakpointCommandCallbackData(
StringList &input,
std::string &output,
bool has_extra_args) {
Status error;
error.SetErrorString("not implemented");
return error;
}
virtual bool GenerateWatchpointCommandCallbackData(StringList &input,
std::string &output) {
return false;
}
virtual bool GenerateTypeScriptFunction(const char *oneliner,
std::string &output,
const void *name_token = nullptr) {
return false;
}
virtual bool GenerateTypeScriptFunction(StringList &input,
std::string &output,
const void *name_token = nullptr) {
return false;
}
virtual bool GenerateScriptAliasFunction(StringList &input,
std::string &output) {
return false;
}
virtual bool GenerateTypeSynthClass(StringList &input, std::string &output,
const void *name_token = nullptr) {
return false;
}
virtual bool GenerateTypeSynthClass(const char *oneliner, std::string &output,
const void *name_token = nullptr) {
return false;
}
virtual StructuredData::ObjectSP
CreateSyntheticScriptedProvider(const char *class_name,
lldb::ValueObjectSP valobj) {
return StructuredData::ObjectSP();
}
virtual StructuredData::GenericSP
CreateScriptCommandObject(const char *class_name) {
return StructuredData::GenericSP();
}
virtual StructuredData::GenericSP
CreateFrameRecognizer(const char *class_name) {
return StructuredData::GenericSP();
}
virtual lldb::ValueObjectListSP GetRecognizedArguments(
const StructuredData::ObjectSP &implementor,
lldb::StackFrameSP frame_sp) {
return lldb::ValueObjectListSP();
}
virtual StructuredData::GenericSP
OSPlugin_CreatePluginObject(const char *class_name,
lldb::ProcessSP process_sp) {
return StructuredData::GenericSP();
}
virtual StructuredData::DictionarySP
OSPlugin_RegisterInfo(StructuredData::ObjectSP os_plugin_object_sp) {
return StructuredData::DictionarySP();
}
virtual StructuredData::ArraySP
OSPlugin_ThreadsInfo(StructuredData::ObjectSP os_plugin_object_sp) {
return StructuredData::ArraySP();
}
virtual StructuredData::StringSP
OSPlugin_RegisterContextData(StructuredData::ObjectSP os_plugin_object_sp,
lldb::tid_t thread_id) {
return StructuredData::StringSP();
}
virtual StructuredData::DictionarySP
OSPlugin_CreateThread(StructuredData::ObjectSP os_plugin_object_sp,
lldb::tid_t tid, lldb::addr_t context) {
return StructuredData::DictionarySP();
}
virtual StructuredData::ObjectSP
CreateScriptedThreadPlan(const char *class_name,
StructuredDataImpl *args_data,
std::string &error_str,
lldb::ThreadPlanSP thread_plan_sp) {
return StructuredData::ObjectSP();
}
virtual bool
ScriptedThreadPlanExplainsStop(StructuredData::ObjectSP implementor_sp,
Event *event, bool &script_error) {
script_error = true;
return true;
}
virtual bool
ScriptedThreadPlanShouldStop(StructuredData::ObjectSP implementor_sp,
Event *event, bool &script_error) {
script_error = true;
return true;
}
virtual bool
ScriptedThreadPlanIsStale(StructuredData::ObjectSP implementor_sp,
bool &script_error) {
script_error = true;
return true;
}
virtual lldb::StateType
ScriptedThreadPlanGetRunState(StructuredData::ObjectSP implementor_sp,
bool &script_error) {
script_error = true;
return lldb::eStateStepping;
}
virtual StructuredData::GenericSP
CreateScriptedBreakpointResolver(const char *class_name,
StructuredDataImpl *args_data,
lldb::BreakpointSP &bkpt_sp) {
return StructuredData::GenericSP();
}
virtual bool
ScriptedBreakpointResolverSearchCallback(StructuredData::GenericSP implementor_sp,
SymbolContext *sym_ctx)
{
return false;
}
virtual lldb::SearchDepth
ScriptedBreakpointResolverSearchDepth(StructuredData::GenericSP implementor_sp)
{
return lldb::eSearchDepthModule;
}
virtual StructuredData::GenericSP
CreateScriptedStopHook(lldb::TargetSP target_sp, const char *class_name,
StructuredDataImpl *args_data, Status &error) {
error.SetErrorString("Creating scripted stop-hooks with the current "
"script interpreter is not supported.");
return StructuredData::GenericSP();
}
// This dispatches to the handle_stop method of the stop-hook class. It
// returns a "should_stop" bool.
virtual bool
ScriptedStopHookHandleStop(StructuredData::GenericSP implementor_sp,
ExecutionContext &exc_ctx,
lldb::StreamSP stream_sp) {
return true;
}
virtual StructuredData::ObjectSP
LoadPluginModule(const FileSpec &file_spec, lldb_private::Status &error) {
return StructuredData::ObjectSP();
}
virtual StructuredData::DictionarySP
GetDynamicSettings(StructuredData::ObjectSP plugin_module_sp, Target *target,
const char *setting_name, lldb_private::Status &error) {
return StructuredData::DictionarySP();
}
virtual Status GenerateFunction(const char *signature,
const StringList &input) {
Status error;
error.SetErrorString("unimplemented");
return error;
}
virtual void CollectDataForBreakpointCommandCallback(
std::vector<std::reference_wrapper<BreakpointOptions>> &options,
CommandReturnObject &result);
virtual void
CollectDataForWatchpointCommandCallback(WatchpointOptions *wp_options,
CommandReturnObject &result);
/// Set the specified text as the callback for the breakpoint.
Status SetBreakpointCommandCallback(
std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
const char *callback_text);
virtual Status SetBreakpointCommandCallback(BreakpointOptions &bp_options,
const char *callback_text) {
Status error;
error.SetErrorString("unimplemented");
return error;
}
/// This one is for deserialization:
virtual Status SetBreakpointCommandCallback(
BreakpointOptions &bp_options,
std::unique_ptr<BreakpointOptions::CommandData> &data_up) {
Status error;
error.SetErrorString("unimplemented");
return error;
}
Status SetBreakpointCommandCallbackFunction(
std::vector<std::reference_wrapper<BreakpointOptions>> &bp_options_vec,
const char *function_name, StructuredData::ObjectSP extra_args_sp);
/// Set a script function as the callback for the breakpoint.
virtual Status
SetBreakpointCommandCallbackFunction(BreakpointOptions &bp_options,
const char *function_name,
StructuredData::ObjectSP extra_args_sp) {
Status error;
error.SetErrorString("unimplemented");
return error;
}
/// Set a one-liner as the callback for the watchpoint.
virtual void SetWatchpointCommandCallback(WatchpointOptions *wp_options,
const char *oneliner) {}
virtual bool GetScriptedSummary(const char *function_name,
lldb::ValueObjectSP valobj,
StructuredData::ObjectSP &callee_wrapper_sp,
const TypeSummaryOptions &options,
std::string &retval) {
return false;
}
virtual void Clear() {
// Clean up any ref counts to SBObjects that might be in global variables
}
virtual size_t
CalculateNumChildren(const StructuredData::ObjectSP &implementor,
uint32_t max) {
return 0;
}
virtual lldb::ValueObjectSP
GetChildAtIndex(const StructuredData::ObjectSP &implementor, uint32_t idx) {
return lldb::ValueObjectSP();
}
virtual int
GetIndexOfChildWithName(const StructuredData::ObjectSP &implementor,
const char *child_name) {
return UINT32_MAX;
}
virtual bool
UpdateSynthProviderInstance(const StructuredData::ObjectSP &implementor) {
return false;
}
virtual bool MightHaveChildrenSynthProviderInstance(
const StructuredData::ObjectSP &implementor) {
return true;
}
virtual lldb::ValueObjectSP
GetSyntheticValue(const StructuredData::ObjectSP &implementor) {
return nullptr;
}
virtual ConstString
GetSyntheticTypeName(const StructuredData::ObjectSP &implementor) {
return ConstString();
}
virtual bool
RunScriptBasedCommand(const char *impl_function, llvm::StringRef args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject &cmd_retobj,
Status &error,
const lldb_private::ExecutionContext &exe_ctx) {
return false;
}
virtual bool RunScriptBasedCommand(
StructuredData::GenericSP impl_obj_sp, llvm::StringRef args,
ScriptedCommandSynchronicity synchronicity,
lldb_private::CommandReturnObject &cmd_retobj, Status &error,
const lldb_private::ExecutionContext &exe_ctx) {
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function,
Process *process, std::string &output,
Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function, Thread *thread,
std::string &output, Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function, Target *target,
std::string &output, Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function,
StackFrame *frame, std::string &output,
Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool RunScriptFormatKeyword(const char *impl_function,
ValueObject *value, std::string &output,
Status &error) {
error.SetErrorString("unimplemented");
return false;
}
virtual bool GetDocumentationForItem(const char *item, std::string &dest) {
dest.clear();
return false;
}
virtual bool
GetShortHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
std::string &dest) {
dest.clear();
return false;
}
virtual uint32_t
GetFlagsForCommandObject(StructuredData::GenericSP cmd_obj_sp) {
return 0;
}
virtual bool GetLongHelpForCommandObject(StructuredData::GenericSP cmd_obj_sp,
std::string &dest) {
dest.clear();
return false;
}
virtual bool CheckObjectExists(const char *name) { return false; }
virtual bool
LoadScriptingModule(const char *filename, const LoadScriptOptions &options,
lldb_private::Status &error,
StructuredData::ObjectSP *module_sp = nullptr,
FileSpec extra_search_dir = {});
virtual bool IsReservedWord(const char *word) { return false; }
virtual std::unique_ptr<ScriptInterpreterLocker> AcquireInterpreterLock();
const char *GetScriptInterpreterPtyName();
virtual llvm::Expected<unsigned>
GetMaxPositionalArgumentsForCallable(const llvm::StringRef &callable_name) {
return llvm::createStringError(
llvm::inconvertibleErrorCode(), "Unimplemented function");
}
static std::string LanguageToString(lldb::ScriptLanguage language);
static lldb::ScriptLanguage StringToLanguage(const llvm::StringRef &string);
lldb::ScriptLanguage GetLanguage() { return m_script_lang; }
ScriptedProcessInterface &GetScriptedProcessInterface() {
return *m_scripted_process_interface_up;
}
lldb::DataExtractorSP
GetDataExtractorFromSBData(const lldb::SBData &data) const;
Status GetStatusFromSBError(const lldb::SBError &error) const;
protected:
Debugger &m_debugger;
lldb::ScriptLanguage m_script_lang;
lldb::ScriptedProcessInterfaceUP m_scripted_process_interface_up;
};
} // namespace lldb_private
#endif // LLDB_INTERPRETER_SCRIPTINTERPRETER_H