forked from OSchip/llvm-project
Python commands:
It is now possible to use 'command alias --python' to define a command name that actually triggers execution of a Python function (e.g. command alias --python foo foo_impl makes a command named 'foo' that runs Python function 'foo_impl') The Python function foo_impl should have as signature: def foo_impl(debugger, args, stream, dict): where debugger is an object wrapping an LLDB SBDebugger args is the command line arguments, as an unparsed Python string stream is an SBStream that represents the standard output dict is an internal utility parameter and should be left untouched The function should return None on no error, or an error string to describe any problems llvm-svn: 137722
This commit is contained in:
parent
5de2044f3d
commit
be93a35a8a
|
@ -43,6 +43,13 @@ public:
|
|||
typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name);
|
||||
typedef lldb::SBValue* (*SWIGPythonCastPyObjectToSBValue) (void* data);
|
||||
typedef void (*SWIGPythonUpdateSynthProviderInstance) (void* data);
|
||||
|
||||
typedef bool (*SWIGPythonCallCommand) (const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger,
|
||||
const char* args,
|
||||
std::string& err_msg,
|
||||
lldb::SBStream& stream);
|
||||
|
||||
typedef enum
|
||||
{
|
||||
|
@ -58,7 +65,8 @@ public:
|
|||
eLongLongUnsigned,
|
||||
eFloat,
|
||||
eDouble,
|
||||
eChar
|
||||
eChar,
|
||||
eCharStrOrNone,
|
||||
} ReturnType;
|
||||
|
||||
|
||||
|
@ -102,6 +110,12 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
GenerateScriptAliasFunction (StringList &input, StringList &output)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
GenerateTypeSynthClass (StringList &input, StringList &output)
|
||||
{
|
||||
|
@ -168,6 +182,15 @@ public:
|
|||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
RunScriptBasedCommand(const char* impl_function,
|
||||
const char* args,
|
||||
lldb::SBStream& stream,
|
||||
Error& error)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *
|
||||
GetScriptInterpreterPtyName ();
|
||||
|
@ -178,7 +201,7 @@ public:
|
|||
CommandInterpreter &
|
||||
GetCommandInterpreter ();
|
||||
|
||||
static std::string
|
||||
static std::string
|
||||
LanguageToString (lldb::ScriptLanguage language);
|
||||
|
||||
static void
|
||||
|
@ -190,7 +213,8 @@ public:
|
|||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider);
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command);
|
||||
|
||||
static void
|
||||
TerminateInterpreter ();
|
||||
|
|
|
@ -59,6 +59,9 @@ public:
|
|||
bool
|
||||
GenerateTypeScriptFunction (const char* oneliner, StringList &output);
|
||||
|
||||
virtual bool
|
||||
GenerateScriptAliasFunction (StringList &input, StringList &output);
|
||||
|
||||
void*
|
||||
CreateSyntheticScriptedProvider (std::string class_name,
|
||||
lldb::ValueObjectSP valobj);
|
||||
|
@ -78,6 +81,12 @@ public:
|
|||
virtual lldb::SBValue*
|
||||
CastPyObjectToSBValue (void* data);
|
||||
|
||||
virtual bool
|
||||
RunScriptBasedCommand(const char* impl_function,
|
||||
const char* args,
|
||||
lldb::SBStream& stream,
|
||||
Error& error);
|
||||
|
||||
bool
|
||||
GenerateFunction(std::string& signature, StringList &input, StringList &output);
|
||||
|
||||
|
@ -131,7 +140,8 @@ public:
|
|||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider);
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -405,6 +405,8 @@
|
|||
94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
|
||||
9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */; };
|
||||
9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */; };
|
||||
94A075BB13F9F58500D97961 /* CommandObjectPythonFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94A075B913F9F58500D97961 /* CommandObjectPythonFunction.cpp */; };
|
||||
94A075BC13F9F58500D97961 /* CommandObjectPythonFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 94A075BA13F9F58500D97961 /* CommandObjectPythonFunction.h */; };
|
||||
94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; };
|
||||
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
|
||||
|
@ -1174,6 +1176,8 @@
|
|||
9463D4CE13B179A500C230D4 /* CommandObjectType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectType.h; path = source/Commands/CommandObjectType.h; sourceTree = "<group>"; };
|
||||
9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeHierarchyNavigator.cpp; path = source/Symbol/TypeHierarchyNavigator.cpp; sourceTree = "<group>"; };
|
||||
9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = "<group>"; };
|
||||
94A075B913F9F58500D97961 /* CommandObjectPythonFunction.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectPythonFunction.cpp; path = source/Commands/CommandObjectPythonFunction.cpp; sourceTree = "<group>"; };
|
||||
94A075BA13F9F58500D97961 /* CommandObjectPythonFunction.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectPythonFunction.h; path = source/Commands/CommandObjectPythonFunction.h; sourceTree = "<group>"; };
|
||||
94A9112B13D5DEF80046D8A6 /* FormatClasses.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatClasses.h; path = include/lldb/Core/FormatClasses.h; sourceTree = "<group>"; };
|
||||
94A9112D13D5DF210046D8A6 /* FormatClasses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatClasses.cpp; path = source/Core/FormatClasses.cpp; sourceTree = "<group>"; };
|
||||
94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectSyntheticFilter.h; path = include/lldb/Core/ValueObjectSyntheticFilter.h; sourceTree = "<group>"; };
|
||||
|
@ -2123,6 +2127,8 @@
|
|||
26879CE71333F58B0012C1F8 /* CommandObjectPlatform.cpp */,
|
||||
26BC7D1F10F1B76300F91463 /* CommandObjectProcess.h */,
|
||||
26BC7E3810F1B84700F91463 /* CommandObjectProcess.cpp */,
|
||||
94A075BA13F9F58500D97961 /* CommandObjectPythonFunction.h */,
|
||||
94A075B913F9F58500D97961 /* CommandObjectPythonFunction.cpp */,
|
||||
26BC7D2010F1B76300F91463 /* CommandObjectQuit.h */,
|
||||
26BC7E3910F1B84700F91463 /* CommandObjectQuit.cpp */,
|
||||
26BC7D2210F1B76300F91463 /* CommandObjectRegister.h */,
|
||||
|
@ -2658,6 +2664,7 @@
|
|||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
94A075BC13F9F58500D97961 /* CommandObjectPythonFunction.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3250,6 +3257,7 @@
|
|||
26D7E45D13D5E30A007FD12B /* SocketAddress.cpp in Sources */,
|
||||
B271B11413D6139300C3FEDB /* FormatClasses.cpp in Sources */,
|
||||
94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */,
|
||||
94A075BB13F9F58500D97961 /* CommandObjectPythonFunction.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -582,4 +582,144 @@ LLDBSWIGPython_CastPyObjectToSBValue
|
|||
return sb_ptr;
|
||||
}
|
||||
|
||||
SWIGEXPORT bool
|
||||
LLDBSwigPythonCallCommand
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger,
|
||||
const char* args,
|
||||
std::string& err_msg,
|
||||
lldb::SBStream& stream
|
||||
)
|
||||
{
|
||||
|
||||
bool retval = false;
|
||||
|
||||
PyObject *DebuggerObj_PyObj = SWIG_NewPointerObj((void *) &debugger, SWIGTYPE_p_lldb__SBDebugger, 0);
|
||||
PyObject *StreamObj_PyObj = SWIG_NewPointerObj((void *) &stream, SWIGTYPE_p_lldb__SBStream, 0);
|
||||
|
||||
if (DebuggerObj_PyObj == NULL)
|
||||
return retval;
|
||||
|
||||
if (StreamObj_PyObj == NULL)
|
||||
return retval;
|
||||
|
||||
if (!python_function_name || !session_dictionary_name)
|
||||
return retval;
|
||||
|
||||
PyObject *pmodule, *main_dict, *session_dict, *pfunc;
|
||||
PyObject *pargs, *pvalue;
|
||||
|
||||
pmodule = PyImport_AddModule ("__main__");
|
||||
if (pmodule != NULL)
|
||||
{
|
||||
main_dict = PyModule_GetDict (pmodule);
|
||||
if (main_dict != NULL)
|
||||
{
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t pos = 0;
|
||||
|
||||
// Find the current session's dictionary in the main module's dictionary.
|
||||
|
||||
if (PyDict_Check (main_dict))
|
||||
{
|
||||
session_dict = NULL;
|
||||
while (PyDict_Next (main_dict, &pos, &key, &value))
|
||||
{
|
||||
// We have stolen references to the key and value objects in the dictionary; we need to increment
|
||||
// them now so that Python's garbage collector doesn't collect them out from under us.
|
||||
Py_INCREF (key);
|
||||
Py_INCREF (value);
|
||||
if (strcmp (PyString_AsString (key), session_dictionary_name) == 0)
|
||||
{
|
||||
session_dict = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!session_dict || !PyDict_Check (session_dict))
|
||||
return retval;
|
||||
|
||||
// Find the function we need to call in the current session's dictionary.
|
||||
|
||||
pos = 0;
|
||||
pfunc = NULL;
|
||||
while (PyDict_Next (session_dict, &pos, &key, &value))
|
||||
{
|
||||
if (PyString_Check (key))
|
||||
{
|
||||
// We have stolen references to the key and value objects in the dictionary; we need to increment
|
||||
// them now so that Python's garbage collector doesn't collect them out from under us.
|
||||
Py_INCREF (key);
|
||||
Py_INCREF (value);
|
||||
if (strcmp (PyString_AsString (key), python_function_name) == 0)
|
||||
{
|
||||
pfunc = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the arguments and call the function.
|
||||
|
||||
if (pfunc && PyCallable_Check (pfunc))
|
||||
{
|
||||
pargs = PyTuple_New (4);
|
||||
if (pargs == NULL)
|
||||
{
|
||||
if (PyErr_Occurred())
|
||||
PyErr_Clear();
|
||||
return retval;
|
||||
}
|
||||
|
||||
PyTuple_SetItem (pargs, 0, DebuggerObj_PyObj); // This "steals" a reference to DebuggerObj_PyObj
|
||||
PyTuple_SetItem (pargs, 1, PyString_FromString(args));
|
||||
PyTuple_SetItem (pargs, 2, StreamObj_PyObj); // This "steals" a reference to StreamObj_PyObj
|
||||
PyTuple_SetItem (pargs, 3, session_dict); // This "steals" a reference to session_dict
|
||||
pvalue = PyObject_CallObject (pfunc, pargs);
|
||||
Py_DECREF (pargs);
|
||||
|
||||
if (pvalue != NULL)
|
||||
{
|
||||
if (pvalue == Py_None) // no error
|
||||
{
|
||||
err_msg.clear();
|
||||
retval = true;
|
||||
}
|
||||
else // return value is an error string
|
||||
{
|
||||
err_msg.assign(PyString_AsString(pvalue));
|
||||
retval = false;
|
||||
}
|
||||
Py_DECREF (pvalue);
|
||||
}
|
||||
else if (PyErr_Occurred ())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
Py_INCREF (session_dict);
|
||||
}
|
||||
else if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
else if (PyErr_Occurred())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
else if (PyErr_Occurred ())
|
||||
{
|
||||
PyErr_Print();
|
||||
PyErr_Clear ();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
%}
|
||||
|
|
|
@ -337,6 +337,17 @@ extern "C" int LLDBSwigPython_GetIndexOfChildWithName (void *impl
|
|||
extern "C" lldb::SBValue* LLDBSWIGPython_CastPyObjectToSBValue (void* data);
|
||||
extern "C" void LLDBSwigPython_UpdateSynthProviderInstance (void* implementor);
|
||||
|
||||
extern "C" bool LLDBSwigPythonCallCommand
|
||||
(
|
||||
const char *python_function_name,
|
||||
const char *session_dictionary_name,
|
||||
lldb::DebuggerSP& debugger,
|
||||
const char* args,
|
||||
std::string& err_msg,
|
||||
lldb::SBStream& stream
|
||||
);
|
||||
|
||||
|
||||
extern "C" void init_lldb(void);
|
||||
|
||||
void
|
||||
|
@ -354,6 +365,7 @@ SBCommandInterpreter::InitializeSWIG ()
|
|||
LLDBSwigPython_GetChildAtIndex,
|
||||
LLDBSwigPython_GetIndexOfChildWithName,
|
||||
LLDBSWIGPython_CastPyObjectToSBValue,
|
||||
LLDBSwigPython_UpdateSynthProviderInstance);
|
||||
LLDBSwigPython_UpdateSynthProviderInstance,
|
||||
LLDBSwigPythonCallCommand);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,8 +15,11 @@
|
|||
#include "llvm/ADT/StringRef.h"
|
||||
|
||||
// Project includes
|
||||
#include "CommandObjectPythonFunction.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/InputReader.h"
|
||||
#include "lldb/Core/InputReaderEZ.h"
|
||||
#include "lldb/Core/StringList.h"
|
||||
#include "lldb/Interpreter/Args.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandObjectRegexCommand.h"
|
||||
|
@ -306,8 +309,131 @@ CommandObjectCommandsSource::CommandOptions::g_option_table[] =
|
|||
// CommandObjectCommandsAlias
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
static const char *g_python_command_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
|
||||
"You must define a Python function with this signature:\n"
|
||||
"def my_command_impl(debugger, args, stream, dict):";
|
||||
|
||||
|
||||
class CommandObjectCommandsAlias : public CommandObject
|
||||
{
|
||||
|
||||
class PythonAliasReader : public InputReaderEZ
|
||||
{
|
||||
private:
|
||||
CommandInterpreter& m_interpreter;
|
||||
std::string m_cmd_name;
|
||||
StringList m_user_input;
|
||||
DISALLOW_COPY_AND_ASSIGN (PythonAliasReader);
|
||||
public:
|
||||
PythonAliasReader(Debugger& debugger,
|
||||
CommandInterpreter& interpreter,
|
||||
std::string cmd_name) :
|
||||
InputReaderEZ(debugger),
|
||||
m_interpreter(interpreter),
|
||||
m_cmd_name(cmd_name),
|
||||
m_user_input()
|
||||
{}
|
||||
|
||||
virtual
|
||||
~PythonAliasReader()
|
||||
{
|
||||
}
|
||||
|
||||
virtual void ActivateHandler(HandlerData& data)
|
||||
{
|
||||
StreamSP out_stream = data.GetOutStream();
|
||||
bool batch_mode = data.GetBatchMode();
|
||||
if (!batch_mode)
|
||||
{
|
||||
out_stream->Printf ("%s\n", g_python_command_instructions);
|
||||
if (data.reader.GetPrompt())
|
||||
out_stream->Printf ("%s", data.reader.GetPrompt());
|
||||
out_stream->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void ReactivateHandler(HandlerData& data)
|
||||
{
|
||||
StreamSP out_stream = data.GetOutStream();
|
||||
bool batch_mode = data.GetBatchMode();
|
||||
if (data.reader.GetPrompt() && !batch_mode)
|
||||
{
|
||||
out_stream->Printf ("%s", data.reader.GetPrompt());
|
||||
out_stream->Flush();
|
||||
}
|
||||
}
|
||||
virtual void GotTokenHandler(HandlerData& data)
|
||||
{
|
||||
StreamSP out_stream = data.GetOutStream();
|
||||
bool batch_mode = data.GetBatchMode();
|
||||
if (data.bytes && data.bytes_len)
|
||||
{
|
||||
m_user_input.AppendString(data.bytes, data.bytes_len);
|
||||
}
|
||||
if (!data.reader.IsDone() && data.reader.GetPrompt() && !batch_mode)
|
||||
{
|
||||
out_stream->Printf ("%s", data.reader.GetPrompt());
|
||||
out_stream->Flush();
|
||||
}
|
||||
}
|
||||
virtual void InterruptHandler(HandlerData& data)
|
||||
{
|
||||
StreamSP out_stream = data.GetOutStream();
|
||||
bool batch_mode = data.GetBatchMode();
|
||||
data.reader.SetIsDone (true);
|
||||
if (!batch_mode)
|
||||
{
|
||||
out_stream->Printf ("Warning: No command attached to breakpoint.\n");
|
||||
out_stream->Flush();
|
||||
}
|
||||
}
|
||||
virtual void EOFHandler(HandlerData& data)
|
||||
{
|
||||
data.reader.SetIsDone (true);
|
||||
}
|
||||
virtual void DoneHandler(HandlerData& data)
|
||||
{
|
||||
StreamSP out_stream = data.GetOutStream();
|
||||
|
||||
ScriptInterpreter *interpreter = data.reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
|
||||
if (!interpreter)
|
||||
{
|
||||
out_stream->Printf ("Internal error #1: no script attached.\n");
|
||||
out_stream->Flush();
|
||||
return;
|
||||
}
|
||||
StringList funct_name_sl;
|
||||
if (!interpreter->GenerateScriptAliasFunction (m_user_input,
|
||||
funct_name_sl))
|
||||
{
|
||||
out_stream->Printf ("Internal error #2: no script attached.\n");
|
||||
out_stream->Flush();
|
||||
return;
|
||||
}
|
||||
if (funct_name_sl.GetSize() == 0)
|
||||
{
|
||||
out_stream->Printf ("Internal error #3: no script attached.\n");
|
||||
out_stream->Flush();
|
||||
return;
|
||||
}
|
||||
const char *funct_name = funct_name_sl.GetStringAtIndex(0);
|
||||
if (!funct_name || !funct_name[0])
|
||||
{
|
||||
out_stream->Printf ("Internal error #4: no script attached.\n");
|
||||
out_stream->Flush();
|
||||
return;
|
||||
}
|
||||
|
||||
// everything should be fine now, let's add this alias
|
||||
|
||||
CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(m_interpreter,
|
||||
m_cmd_name,
|
||||
funct_name));
|
||||
|
||||
m_interpreter.AddAlias(m_cmd_name.c_str(), command_obj_sp);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
CommandObjectCommandsAlias (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
|
@ -425,6 +551,98 @@ public:
|
|||
// Get the alias command.
|
||||
|
||||
const std::string alias_command = args.GetArgumentAtIndex (0);
|
||||
|
||||
if (
|
||||
(strcmp("--python",alias_command.c_str()) == 0) ||
|
||||
(strcmp("-P",alias_command.c_str()) == 0)
|
||||
)
|
||||
{
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
// this is a definition of the form
|
||||
// command alias --python foo_cmd
|
||||
// and the user will type foo_cmd_impl by hand
|
||||
std::string cmd_name = args.GetArgumentAtIndex(1);
|
||||
// Verify that the command is alias-able.
|
||||
if (m_interpreter.CommandExists (cmd_name.c_str()))
|
||||
{
|
||||
result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
|
||||
cmd_name.c_str());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
if (m_interpreter.AliasExists (cmd_name.c_str())
|
||||
|| m_interpreter.UserCommandExists (cmd_name.c_str()))
|
||||
{
|
||||
result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
|
||||
cmd_name.c_str());
|
||||
}
|
||||
|
||||
|
||||
InputReaderSP reader_sp (new PythonAliasReader (m_interpreter.GetDebugger(),
|
||||
m_interpreter,
|
||||
cmd_name));
|
||||
|
||||
if (reader_sp)
|
||||
{
|
||||
|
||||
InputReaderEZ::InitializationParameters ipr;
|
||||
|
||||
Error err (reader_sp->Initialize (ipr.SetBaton(NULL).SetPrompt(" ")));
|
||||
if (err.Success())
|
||||
{
|
||||
m_interpreter.GetDebugger().PushInputReader (reader_sp);
|
||||
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendError (err.AsCString());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendError("out of memory");
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
}
|
||||
|
||||
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is a definition of the form
|
||||
// command alias --python foo_cmd funct_impl_foo
|
||||
std::string cmd_name = args.GetArgumentAtIndex(1);
|
||||
std::string funct_name = args.GetArgumentAtIndex(2);
|
||||
|
||||
// Verify that the command is alias-able.
|
||||
if (m_interpreter.CommandExists (cmd_name.c_str()))
|
||||
{
|
||||
result.AppendErrorWithFormat ("'%s' is a permanent debugger command and cannot be redefined.\n",
|
||||
cmd_name.c_str());
|
||||
result.SetStatus (eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
CommandObjectSP command_obj_sp(new CommandObjectPythonFunction(m_interpreter,
|
||||
cmd_name,
|
||||
funct_name));
|
||||
|
||||
if (m_interpreter.AliasExists (cmd_name.c_str())
|
||||
|| m_interpreter.UserCommandExists (cmd_name.c_str()))
|
||||
{
|
||||
result.AppendWarningWithFormat ("Overwriting existing definition for '%s'.\n",
|
||||
cmd_name.c_str());
|
||||
}
|
||||
|
||||
m_interpreter.AddAlias(cmd_name.c_str(), command_obj_sp);
|
||||
|
||||
result.SetStatus (eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
}
|
||||
|
||||
// Strip the new alias name off 'raw_command_string' (leave it on args, which gets passed to 'Execute', which
|
||||
// does the stripping itself.
|
||||
|
|
|
@ -0,0 +1,88 @@
|
|||
//===-- CommandObjectPythonFunction.cpp --------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "CommandObjectPythonFunction.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
|
||||
#include "lldb/API/SBStream.h"
|
||||
|
||||
#include "lldb/Core/Debugger.h"
|
||||
|
||||
#include "lldb/Interpreter/Args.h"
|
||||
#include "lldb/Interpreter/Options.h"
|
||||
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
|
||||
#include "lldb/Interpreter/ScriptInterpreter.h"
|
||||
#include "lldb/Interpreter/ScriptInterpreterPython.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectApropos
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
CommandObjectPythonFunction::CommandObjectPythonFunction (CommandInterpreter &interpreter,
|
||||
std::string name,
|
||||
std::string funct) :
|
||||
CommandObject (interpreter,
|
||||
name.c_str(),
|
||||
(std::string("Run Python function ") + funct).c_str(),
|
||||
NULL),
|
||||
m_function_name(funct)
|
||||
{
|
||||
CommandArgumentEntry arg;
|
||||
CommandArgumentData search_word_arg;
|
||||
|
||||
// Define the first (and only) variant of this arg.
|
||||
search_word_arg.arg_type = eArgTypeSearchWord;
|
||||
search_word_arg.arg_repetition = eArgRepeatPlain;
|
||||
|
||||
// There is only one variant this argument could be; put it into the argument entry.
|
||||
arg.push_back (search_word_arg);
|
||||
|
||||
// Push the data for the first argument into the m_arguments vector.
|
||||
m_arguments.push_back (arg);
|
||||
}
|
||||
|
||||
CommandObjectPythonFunction::~CommandObjectPythonFunction()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectPythonFunction::ExecuteRawCommandString (const char *raw_command_line,
|
||||
CommandReturnObject &result)
|
||||
{
|
||||
ScriptInterpreter* scripter = m_interpreter.GetScriptInterpreter();
|
||||
|
||||
Error error;
|
||||
|
||||
lldb::SBStream stream;
|
||||
|
||||
if (scripter->RunScriptBasedCommand(m_function_name.c_str(),
|
||||
raw_command_line,
|
||||
stream,
|
||||
error) == false)
|
||||
{
|
||||
result.AppendError(error.AsCString());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
}
|
||||
else
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
|
||||
result.GetOutputStream() << stream.GetData();
|
||||
|
||||
return result.Succeeded();
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//===-- CommandObjectPythonFunction.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_CommandObjectPythonFunction_h_
|
||||
#define liblldb_CommandObjectPythonFunction_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Interpreter/CommandObject.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectApropos
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class CommandObjectPythonFunction : public CommandObject
|
||||
{
|
||||
private:
|
||||
std::string m_function_name;
|
||||
|
||||
public:
|
||||
|
||||
CommandObjectPythonFunction (CommandInterpreter &interpreter,
|
||||
std::string name,
|
||||
std::string funct);
|
||||
|
||||
virtual
|
||||
~CommandObjectPythonFunction ();
|
||||
|
||||
virtual bool
|
||||
ExecuteRawCommandString (const char *raw_command_line, CommandReturnObject &result);
|
||||
|
||||
virtual bool
|
||||
WantsRawCommandString ()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Execute (Args& command,
|
||||
CommandReturnObject &result)
|
||||
{
|
||||
std::string cmd_string;
|
||||
command.GetCommandString(cmd_string);
|
||||
return ExecuteRawCommandString(cmd_string.c_str(), result);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_CommandObjectPythonFunction_h_
|
|
@ -99,7 +99,8 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
|
|||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider)
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command)
|
||||
{
|
||||
ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback,
|
||||
python_swig_breakpoint_callback,
|
||||
|
@ -109,7 +110,8 @@ ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_call
|
|||
python_swig_get_child_index,
|
||||
python_swig_get_index_child,
|
||||
python_swig_cast_to_sbvalue,
|
||||
python_swig_update_provider);
|
||||
python_swig_update_provider,
|
||||
python_swig_call_command);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -41,6 +41,7 @@ static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NUL
|
|||
static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL;
|
||||
static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL;
|
||||
static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL;
|
||||
static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
|
||||
|
||||
static int
|
||||
_check_and_flush (FILE *stream)
|
||||
|
@ -765,6 +766,12 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
|
|||
success = PyArg_Parse (py_return, format, (char **) &ret_value);
|
||||
break;
|
||||
}
|
||||
case eCharStrOrNone: // char* or NULL if py_return == Py_None
|
||||
{
|
||||
const char format[3] = "z";
|
||||
success = PyArg_Parse (py_return, format, (char **) &ret_value);
|
||||
break;
|
||||
}
|
||||
case eBool:
|
||||
{
|
||||
const char format[2] = "b";
|
||||
|
@ -1250,6 +1257,70 @@ ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, Str
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, StringList &output)
|
||||
{
|
||||
static int num_created_functions = 0;
|
||||
user_input.RemoveBlankLines ();
|
||||
int num_lines = user_input.GetSize ();
|
||||
StreamString sstr;
|
||||
|
||||
// Check to see if we have any data; if not, just return.
|
||||
if (user_input.GetSize() == 0)
|
||||
return false;
|
||||
|
||||
// Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
|
||||
// ValueObject as parameter to the function.
|
||||
|
||||
sstr.Printf ("lldb_autogen_python_cmd_alias_func_%d", num_created_functions);
|
||||
++num_created_functions;
|
||||
std::string auto_generated_function_name = sstr.GetData();
|
||||
|
||||
sstr.Clear();
|
||||
StringList auto_generated_function;
|
||||
|
||||
// Create the function name & definition string.
|
||||
|
||||
sstr.Printf ("def %s (debugger, args, dict):", auto_generated_function_name.c_str());
|
||||
auto_generated_function.AppendString (sstr.GetData());
|
||||
|
||||
// Pre-pend code for setting up the session dictionary.
|
||||
|
||||
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
||||
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
||||
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
||||
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
||||
// global dictionary.
|
||||
|
||||
// Wrap everything up inside the function, increasing the indentation.
|
||||
|
||||
for (int i = 0; i < num_lines; ++i)
|
||||
{
|
||||
sstr.Clear ();
|
||||
sstr.Printf (" %s", user_input.GetStringAtIndex (i));
|
||||
auto_generated_function.AppendString (sstr.GetData());
|
||||
}
|
||||
|
||||
// Append code to clean up the global dictionary and update the session dictionary (all updates in the function
|
||||
// got written to the values in the global dictionary, not the session dictionary).
|
||||
|
||||
auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
|
||||
auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
|
||||
auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
|
||||
auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
|
||||
|
||||
// Verify that the results are valid Python.
|
||||
|
||||
if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
||||
return false;
|
||||
|
||||
// Store the name of the auto-generated function to be called.
|
||||
|
||||
output.AppendString (auto_generated_function_name.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, StringList &output)
|
||||
{
|
||||
|
@ -1835,6 +1906,72 @@ ScriptInterpreterPython::CastPyObjectToSBValue (void* data)
|
|||
return ret_val;
|
||||
}
|
||||
|
||||
bool
|
||||
ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
|
||||
const char* args,
|
||||
lldb::SBStream& stream,
|
||||
Error& error)
|
||||
{
|
||||
if (!impl_function)
|
||||
{
|
||||
error.SetErrorString("no function to execute");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!g_swig_call_command)
|
||||
{
|
||||
error.SetErrorString("no helper function to run scripted commands");
|
||||
return false;
|
||||
}
|
||||
|
||||
ScriptInterpreterPython *python_interpreter = this;
|
||||
|
||||
lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().GetSP();
|
||||
|
||||
bool ret_val;
|
||||
|
||||
std::string err_msg;
|
||||
|
||||
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
|
||||
if (CurrentThreadHasPythonLock())
|
||||
{
|
||||
python_interpreter->EnterSession ();
|
||||
ret_val = g_swig_call_command (impl_function,
|
||||
python_interpreter->m_dictionary_name.c_str(),
|
||||
debugger_sp,
|
||||
args,
|
||||
err_msg,
|
||||
stream);
|
||||
python_interpreter->LeaveSession ();
|
||||
}
|
||||
else
|
||||
{
|
||||
while (!GetPythonLock (1))
|
||||
fprintf (tmp_fh,
|
||||
"Python interpreter locked on another thread; waiting to acquire lock...\n");
|
||||
python_interpreter->EnterSession ();
|
||||
ret_val = g_swig_call_command (impl_function,
|
||||
python_interpreter->m_dictionary_name.c_str(),
|
||||
debugger_sp,
|
||||
args,
|
||||
err_msg,
|
||||
stream);
|
||||
python_interpreter->LeaveSession ();
|
||||
ReleasePythonLock ();
|
||||
}
|
||||
|
||||
if (!ret_val)
|
||||
error.SetErrorString(err_msg.c_str());
|
||||
else
|
||||
error.Clear();
|
||||
|
||||
return ret_val;
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
||||
|
@ -1845,7 +1982,8 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_ini
|
|||
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
||||
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
||||
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider)
|
||||
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
||||
SWIGPythonCallCommand python_swig_call_command)
|
||||
{
|
||||
g_swig_init_callback = python_swig_init_callback;
|
||||
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
|
||||
|
@ -1856,6 +1994,7 @@ ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_ini
|
|||
g_swig_get_index_child = python_swig_get_index_child;
|
||||
g_swig_cast_to_sbvalue = python_swig_cast_to_sbvalue;
|
||||
g_swig_update_provider = python_swig_update_provider;
|
||||
g_swig_call_command = python_swig_call_command;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -130,6 +130,30 @@ class AliasTestCase(TestBase):
|
|||
substrs = [ "use of undeclared identifier 'f'",
|
||||
"1 errors parsing expression" ])
|
||||
|
||||
self.runCmd("command source py_import")
|
||||
|
||||
self.expect('welcome Enrico',
|
||||
substrs = ['Hello Enrico, welcome to LLDB']);
|
||||
|
||||
self.runCmd("command unalias welcome");
|
||||
|
||||
self.expect('welcome Enrico', matching=False, error=True,
|
||||
substrs = ['Hello Enrico, welcome to LLDB']);
|
||||
|
||||
self.expect('targetname',
|
||||
substrs = ['a.out'])
|
||||
|
||||
self.expect('targetname fail', error=True,
|
||||
substrs = ['a test for error in command'])
|
||||
|
||||
self.expect('help',
|
||||
substrs = ['targetname',
|
||||
'Run Python function target_name_impl'])
|
||||
|
||||
self.expect("help targetname",
|
||||
substrs = ['Run Python function target_name_imp',
|
||||
'This command takes \'raw\' input',
|
||||
'quote stuff'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
script import sys, os
|
||||
script sys.path.append(os.path.join(os.getcwd(), os.pardir))
|
||||
script from welcome import *
|
||||
command alias --python welcome welcome_impl
|
||||
command alias --python targetname target_name_impl
|
|
@ -0,0 +1,14 @@
|
|||
import sys
|
||||
|
||||
def welcome_impl(debugger, args, stream, dict):
|
||||
stream.Printf('Hello ' + args + ', welcome to LLDB');
|
||||
return None;
|
||||
|
||||
def target_name_impl(debugger, args, stream, dict):
|
||||
target = debugger.GetSelectedTarget()
|
||||
file = target.GetExecutable()
|
||||
stream.Printf('Current target ' + file.GetFilename())
|
||||
if args == 'fail':
|
||||
return 'a test for error in command'
|
||||
else:
|
||||
return None
|
Loading…
Reference in New Issue