<rdar://problem/13010007>

Added the ability for OS plug-ins to lazily populate the thread this. The python OS plug-in classes can now implement the following method:

class OperatingSystemPlugin:
  def create_thread(self, tid, context):
    # Return a dictionary for a new thread to create it on demand

This will add a new thread to the thread list if it doesn't already exist. The example code in lldb/examples/python/operating_system.py has been updated to show how this call us used.

Cleaned up the code in PythonDataObjects.cpp/h:
- renamed all classes that started with PythonData* to be Python*. 
- renamed PythonArray to PythonList. Cleaned up the code to use inheritance where
- Centralized the code that does ref counting in the PythonObject class to a single function.
- Made the "bool PythonObject::Reset(PyObject *)" function be virtual so each subclass can correctly check to ensure a PyObject is of the right type before adopting the object.
- Cleaned up all APIs and added new constructors for the Python* classes to they can all construct form:
	- PyObject *
	- const PythonObject &
	- const lldb::ScriptInterpreterObjectSP &

Cleaned up code in ScriptInterpreterPython:
- Made calling python functions safer by templatizing the production of value formats. Python specifies the value formats based on built in C types (long, long long, etc), and code often uses typedefs for uint32_t, uint64_t, etc when passing arguments down to python. We will now always produce correct value formats as the templatized code will "do the right thing" all the time.
- Fixed issues with the ScriptInterpreterPython::Locker where entering the session and leaving the session had a bunch of issues that could cause the "lldb" module globals lldb.debugger, lldb.target, lldb.process, lldb.thread, and lldb.frame to not be initialized.

llvm-svn: 172873
This commit is contained in:
Greg Clayton
2013-01-18 23:41:08 +00:00
parent 162b22c155
commit a4d8747d0f
17 changed files with 698 additions and 469 deletions

View File

