<rdar://problem/12491420>

Added a new setting that allows a python OS plug-in to detect threads and provide registers for memory threads. To enable this you set the setting:

settings set target.process.python-os-plugin-path lldb/examples/python/operating_system.py

Then run your program and see the extra threads. 

llvm-svn: 166244
This commit is contained in:
Greg Clayton 2012-10-18 22:40:37 +00:00
parent ed8560b09c
commit c9d645d306
11 changed files with 109 additions and 37 deletions

View File

@ -3,7 +3,7 @@
import lldb
import struct
class PlugIn(object):
class OperatingSystemPlugIn(object):
"""Class that provides data for an instance of a LLDB 'OperatingSystemPython' plug-in class"""
def __init__(self, process):

View File

@ -127,19 +127,28 @@ public:
virtual ~ScriptInterpreter ();
virtual bool
ExecuteOneLine (const char *command, CommandReturnObject *result, bool enable_io) = 0;
ExecuteOneLine (const char *command,
CommandReturnObject *result,
bool enable_io,
bool set_lldb_globals = true) = 0;
virtual void
ExecuteInterpreterLoop () = 0;
virtual bool
ExecuteOneLineWithReturn (const char *in_string, ScriptReturnType return_type, void *ret_value, bool enable_io)
ExecuteOneLineWithReturn (const char *in_string,
ScriptReturnType return_type,
void *ret_value,
bool enable_io,
bool set_lldb_globals = true)
{
return true;
}
virtual bool
ExecuteMultipleLines (const char *in_string, bool enable_io)
ExecuteMultipleLines (const char *in_string,
bool enable_io,
bool set_lldb_globals = true)
{
return true;
}
@ -308,6 +317,7 @@ public:
virtual bool
LoadScriptingModule (const char* filename,
bool can_reload,
bool init_session,
lldb_private::Error& error)
{
error.SetErrorString("loading unimplemented");

View File

@ -23,7 +23,7 @@ public:
~ScriptInterpreterNone ();
bool
ExecuteOneLine (const char *command, CommandReturnObject *result, bool enable_io);
ExecuteOneLine (const char *command, CommandReturnObject *result, bool enable_io, bool set_lldb_globals = true);
void
ExecuteInterpreterLoop ();

View File

@ -39,7 +39,10 @@ public:
~ScriptInterpreterPython ();
bool
ExecuteOneLine (const char *command, CommandReturnObject *result, bool enable_io);
ExecuteOneLine (const char *command,
CommandReturnObject *result,
bool enable_io,
bool set_lldb_globals = true);
void
ExecuteInterpreterLoop ();
@ -48,10 +51,13 @@ public:
ExecuteOneLineWithReturn (const char *in_string,
ScriptInterpreter::ScriptReturnType return_type,
void *ret_value,
bool enable_io);
bool enable_io,
bool set_lldb_globals = true);
bool
ExecuteMultipleLines (const char *in_string, bool enable_io);
ExecuteMultipleLines (const char *in_string,
bool enable_io,
bool set_lldb_globals = true);
bool
ExportFunctionDefinitionToInterpreter (StringList &function_def);
@ -155,6 +161,7 @@ public:
virtual bool
LoadScriptingModule (const char* filename,
bool can_reload,
bool init_session,
lldb_private::Error& error);
virtual lldb::ScriptInterpreterObjectSP

View File

@ -67,6 +67,12 @@ public:
void
SetExtraStartupCommands (const Args &args);
FileSpec
GetPythonOSPluginPath () const;
void
SetPythonOSPluginPath (const FileSpec &file);
};
typedef STD_SHARED_PTR(ProcessProperties) ProcessPropertiesSP;

View File

