llvm-project/lldb/include/lldb/Interpreter/ScriptInterpreter.h
Jonas Devlieghere 00bb397b0d [lldb] Support Python imports relative the to the current file being sourced
Make it possible to use a relative path in command script import to the
location of the file being sourced. This allows the user to put Python
scripts next to LLDB command files and importing them without having to
specify an absolute path.

To enable this behavior pass `-c` to `command script import`. The
argument can only be used when sourcing the command from a file.

rdar://68310384

Differential revision: https://reviews.llvm.org/D89334
2020-10-27 09:20:45 -07:00

539 lines
17 KiB
C++

//===-- 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/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/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 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);
~ScriptInterpreter() override;
struct ExecuteScriptOptions {
public:
ExecuteScriptOptions()
: m_enable_io(true), m_set_lldb_globals(true), m_maskout_errors(true) {}
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;
bool m_set_lldb_globals;
bool m_maskout_errors;
};
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<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<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<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, bool init_session,
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; }
protected:
Debugger &m_debugger;
lldb::ScriptLanguage m_script_lang;
};
} // namespace lldb_private
#endif // LLDB_INTERPRETER_SCRIPTINTERPRETER_H