@@ -135,7 +135,7 @@ ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter
uint16_t on_entry,
uint16_t on_leave,
FILE* wait_msg_handle) :
m_need_session( (on_leave & TearDownSession) == TearDownSession ),
m_teardown_session( (on_leave & TearDownSession) == TearDownSession ),
m_python_interpreter(py_interpreter),
m_tmp_fh(wait_msg_handle)
{
@@ -144,7 +144,13 @@ ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter
DoAcquireLock();
if ((on_entry & InitSession) == InitSession)
DoInitSession((on_entry & InitGlobals) == InitGlobals);
{
if (DoInitSession((on_entry & InitGlobals) == InitGlobals) == false)
{
// Don't teardown the session if we didn't init it.
m_teardown_session = false;
}
}
}
bool
@@ -162,8 +168,7 @@ ScriptInterpreterPython::Locker::DoInitSession(bool init_lldb_globals)
{
if (!m_python_interpreter)
return false;
m_python_interpreter->EnterSession (init_lldb_globals);
return true;
return m_python_interpreter->EnterSession (init_lldb_globals);
}
bool
@@ -187,7 +192,7 @@ ScriptInterpreterPython::Locker::DoTearDownSession()
ScriptInterpreterPython::Locker::~Locker()
{
if (m_need_session)
if (m_teardown_session)
DoTearDownSession();
DoFreeLock();
}
@@ -254,14 +259,11 @@ ScriptInterpreterPython::PythonInputReaderManager::~PythonInputReaderManager()
}
size_t
ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback
(
void *baton,
InputReader &reader,
InputReaderAction notification,
const char *bytes,
size_t bytes_len
)
ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback (void *baton,
InputReader &reader,
InputReaderAction notification,
const char *bytes,
size_t bytes_len)
{
lldb::thread_t embedded_interpreter_thread;
LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
@@ -364,22 +366,22 @@ ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback
break;
case eInputReaderInterrupt:
{
PyThreadState* state = _PyThreadState_Current;
if (!state)
state = script_interpreter->m_command_thread_state;
if (state)
{
long tid = state->thread_id;
_PyThreadState_Current = state;
int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt);
if (log)
log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p",
tid,num_threads,state);
PyThreadState* state = _PyThreadState_Current;
if (!state)
state = script_interpreter->m_command_thread_state;
if (state)
{
long tid = state->thread_id;
_PyThreadState_Current = state;
int num_threads = PyThreadState_SetAsyncExc(tid, PyExc_KeyboardInterrupt);
if (log)
log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, tid = %ld, num_threads = %d, state = %p",
tid,num_threads,state);
}
else if (log)
log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL");
}
else if (log)
log->Printf("ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL");
}
break;
case eInputReaderEndOfFile:
@@ -404,36 +406,30 @@ ScriptInterpreterPython::PythonInputReaderManager::InputReaderCallback
bytes_len);
reader.SetIsDone (true);
}
break;
case eInputReaderDone:
{
StreamString run_string;
char error_str[1024];
const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str));
if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL)
{
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin')", script_interpreter->m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
run_string.Clear();
StreamString run_string;
char error_str[1024];
const char *pty_slave_name = script_interpreter->m_embedded_thread_pty.GetSlaveName (error_str, sizeof (error_str));
if (pty_slave_name != NULL && PyThreadState_GetDict() != NULL)
{
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
run_string.Printf ("run_one_line (%s, 'sys.stdin = save_stdin; sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
run_string.Clear();
}
// Restore terminal settings if they were validly saved
if (log)
log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Done, closing down input reader.");
run_string.Printf ("run_one_line (%s, 'sys.stderr = save_stderr')", script_interpreter->m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
run_string.Clear();
}
}
// Restore terminal settings if they were validly saved
if (log)
log->Printf ("ScriptInterpreterPython::NonInteractiveInputReaderCallback, Done, closing down input reader.");
script_interpreter->RestoreTerminalState ();
script_interpreter->m_embedded_thread_pty.CloseMasterFileDescriptor();
script_interpreter->RestoreTerminalState ();
script_interpreter->m_embedded_thread_pty.CloseMasterFileDescriptor();
}
break;
}
@@ -586,6 +582,10 @@ ScriptInterpreterPython::RestoreTerminalState ()
void
ScriptInterpreterPython::LeaveSession ()
{
LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
if (log)
log->PutCString("ScriptInterpreterPython::LeaveSession()");
// checking that we have a valid thread state - since we use our own threading and locking
// in some (rare) cases during cleanup Python may end up believing we have no thread state
// and PyImport_AddModule will crash if that is the case - since that seems to only happen
@@ -610,14 +610,22 @@ ScriptInterpreterPython::LeaveSession ()
m_session_is_active = false;
}
void
bool
ScriptInterpreterPython::EnterSession (bool init_lldb_globals)
{
// If we have already entered the session, without having officially 'left' it, then there is no need to
// 'enter' it again.
LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
if (m_session_is_active)
return;
{
if (log)
log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i) session is already active, returning without doing anything", init_lldb_globals);
return false;
}
if (log)
log->Printf("ScriptInterpreterPython::EnterSession(init_lldb_globals=%i)", init_lldb_globals);
m_session_is_active = true;
@@ -660,6 +668,8 @@ ScriptInterpreterPython::EnterSession (bool init_lldb_globals)
if (PyErr_Occurred())
PyErr_Clear ();
return true;
}
static PyObject*
@@ -733,7 +743,7 @@ ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObjec
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::TearDownSession : 0));
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
bool success = false;
@@ -854,9 +864,7 @@ ScriptInterpreterPython::InputReaderCallback
{
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock
| ScriptInterpreterPython::Locker::InitSession
| ScriptInterpreterPython::Locker::InitGlobals,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | ScriptInterpreterPython::Locker::InitGlobals,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
}
@@ -900,11 +908,9 @@ ScriptInterpreterPython::InputReaderCallback
case eInputReaderReactivate:
{
ScriptInterpreterPython::Locker locker(script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock
| ScriptInterpreterPython::Locker::InitSession
| ScriptInterpreterPython::Locker::InitGlobals,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
ScriptInterpreterPython::Locker locker (script_interpreter,
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
ScriptInterpreterPython::Locker::FreeAcquiredLock);
}
break;
@@ -1008,10 +1014,8 @@ ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
{
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock
| ScriptInterpreterPython::Locker::InitSession
| (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::TearDownSession : 0));
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
PyObject *py_return = NULL;
PyObject *mainmod = PyImport_AddModule ("__main__");
@@ -1177,10 +1181,8 @@ ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string, const Exec
Locker locker(this,
ScriptInterpreterPython::Locker::AcquireLock
| ScriptInterpreterPython::Locker::InitSession
| (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::TearDownSession : 0));
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession | (options.GetSetLLDBGlobals() ? ScriptInterpreterPython::Locker::InitGlobals : 0),
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
bool success = false;
PyObject *py_return = NULL;
@@ -1719,7 +1721,7 @@ ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, std::st
}
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::CreateOSPlugin (const char *class_name, lldb::ProcessSP process_sp)
ScriptInterpreterPython::OSPlugin_CreatePluginObject (const char *class_name, lldb::ProcessSP process_sp)
{
if (class_name == NULL || class_name[0] == '\0')
return lldb::ScriptInterpreterObjectSP();
@@ -1740,16 +1742,16 @@ ScriptInterpreterPython::CreateOSPlugin (const char *class_name, lldb::ProcessSP
}
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::OSPlugin_QueryForRegisterInfo (lldb::ScriptInterpreterObjectSP object)
ScriptInterpreterPython::OSPlugin_RegisterInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
{
Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
static char callee_name[] = "get_register_info";
if (!object)
if (!os_plugin_object_sp)
return lldb::ScriptInterpreterObjectSP();
PyObject* implementor = (PyObject*)object->GetObject();
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
if (implementor == NULL || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
@@ -1799,16 +1801,16 @@ ScriptInterpreterPython::OSPlugin_QueryForRegisterInfo (lldb::ScriptInterpreterO
}
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::OSPlugin_QueryForThreadsInfo (lldb::ScriptInterpreterObjectSP object)
ScriptInterpreterPython::OSPlugin_ThreadsInfo (lldb::ScriptInterpreterObjectSP os_plugin_object_sp)
{
Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
static char callee_name[] = "get_thread_info";
if (!object)
if (!os_plugin_object_sp)
return lldb::ScriptInterpreterObjectSP();
PyObject* implementor = (PyObject*)object->GetObject();
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
if (implementor == NULL || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
@@ -1857,19 +1859,45 @@ ScriptInterpreterPython::OSPlugin_QueryForThreadsInfo (lldb::ScriptInterpreterOb
return MakeScriptObject(py_return);
}
// GetPythonValueFormatString provides a system independent type safe way to
// convert a variable's type into a python value format. Python value formats
// are defined in terms of builtin C types and could change from system to
// as the underlying typedef for uint* types, size_t, off_t and other values
// change.
template <typename T>
const char *GetPythonValueFormatString(T t)
{
assert(!"Unhandled type passed to GetPythonValueFormatString(T), make a specialization of GetPythonValueFormatString() to support this type.");
return NULL;
}
template <> const char *GetPythonValueFormatString (char *) { return "s"; }
template <> const char *GetPythonValueFormatString (char) { return "b"; }
template <> const char *GetPythonValueFormatString (unsigned char) { return "B"; }
template <> const char *GetPythonValueFormatString (short) { return "h"; }
template <> const char *GetPythonValueFormatString (unsigned short) { return "H"; }
template <> const char *GetPythonValueFormatString (int) { return "i"; }
template <> const char *GetPythonValueFormatString (unsigned int) { return "I"; }
template <> const char *GetPythonValueFormatString (long) { return "l"; }
template <> const char *GetPythonValueFormatString (unsigned long) { return "k"; }
template <> const char *GetPythonValueFormatString (long long) { return "L"; }
template <> const char *GetPythonValueFormatString (unsigned long long) { return "K"; }
template <> const char *GetPythonValueFormatString (float t) { return "f"; }
template <> const char *GetPythonValueFormatString (double t) { return "d"; }
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::OSPlugin_QueryForRegisterContextData (lldb::ScriptInterpreterObjectSP object,
lldb::tid_t thread_id)
ScriptInterpreterPython::OSPlugin_RegisterContextData (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
lldb::tid_t tid)
{
Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
static char callee_name[] = "get_register_data";
static char param_format[] = "l";
static char *param_format = const_cast<char *>(GetPythonValueFormatString(tid));
if (!object)
if (!os_plugin_object_sp)
return lldb::ScriptInterpreterObjectSP();
PyObject* implementor = (PyObject*)object->GetObject();
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
if (implementor == NULL || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
@@ -1906,7 +1934,7 @@ ScriptInterpreterPython::OSPlugin_QueryForRegisterContextData (lldb::ScriptInter
Py_XDECREF(pmeth);
// right now we know this function exists and is callable..
PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, thread_id);
PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, tid);
// if it fails, print the error but otherwise go on
if (PyErr_Occurred())
@@ -1918,6 +1946,70 @@ ScriptInterpreterPython::OSPlugin_QueryForRegisterContextData (lldb::ScriptInter
return MakeScriptObject(py_return);
}
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::OSPlugin_CreateThread (lldb::ScriptInterpreterObjectSP os_plugin_object_sp,
lldb::tid_t tid,
lldb::addr_t context)
{
Locker py_lock(this,Locker::AcquireLock,Locker::FreeLock);
static char callee_name[] = "create_thread";
std::string param_format;
param_format += GetPythonValueFormatString(tid);
param_format += GetPythonValueFormatString(context);
if (!os_plugin_object_sp)
return lldb::ScriptInterpreterObjectSP();
PyObject* implementor = (PyObject*)os_plugin_object_sp->GetObject();
if (implementor == NULL || implementor == Py_None)
return lldb::ScriptInterpreterObjectSP();
PyObject* pmeth = PyObject_GetAttrString(implementor, callee_name);
if (PyErr_Occurred())
{
PyErr_Clear();
}
if (pmeth == NULL || pmeth == Py_None)
{
Py_XDECREF(pmeth);
return lldb::ScriptInterpreterObjectSP();
}
if (PyCallable_Check(pmeth) == 0)
{
if (PyErr_Occurred())
{
PyErr_Clear();
}
Py_XDECREF(pmeth);
return lldb::ScriptInterpreterObjectSP();
}
if (PyErr_Occurred())
{
PyErr_Clear();
}
Py_XDECREF(pmeth);
// right now we know this function exists and is callable..
PyObject* py_return = PyObject_CallMethod(implementor, callee_name, &param_format[0], tid, context);
// if it fails, print the error but otherwise go on
if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
return MakeScriptObject(py_return);
}
lldb::ScriptInterpreterObjectSP
ScriptInterpreterPython::CreateSyntheticScriptedProvider (const char *class_name,
lldb::ValueObjectSP valobj)
@@ -2651,8 +2743,8 @@ ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
{
Locker py_lock(this,
Locker::AcquireLock | Locker::InitSession | Locker::InitGlobals,
Locker::FreeLock | Locker::TearDownSession);
Locker::AcquireLock | Locker::InitSession,
Locker::FreeLock | Locker::TearDownSession);
SynchronicityHandler synch_handler(debugger_sp,
synchronicity);
@@ -2697,8 +2789,9 @@ ScriptInterpreterPython::GetDocumentationForItem(const char* item, std::string&
char* result_ptr = NULL; // Python is going to point this to valid data if ExecuteOneLineWithReturn returns successfully
if (ExecuteOneLineWithReturn (command.c_str(),
ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
&result_ptr, ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false) /*.SetSetLLDBGlobals(false)*/))
ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
&result_ptr,
ScriptInterpreter::ExecuteScriptOptions().SetEnableIO(false)))
{
if (result_ptr)
dest.assign(result_ptr);