@ -1394,8 +1394,10 @@ protected:
std::string path = command.GetArgumentAtIndex(0);
Error error;
const bool init_session = true;
if (m_interpreter.GetScriptInterpreter()->LoadScriptingModule(path.c_str(),
m_options.m_allow_reload,
init_session,
error))
{
result.SetStatus (eReturnStatusSuccessFinishNoResult);

View File

@ -26,7 +26,7 @@ ScriptInterpreterNone::~ScriptInterpreterNone ()
}
bool
ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, bool enable_io)
ScriptInterpreterNone::ExecuteOneLine (const char *command, CommandReturnObject *, bool enable_io, bool set_lldb_globals)
{
m_interpreter.GetDebugger().GetErrorStream().PutCString ("error: there is no embedded script interpreter in this mode.\n");
return false;

View File

@ -721,7 +721,7 @@ GenerateUniqueName (const char* base_name_wanted,
}
bool
ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, bool enable_io)
ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result, bool enable_io, bool set_lldb_globals)
{
if (!m_valid_session)
return false;
@ -732,8 +732,8 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
// method to pass the command string directly down to Python.
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
ScriptInterpreterPython::Locker::AcquireLock | (set_lldb_globals ? ScriptInterpreterPython::Locker::InitSession : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | (set_lldb_globals ? ScriptInterpreterPython::Locker::TearDownSession : 0));
bool success = false;
@ -1000,12 +1000,13 @@ bool
ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
ScriptInterpreter::ScriptReturnType return_type,
void *ret_value,
bool enable_io)
bool enable_io,
bool set_lldb_globals)
{
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
ScriptInterpreterPython::Locker::AcquireLock | (set_lldb_globals ? ScriptInterpreterPython::Locker::InitSession : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | (set_lldb_globals ? ScriptInterpreterPython::Locker::TearDownSession : 0));
PyObject *py_return = NULL;
PyObject *mainmod = PyImport_AddModule ("__main__");
@ -1165,13 +1166,13 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
}
bool
ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, bool enable_io)
ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, bool enable_io, bool set_lldb_globals)
{
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
ScriptInterpreterPython::Locker::AcquireLock | (set_lldb_globals ? ScriptInterpreterPython::Locker::InitSession : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | (set_lldb_globals ? ScriptInterpreterPython::Locker::TearDownSession : 0));
bool success = false;
PyObject *py_return = NULL;
@ -2373,6 +2374,7 @@ ScriptInterpreterPython::UpdateSynthProviderInstance (const lldb::ScriptInterpre
bool
ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
bool can_reload,
bool init_lldb_globals,
lldb_private::Error& error)
{
if (!pathname || !pathname[0])
@ -2404,14 +2406,16 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
std::string basename(target_file.GetFilename().GetCString());
// Before executing Pyton code, lock the GIL.
Locker py_lock(this);
Locker py_lock (this,
Locker::AcquireLock | (init_lldb_globals ? Locker::InitSession : 0),
Locker::FreeAcquiredLock | (init_lldb_globals ? Locker::TearDownSession : 0));
// now make sure that Python has "directory" in the search path
StreamString command_stream;
command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.append('%s');\n\n",
directory,
directory);
bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), false);
bool syspath_retval = ExecuteMultipleLines(command_stream.GetData(), false, false);
if (!syspath_retval)
{
error.SetErrorString("Python sys.path handling failed");
@ -2432,7 +2436,10 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
// this call will fail if the module does not exist (because the parameter to it is not a string
// but an actual Python module object, which is non-existant if the module was not imported before)
bool was_imported = (ExecuteOneLineWithReturn(command_stream.GetData(),
ScriptInterpreterPython::eScriptReturnTypeInt, &refcount, false) && refcount > 0);
ScriptInterpreterPython::eScriptReturnTypeInt,
&refcount,
false,
false) && refcount > 0);
if (was_imported == true && can_reload == false)
{
error.SetErrorString("module already imported");
@ -2442,7 +2449,7 @@ ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
// now actually do the import
command_stream.Clear();
command_stream.Printf("import %s",basename.c_str());
bool import_retval = ExecuteOneLine(command_stream.GetData(), NULL, false);
bool import_retval = ExecuteOneLine(command_stream.GetData(), NULL, false, false);
if (!import_retval)
{
error.SetErrorString("Python import statement failed");

View File

@ -55,8 +55,13 @@ OperatingSystem *
OperatingSystemPython::CreateInstance (Process *process, bool force)
{
// Python OperatingSystem plug-ins must be requested by name, so force must be true
if (force)
return new OperatingSystemPython (process);
FileSpec python_os_plugin_spec (process->GetPythonOSPluginPath());
if (python_os_plugin_spec && python_os_plugin_spec.Exists())
{
std::auto_ptr<OperatingSystemPython> os_ap (new OperatingSystemPython (process, python_os_plugin_spec));
if (os_ap.get() && os_ap->IsValid())
return os_ap.release();
}
return NULL;
}
@ -74,12 +79,12 @@ OperatingSystemPython::GetPluginDescriptionStatic()
}
OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process) :
OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process, const FileSpec &python_module_path) :
OperatingSystem (process),
m_thread_list_valobj_sp (),
m_register_info_ap (),
m_interpreter(NULL),
m_python_object(NULL)
m_interpreter (NULL),
m_python_object (NULL)
{
if (!process)
return;
@ -89,13 +94,27 @@ OperatingSystemPython::OperatingSystemPython (lldb_private::Process *process) :
m_interpreter = target_sp->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
if (m_interpreter)
{
// TODO: hardcoded is not good
auto object_sp = m_interpreter->CreateOSPlugin("operating_system.PlugIn",process->CalculateProcess());
if (object_sp)
std::string os_plugin_class_name (python_module_path.GetFilename().AsCString(""));
if (!os_plugin_class_name.empty())
{
m_python_object = object_sp->GetObject();
//GetDynamicRegisterInfo (); // COMMENT THIS LINE OUT PRIOR TO CHECKIN!!!
const bool init_session = false;
const bool allow_reload = true;
char python_module_path_cstr[PATH_MAX];
python_module_path.GetPath(python_module_path_cstr, sizeof(python_module_path_cstr));
Error error;
if (m_interpreter->LoadScriptingModule (python_module_path_cstr, allow_reload, init_session, error))
{
// Strip the ".py" extension if there is one
size_t py_extension_pos = os_plugin_class_name.rfind(".py");
if (py_extension_pos != std::string::npos)
os_plugin_class_name.erase (py_extension_pos);
// Add ".OperatingSystemPlugIn" to the module name to get a string like "modulename.OperatingSystemPlugIn"
os_plugin_class_name += ".OperatingSystemPlugIn";
auto object_sp = m_interpreter->CreateOSPlugin(os_plugin_class_name.c_str(), process->CalculateProcess());
if (object_sp)
m_python_object = object_sp->GetObject();
}
}
}
}
@ -217,8 +236,8 @@ OperatingSystemPython::CreateRegisterContextForThread (Thread *thread)
return RegisterContextSP();
auto object_sp = m_interpreter->OSPlugin_QueryForRegisterContextData (m_interpreter->MakeScriptObject(m_python_object),
thread->GetID());
if (!object_sp)
if (!object_sp)
return RegisterContextSP();
PythonDataString reg_context_data((PyObject*)object_sp->GetObject());

View File

@ -43,7 +43,8 @@ public:
//------------------------------------------------------------------
// Class Methods
//------------------------------------------------------------------
OperatingSystemPython (lldb_private::Process *process);
OperatingSystemPython (lldb_private::Process *process,
const lldb_private::FileSpec &python_module_path);
virtual
~OperatingSystemPython ();
@ -78,6 +79,10 @@ public:
protected:
bool IsValid() const
{
return m_python_object != NULL;
}
DynamicRegisterInfo *
GetDynamicRegisterInfo ();

View File

@ -94,12 +94,14 @@ g_properties[] =
{
{ "disable-memory-cache" , OptionValue::eTypeBoolean, false, DISABLE_MEM_CACHE_DEFAULT, NULL, NULL, "Disable reading and caching of memory in fixed-size units." },
{ "extra-startup-command", OptionValue::eTypeArray , false, OptionValue::eTypeString, NULL, NULL, "A list containing extra commands understood by the particular process plugin used." },
{ "python-os-plugin-path", OptionValue::eTypeFileSpec, false, 0, NULL, NULL, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." },
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
};
enum {
ePropertyDisableMemCache,
ePropertyExtraStartCommand
ePropertyExtraStartCommand,
ePropertyPythonOSPluginPath
};
ProcessProperties::ProcessProperties (bool is_global) :
@ -145,6 +147,20 @@ ProcessProperties::SetExtraStartupCommands (const Args &args)
m_collection_sp->SetPropertyAtIndexFromArgs(NULL, idx, args);
}
FileSpec
ProcessProperties::GetPythonOSPluginPath () const
{
const uint32_t idx = ePropertyPythonOSPluginPath;
return m_collection_sp->GetPropertyAtIndexAsFileSpec(NULL, idx);
}
void
ProcessProperties::SetPythonOSPluginPath (const FileSpec &file)
{
const uint32_t idx = ePropertyPythonOSPluginPath;
m_collection_sp->SetPropertyAtIndexAsFileSpec(NULL, idx, file);
}
void
ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const
{