[Lldb-commits] [lldb] r123415 - in /lldb/trunk: include/lldb/Core/ include/lldb/Interpreter/ scripts/ source/ source/Core/ source/Interpreter/
Caroline Tice
ctice at apple.com
Thu Jan 13 16:29:17 PST 2011
Author: ctice
Date: Thu Jan 13 18:29:16 2011
New Revision: 123415
URL: http://llvm.org/viewvc/llvm-project?rev=123415&view=rev
Log:
Split up the Python script interpreter code to allow multiple script interpreter objects to
exist within the same process (one script interpreter object per debugger object). The
python script interpreter objects are all using the same global Python script interpreter;
they use separate dictionaries to keep their data separate, and mutex's to prevent any object
attempting to use the global Python interpreter when another object is already using it.
Modified:
lldb/trunk/include/lldb/Core/Debugger.h
lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
lldb/trunk/scripts/lldb.swig
lldb/trunk/source/Core/Debugger.cpp
lldb/trunk/source/Interpreter/CommandInterpreter.cpp
lldb/trunk/source/Interpreter/CommandObjectScript.cpp
lldb/trunk/source/Interpreter/CommandObjectScript.h
lldb/trunk/source/Interpreter/ScriptInterpreter.cpp
lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
lldb/trunk/source/Interpreter/embedded_interpreter.py
lldb/trunk/source/lldb.cpp
Modified: lldb/trunk/include/lldb/Core/Debugger.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Core/Debugger.h?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Core/Debugger.h (original)
+++ lldb/trunk/include/lldb/Core/Debugger.h Thu Jan 13 18:29:16 2011
@@ -166,7 +166,6 @@
m_auto_confirm_on = auto_confirm_on;
}
-
protected:
void
@@ -375,6 +374,9 @@
void
CleanUpInputReaders ();
+ static int
+ TestDebuggerRefCount ();
+
protected:
static void
Modified: lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/CommandInterpreter.h Thu Jan 13 18:29:16 2011
@@ -262,6 +262,7 @@
OptionArgMap m_alias_options; // Stores any options (with or without arguments) that go with any alias.
std::vector<std::string> m_command_history;
std::string m_repeat_command; // Stores the command that will be executed for an empty command string.
+ std::auto_ptr<ScriptInterpreter> m_script_interpreter_ap;
};
Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreter.h Thu Jan 13 18:29:16 2011
@@ -90,16 +90,23 @@
int
GetMasterFileDescriptor ();
- CommandInterpreter *
- GetCommandInterpreter ();
+ CommandInterpreter &
+ GetCommandInterpreter ();
- static std::string
- LanguageToString (lldb::ScriptLanguage);
+ static std::string
+ LanguageToString (lldb::ScriptLanguage language);
+
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+ virtual void
+ ResetOutputFileHandle (FILE *new_fh) { } //By default, do nothing.
protected:
CommandInterpreter &m_interpreter;
-
-private:
lldb::ScriptLanguage m_script_lang;
// Scripting languages may need to use stdin for their interactive loops;
@@ -108,8 +115,11 @@
// embedded scripting loops. Therefore we need to set up a pseudoterminal and use that
// as stdin for the script interpreter interactive loops/prompts.
- lldb_utility::PseudoTerminal m_interpreter_pty;
- std::string m_pty_slave_name;
+ lldb_utility::PseudoTerminal m_interpreter_pty; // m_session_pty
+ std::string m_pty_slave_name; //m_session_pty_slave_name
+
+private:
+
};
} // namespace lldb_private
Modified: lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h (original)
+++ lldb/trunk/include/lldb/Interpreter/ScriptInterpreterPython.h Thu Jan 13 18:29:16 2011
@@ -11,6 +11,12 @@
#ifndef liblldb_ScriptInterpreterPython_h_
#define liblldb_ScriptInterpreterPython_h_
+#if defined (__APPLE__)
+#include <Python/Python.h>
+#else
+#include <Python.h>
+#endif
+
#include "lldb/lldb-private.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Core/InputReader.h"
@@ -70,9 +76,26 @@
StringList
ReadCommandInputFromUser (FILE *in_file);
+ virtual void
+ ResetOutputFileHandle (FILE *new_fh);
+
static lldb::thread_result_t
RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton);
+ static void
+ Initialize ();
+
+ static void
+ Terminate ();
+
+protected:
+
+ void
+ EnterSession ();
+
+ void
+ LeaveSession ();
+
private:
static size_t
@@ -81,12 +104,19 @@
lldb::InputReaderAction notification,
const char *bytes,
size_t bytes_len);
-
- void *m_compiled_module;
- struct termios m_termios;
- bool m_termios_valid;
+
+
lldb_utility::PseudoTerminal m_embedded_python_pty;
lldb::InputReaderSP m_embedded_thread_input_reader_sp;
+ FILE *m_dbg_stdout;
+ PyObject *m_new_sysout;
+ std::string m_dictionary_name;
+ struct termios m_termios;
+ bool m_termios_valid;
+ bool m_session_is_active;
+ bool m_pty_slave_is_open;
+ bool m_valid_session;
+
};
} // namespace lldb_private
Modified: lldb/trunk/scripts/lldb.swig
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/scripts/lldb.swig?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/scripts/lldb.swig (original)
+++ lldb/trunk/scripts/lldb.swig Thu Jan 13 18:29:16 2011
@@ -1,8 +1,6 @@
/*
lldb.swig
- Created by Caroline Tice 1/18/2010
-
This is the input file for SWIG, to create the appropriate C++ wrappers and
functions for various scripting languages, to enable them to call the
liblldb Script Bridge functions.
@@ -151,6 +149,7 @@
LLDBSWIGPythonBreakpointCallbackFunction
(
const char *python_function_name,
+ const char *session_dictionary_name,
lldb::SBFrame& sb_frame,
lldb::SBBreakpointLocation& sb_bp_loc
)
@@ -161,20 +160,70 @@
if (Frame_PyObj == NULL || Bp_Loc_PyObj == NULL)
return stop_at_breakpoint;
+
+ if (!python_function_name || !session_dictionary_name)
+ return stop_at_breakpoint;
- PyObject *pmodule, *pdict, *pfunc;
+ PyObject *pmodule, *main_dict, *session_dict, *pfunc;
PyObject *pargs, *pvalue;
pmodule = PyImport_AddModule ("__main__");
if (pmodule != NULL)
{
- pdict = PyModule_GetDict (pmodule);
- if (pdict != NULL)
+ main_dict = PyModule_GetDict (pmodule);
+ if (main_dict != NULL)
{
- pfunc = PyObject_GetAttrString (pmodule, python_function_name);
+ 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 stop_at_breakpoint;
+
+ // 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 (2);
+ pargs = PyTuple_New (3);
if (pargs == NULL)
{
if (PyErr_Occurred())
@@ -184,6 +233,7 @@
PyTuple_SetItem (pargs, 0, Frame_PyObj); // This "steals" a reference to Frame_PyObj
PyTuple_SetItem (pargs, 1, Bp_Loc_PyObj); // This "steals" a reference to Bp_Loc_PyObj
+ PyTuple_SetItem (pargs, 2, session_dict); // This "steals" a reference to session_dict
pvalue = PyObject_CallObject (pfunc, pargs);
Py_DECREF (pargs);
@@ -195,7 +245,7 @@
{
PyErr_Clear();
}
- Py_DECREF (pfunc);
+ Py_INCREF (session_dict);
}
else if (PyErr_Occurred())
{
Modified: lldb/trunk/source/Core/Debugger.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Core/Debugger.cpp?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Core/Debugger.cpp (original)
+++ lldb/trunk/source/Core/Debugger.cpp Thu Jan 13 18:29:16 2011
@@ -59,6 +59,12 @@
return g_settings_controller;
}
+int
+Debugger::TestDebuggerRefCount ()
+{
+ return g_shared_debugger_refcount;
+}
+
void
Debugger::Initialize ()
{
@@ -252,6 +258,8 @@
m_output_file.SetFileHandle (fh, tranfer_ownership);
if (m_output_file.GetFileHandle() == NULL)
m_output_file.SetFileHandle (stdin, false);
+
+ GetCommandInterpreter().GetScriptInterpreter()->ResetOutputFileHandle (fh);
}
FILE *
Modified: lldb/trunk/source/Interpreter/CommandInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandInterpreter.cpp?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandInterpreter.cpp Thu Jan 13 18:29:16 2011
@@ -50,6 +50,8 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterNone.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
using namespace lldb;
using namespace lldb_private;
@@ -63,7 +65,8 @@
Broadcaster ("lldb.command-interpreter"),
m_debugger (debugger),
m_synchronous_execution (synchronous_execution),
- m_skip_lldbinit_files (false)
+ m_skip_lldbinit_files (false),
+ m_script_interpreter_ap ()
{
const char *dbg_name = debugger.GetInstanceName().AsCString();
std::string lang_name = ScriptInterpreter::LanguageToString (script_language);
@@ -1460,15 +1463,23 @@
ScriptInterpreter *
CommandInterpreter::GetScriptInterpreter ()
{
- CommandObject::CommandMap::iterator pos;
+ if (m_script_interpreter_ap.get() != NULL)
+ return m_script_interpreter_ap.get();
- pos = m_command_dict.find ("script");
- if (pos != m_command_dict.end())
+ lldb::ScriptLanguage script_lang = GetDebugger().GetScriptLanguage();
+ switch (script_lang)
{
- CommandObject *script_cmd_obj = pos->second.get();
- return ((CommandObjectScript *) script_cmd_obj)->GetInterpreter ();
- }
- return NULL;
+ case eScriptLanguageNone:
+ m_script_interpreter_ap.reset (new ScriptInterpreterNone (*this));
+ break;
+ case eScriptLanguagePython:
+ m_script_interpreter_ap.reset (new ScriptInterpreterPython (*this));
+ break;
+ default:
+ break;
+ };
+
+ return m_script_interpreter_ap.get();
}
Modified: lldb/trunk/source/Interpreter/CommandObjectScript.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandObjectScript.cpp?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandObjectScript.cpp (original)
+++ lldb/trunk/source/Interpreter/CommandObjectScript.cpp Thu Jan 13 18:29:16 2011
@@ -17,8 +17,7 @@
#include "lldb/Interpreter/CommandReturnObject.h"
#include "lldb/Interpreter/ScriptInterpreter.h"
-#include "lldb/Interpreter/ScriptInterpreterPython.h"
-#include "lldb/Interpreter/ScriptInterpreterNone.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
using namespace lldb;
using namespace lldb_private;
@@ -32,8 +31,7 @@
"script",
"Pass an expression to the script interpreter for evaluation and return the results. Drop into the interactive interpreter if no expression is given.",
"script [<script-expression-for-evaluation>]"),
- m_script_lang (script_lang),
- m_interpreter_ap ()
+ m_script_lang (script_lang)
{
}
@@ -48,7 +46,7 @@
CommandReturnObject &result
)
{
- ScriptInterpreter *script_interpreter = GetInterpreter ();
+ ScriptInterpreter *script_interpreter = m_interpreter.GetScriptInterpreter ();
if (script_interpreter == NULL)
{
@@ -88,22 +86,3 @@
return false;
}
-
-ScriptInterpreter *
-CommandObjectScript::GetInterpreter ()
-{
- if (m_interpreter_ap.get() == NULL)
- {
- switch (m_script_lang)
- {
- case eScriptLanguagePython:
- m_interpreter_ap.reset (new ScriptInterpreterPython (m_interpreter));
- break;
-
- case eScriptLanguageNone:
- m_interpreter_ap.reset (new ScriptInterpreterNone (m_interpreter));
- break;
- }
- }
- return m_interpreter_ap.get();
-}
Modified: lldb/trunk/source/Interpreter/CommandObjectScript.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/CommandObjectScript.h?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/CommandObjectScript.h (original)
+++ lldb/trunk/source/Interpreter/CommandObjectScript.h Thu Jan 13 18:29:16 2011
@@ -42,12 +42,8 @@
Execute (Args& command,
CommandReturnObject &result);
- ScriptInterpreter *
- GetInterpreter ();
-
private:
lldb::ScriptLanguage m_script_lang;
- std::auto_ptr<ScriptInterpreter> m_interpreter_ap;
};
} // namespace lldb_private
Modified: lldb/trunk/source/Interpreter/ScriptInterpreter.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreter.cpp?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreter.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreter.cpp Thu Jan 13 18:29:16 2011
@@ -17,15 +17,17 @@
#include "lldb/Core/Stream.h"
#include "lldb/Core/StringList.h"
#include "lldb/Interpreter/CommandReturnObject.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Utility/PseudoTerminal.h"
using namespace lldb;
using namespace lldb_private;
-ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, ScriptLanguage script_lang) :
+ScriptInterpreter::ScriptInterpreter (CommandInterpreter &interpreter, lldb::ScriptLanguage script_lang) :
m_interpreter (interpreter),
m_script_lang (script_lang),
- m_interpreter_pty ()
+ m_interpreter_pty (),
+ m_pty_slave_name ()
{
if (m_interpreter_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0))
{
@@ -40,6 +42,12 @@
m_interpreter_pty.CloseMasterFileDescriptor();
}
+CommandInterpreter &
+ScriptInterpreter::GetCommandInterpreter ()
+{
+ return m_interpreter;
+}
+
const char *
ScriptInterpreter::GetScriptInterpreterPtyName ()
{
@@ -81,3 +89,16 @@
return return_value;
}
+
+void
+ScriptInterpreter::Initialize ()
+{
+ ScriptInterpreterPython::Initialize ();
+}
+
+void
+ScriptInterpreter::Terminate ()
+{
+ ScriptInterpreterPython::Terminate ();
+}
+
Modified: lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp (original)
+++ lldb/trunk/source/Interpreter/ScriptInterpreterPython.cpp Thu Jan 13 18:29:16 2011
@@ -52,6 +52,7 @@
LLDBSWIGPythonBreakpointCallbackFunction
(
const char *python_function_name,
+ const char *session_dictionary_name,
lldb::SBFrame& sb_frame,
lldb::SBBreakpointLocation& sb_bp_loc
);
@@ -146,10 +147,22 @@
if not more:\n\
break\n\
\n\
+ def one_line (self, input):\n\
+ line = self.process_input (input)\n\
+ more = self.push(line)\n\
+ if more:\n\
+ self.write (\"Input not a complete line.\")\n\
+ self.resetbuffer()\n\
+ more = 0\n\
+\n\
def run_python_interpreter (dict):\n\
# Pass in the dictionary, for continuity from one session to the next.\n\
repl = SimpleREPL('>>> ', dict)\n\
- repl.interact()\n";
+ repl.interact()\n\
+\n\
+def run_one_line (dict, input_string):\n\
+ repl = SimpleREPL ('', dict)\n\
+ repl.one_line (input_string)\n";
static int
_check_and_flush (FILE *stream)
@@ -158,146 +171,171 @@
return fflush (stream) || prev_fail ? EOF : 0;
}
+static Mutex &
+GetPythonMutex ()
+{
+ static Mutex g_python_mutex (Mutex::eMutexTypeRecursive);
+ return g_python_mutex;
+}
+
ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) :
ScriptInterpreter (interpreter, eScriptLanguagePython),
- m_compiled_module (NULL),
+ m_embedded_python_pty (),
+ m_embedded_thread_input_reader_sp (),
+ m_dbg_stdout (interpreter.GetDebugger().GetOutputFileHandle()),
+ m_new_sysout (NULL),
+ m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()),
m_termios (),
m_termios_valid (false),
- m_embedded_python_pty (),
- m_embedded_thread_input_reader_sp ()
+ m_session_is_active (false),
+ m_pty_slave_is_open (false),
+ m_valid_session (true)
{
+ Mutex::Locker locker (GetPythonMutex());
- Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+ m_dictionary_name.append("_dict");
+ StreamString run_string;
+ run_string.Printf ("%s = dict()", m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+
+ run_string.Clear();
+ run_string.Printf ("run_one_line (%s, 'import sys')", m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+
+ // Importing 'lldb' module calls SBDebugger::Initialize, which calls Debugger::Initialize, which increments a
+ // global debugger ref-count; therefore we need to check the ref-count before and after importing lldb, and if the
+ // ref-count increased we need to call Debugger::Terminate here to decrement the ref-count so that when the final
+ // call to Debugger::Terminate is made, the ref-count has the correct value.
+ //
+ // Bonus question: Why doesn't the ref-count always increase? Because sometimes lldb has already been imported, in
+ // which case the code inside it, including the call to SBDebugger::Initialize(), does not get executed.
+
+ int old_count = Debugger::TestDebuggerRefCount();
- // Save terminal settings if we can
- int input_fd;
- FILE *input_fh = m_interpreter.GetDebugger().GetInputFileHandle();
- if (input_fh != NULL)
- input_fd = ::fileno (input_fh);
- else
- input_fd = STDIN_FILENO;
+ run_string.Clear();
+ run_string.Printf ("run_one_line (%s, 'import lldb')", m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+
+ int new_count = Debugger::TestDebuggerRefCount();
- m_termios_valid = ::tcgetattr (input_fd, &m_termios) == 0;
-
- // Find the module that owns this code and use that path we get to
- // set the PYTHONPATH appropriately.
+ if (new_count > old_count)
+ Debugger::Terminate();
- FileSpec file_spec;
- char python_dir_path[PATH_MAX];
- if (Host::GetLLDBPath (ePathTypePythonDir, file_spec))
+ run_string.Clear();
+ run_string.Printf ("run_one_line (%s, 'import copy')", m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+
+ run_string.Clear();
+ run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %d')", m_dictionary_name.c_str(),
+ interpreter.GetDebugger().GetID());
+ PyRun_SimpleString (run_string.GetData());
+
+ if (m_dbg_stdout != NULL)
{
- std::string python_path;
- const char *curr_python_path = ::getenv ("PYTHONPATH");
- if (curr_python_path)
- {
- // We have a current value for PYTHONPATH, so lets append to it
- python_path.append (curr_python_path);
- }
-
- if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
- {
- if (!python_path.empty())
- python_path.append (1, ':');
- python_path.append (python_dir_path);
- }
-
- if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec))
- {
- if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
- {
- if (!python_path.empty())
- python_path.append (1, ':');
- python_path.append (python_dir_path);
- }
- }
- const char *pathon_path_env_cstr = python_path.c_str();
- ::setenv ("PYTHONPATH", pathon_path_env_cstr, 1);
+ m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
}
+}
- Py_Initialize ();
-
- PyObject *compiled_module = Py_CompileString (embedded_interpreter_string,
- "embedded_interpreter.py",
- Py_file_input);
+ScriptInterpreterPython::~ScriptInterpreterPython ()
+{
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
- m_compiled_module = static_cast<void*>(compiled_module);
+ if (m_embedded_thread_input_reader_sp.get() != NULL)
+ {
+ m_embedded_thread_input_reader_sp->SetIsDone (true);
+ m_embedded_python_pty.CloseSlaveFileDescriptor();
+ m_pty_slave_is_open = false;
+ const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp;
+ m_embedded_thread_input_reader_sp.reset();
+ debugger.PopInputReader (reader_sp);
+ }
+
+ if (m_new_sysout)
+ {
+ Mutex::Locker locker(GetPythonMutex());
+ Py_DECREF (m_new_sysout);
+ }
+}
- // This function is in the C++ output file generated by SWIG after it is
- // run on all of the headers in "lldb/API/SB*.h"
- init_lldb ();
+void
+ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh)
+{
+ if (fh == NULL)
+ return;
+
+ m_dbg_stdout = fh;
+ Mutex::Locker locker (GetPythonMutex());
- // Update the path python uses to search for modules to include the current directory.
+ EnterSession ();
+ m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
+ LeaveSession ();
+}
- int success = PyRun_SimpleString ("import sys");
- success = PyRun_SimpleString ("sys.path.append ('.')");
- if (success == 0)
- {
- // Import the Script Bridge module.
- success = PyRun_SimpleString ("import lldb");
- }
+void
+ScriptInterpreterPython::LeaveSession ()
+{
+ m_session_is_active = false;
+}
- const char *pty_slave_name = GetScriptInterpreterPtyName ();
- FILE *out_fh = interpreter.GetDebugger().GetOutputFileHandle();
+void
+ScriptInterpreterPython::EnterSession ()
+{
+ // If we have already entered the session, without having officially 'left' it, then there is no need to
+ // 'enter' it again.
- PyObject *pmod = PyImport_ExecCodeModule (const_cast<char*> ("embedded_interpreter"),
- static_cast<PyObject*>(m_compiled_module));
+ if (m_session_is_active)
+ return;
- if (pmod != NULL)
- {
- PyRun_SimpleString ("ConsoleDict = locals()");
- PyRun_SimpleString ("from embedded_interpreter import run_python_interpreter");
- PyRun_SimpleString ("import sys");
- PyRun_SimpleString ("from termios import *");
-
- if (out_fh != NULL)
- {
- PyObject *new_sysout = PyFile_FromFile (out_fh, (char *) "", (char *) "w",
- _check_and_flush);
- PyObject *sysmod = PyImport_AddModule ("sys");
- PyObject *sysdict = PyModule_GetDict (sysmod);
-
- if ((new_sysout != NULL)
- && (sysmod != NULL)
- && (sysdict != NULL))
- {
- PyDict_SetItemString (sysdict, "stdout", new_sysout);
- }
+ m_session_is_active = true;
- if (PyErr_Occurred())
- PyErr_Clear();
- }
+ Mutex::Locker locker (GetPythonMutex());
- StreamString run_string;
- run_string.Printf ("new_stdin = open('%s', 'r')", pty_slave_name);
+ PyObject *sysmod = PyImport_AddModule ("sys");
+ PyObject *sysdict = PyModule_GetDict (sysmod);
+
+ if ((m_new_sysout != NULL)
+ && (sysmod != NULL)
+ && (sysdict != NULL))
+ PyDict_SetItemString (sysdict, "stdout", m_new_sysout);
+
+ if (PyErr_Occurred())
+ PyErr_Clear ();
+
+ StreamString run_string;
+ if (!m_pty_slave_is_open)
+ {
+ run_string.Printf ("run_one_line (%s, \"new_stdin = open('%s', 'r')\")", m_dictionary_name.c_str(),
+ m_pty_slave_name.c_str());
PyRun_SimpleString (run_string.GetData());
- PyRun_SimpleString ("sys.stdin = new_stdin");
-
+ m_pty_slave_is_open = true;
+
run_string.Clear();
- run_string.Printf ("lldb.debugger_unique_id = %d", interpreter.GetDebugger().GetID());
+ run_string.Printf ("run_one_line (%s, 'sys.stdin = new_stdin')", m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
}
+}
- // Restore terminal settings if they were validly saved
- if (m_termios_valid)
- {
- ::tcsetattr (input_fd, TCSANOW, &m_termios);
- }
-}
-
-ScriptInterpreterPython::~ScriptInterpreterPython ()
-{
- Py_Finalize ();
-}
-
bool
ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result)
{
+ if (!m_valid_session)
+ return false;
+
+ EnterSession ();
+
+ Mutex::Locker locker (GetPythonMutex());
+
if (command)
{
int success;
- success = PyRun_SimpleString (command);
+ StreamString sstr;
+ sstr.Printf ("run_one_line (%s, '%s')", m_dictionary_name.c_str(), command);
+ success = PyRun_SimpleString (sstr.GetData());
+
+ LeaveSession ();
+
if (success == 0)
return true;
@@ -307,6 +345,7 @@
return false;
}
+ LeaveSession ();
if (result)
result->AppendError ("empty command passed to python\n");
return false;
@@ -329,12 +368,16 @@
if (baton == NULL)
return 0;
-
+
+ ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
+
+ if (script_interpreter->m_script_lang != eScriptLanguagePython)
+ return 0;
+
FILE *out_fh = reader.GetDebugger().GetOutputFileHandle ();
if (out_fh == NULL)
out_fh = stdout;
- ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
switch (notification)
{
case eInputReaderActivate:
@@ -384,14 +427,17 @@
log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty ");
reader.SetIsDone (true);
}
+ script_interpreter->EnterSession ();
}
break;
case eInputReaderDeactivate:
+ script_interpreter->LeaveSession ();
break;
case eInputReaderReactivate:
+ script_interpreter->EnterSession ();
break;
case eInputReaderInterrupt:
@@ -429,10 +475,8 @@
break;
case eInputReaderDone:
- // Send a control D to the script interpreter
- //::write (interpreter->GetMasterFileDescriptor(), "\nquit()\n", strlen("\nquit()\n"));
- // Write a newline out to the reader output
- //::fwrite ("\n", 1, 1, out_fh);
+ script_interpreter->LeaveSession ();
+
// Restore terminal settings if they were validly saved
if (log)
log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader.");
@@ -460,7 +504,7 @@
{
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
- Debugger &debugger = m_interpreter.GetDebugger();
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
// At the moment, the only time the debugger does not have an input file handle is when this is called
// directly from Python, in which case it is both dangerous and unnecessary (not to mention confusing) to
@@ -493,14 +537,54 @@
ScriptInterpreter::ReturnType return_type,
void *ret_value)
{
+ EnterSession ();
+
+ Mutex::Locker locker (GetPythonMutex());
+
PyObject *py_return = NULL;
PyObject *mainmod = PyImport_AddModule ("__main__");
PyObject *globals = PyModule_GetDict (mainmod);
- PyObject *locals = globals;
+ PyObject *locals = NULL;
PyObject *py_error = NULL;
bool ret_success;
+ bool should_decrement_locals = false;
int success;
+
+ if (PyDict_Check (globals))
+ {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ int i = 0;
+ while (PyDict_Next (globals, &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);
+ char *c_str = PyString_AsString (key);
+ if (strcmp (c_str, m_dictionary_name.c_str()) == 0)
+ locals = value;
+ ++i;
+ }
+ }
+ if (locals == NULL)
+ {
+ locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str());
+ should_decrement_locals = true;
+ }
+
+ if (locals == NULL)
+ {
+ locals = globals;
+ should_decrement_locals = false;
+ }
+
+ py_error = PyErr_Occurred();
+ if (py_error != NULL)
+ PyErr_Clear();
+
if (in_string != NULL)
{
py_return = PyRun_String (in_string, Py_eval_input, globals, locals);
@@ -513,6 +597,10 @@
py_return = PyRun_String (in_string, Py_single_input, globals, locals);
}
+ if (locals != NULL
+ && should_decrement_locals)
+ Py_DECREF (locals);
+
if (py_return != NULL)
{
switch (return_type)
@@ -614,6 +702,8 @@
PyErr_Clear();
ret_success = false;
}
+
+ LeaveSession ();
return ret_success;
}
@@ -621,13 +711,50 @@
bool
ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string)
{
+ EnterSession ();
+
+ Mutex::Locker locker (GetPythonMutex());
+
bool success = false;
PyObject *py_return = NULL;
PyObject *mainmod = PyImport_AddModule ("__main__");
PyObject *globals = PyModule_GetDict (mainmod);
- PyObject *locals = globals;
+ PyObject *locals = NULL;
PyObject *py_error = NULL;
+ bool should_decrement_locals = false;
+ if (PyDict_Check (globals))
+ {
+ PyObject *key, *value;
+ Py_ssize_t pos = 0;
+
+ while (PyDict_Next (globals, &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), m_dictionary_name.c_str()) == 0)
+ locals = value;
+ }
+ }
+
+ if (locals == NULL)
+ {
+ locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str());
+ should_decrement_locals = true;
+ }
+
+ if (locals == NULL)
+ {
+ locals = globals;
+ should_decrement_locals = false;
+ }
+
+ py_error = PyErr_Occurred();
+ if (py_error != NULL)
+ PyErr_Clear();
+
if (in_string != NULL)
{
struct _node *compiled_node = PyParser_SimpleParseString (in_string, Py_file_input);
@@ -642,6 +769,8 @@
success = true;
Py_DECREF (py_return);
}
+ if (locals && should_decrement_locals)
+ Py_DECREF (locals);
}
}
}
@@ -655,6 +784,8 @@
success = false;
}
+ LeaveSession ();
+
return success;
}
@@ -764,7 +895,8 @@
ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
CommandReturnObject &result)
{
- Debugger &debugger = m_interpreter.GetDebugger();
+ Debugger &debugger = GetCommandInterpreter().GetDebugger();
+
InputReaderSP reader_sp (new InputReader (debugger));
if (reader_sp)
@@ -861,8 +993,16 @@
// Create the function name & definition string.
- sstr.Printf ("def %s (frame, bp_loc):", auto_generated_function_name.c_str());
+ sstr.Printf ("def %s (frame, bp_loc, 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.
@@ -873,6 +1013,14 @@
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))
@@ -897,6 +1045,21 @@
{
BreakpointOptions::CommandData *bp_option_data = (BreakpointOptions::CommandData *) baton;
const char *python_function_name = bp_option_data->script_source.GetStringAtIndex (0);
+
+ if (!context)
+ return true;
+
+ Target *target = context->exe_ctx.target;
+
+ if (!target)
+ return true;
+
+ Debugger &debugger = target->GetDebugger();
+ ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
+ ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
+
+ if (!script_interpreter)
+ return true;
if (python_function_name != NULL
&& python_function_name[0] != '\0')
@@ -911,7 +1074,15 @@
SBBreakpointLocation sb_bp_loc (bp_loc_sp);
if (sb_bp_loc.IsValid() || sb_frame.IsValid())
- return LLDBSWIGPythonBreakpointCallbackFunction (python_function_name, sb_frame, sb_bp_loc);
+ {
+ python_interpreter->EnterSession ();
+ Mutex::Locker locker (GetPythonMutex());
+ bool ret_val = LLDBSWIGPythonBreakpointCallbackFunction(python_function_name,
+ python_interpreter->m_dictionary_name.c_str(),
+ sb_frame, sb_bp_loc);
+ python_interpreter->LeaveSession ();
+ return ret_val;
+ }
}
// We currently always true so we stop in case anything goes wrong when
// trying to call the script function
@@ -923,6 +1094,8 @@
{
ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
+ script_interpreter->EnterSession ();
+
LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
if (log)
@@ -932,39 +1105,172 @@
const char *pty_slave_name = script_interpreter->m_embedded_python_pty.GetSlaveName (error_str, sizeof (error_str));
if (pty_slave_name != NULL)
{
+ Mutex::Locker locker (GetPythonMutex());
+
StreamString run_string;
- PyRun_SimpleString ("save_stderr = sys.stderr");
- PyRun_SimpleString ("sys.stderr = sys.stdout");
- PyRun_SimpleString ("save_stdin = sys.stdin");
- run_string.Printf ("sys.stdin = open ('%s', 'r')", pty_slave_name);
+
+ run_string.Printf ("run_one_line (%s, 'save_stderr = sys.stderr')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'sys.stderr = sys.stdout')", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ run_string.Printf ("run_one_line (%s, 'save_stdin = sys.stdin')", script_interpreter->m_dictionary_name.c_str());
PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+ run_string.Printf ("run_one_line (%s, \"sys.stdin = open ('%s', 'r')\")", script_interpreter->m_dictionary_name.c_str(),
+ pty_slave_name);
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
// The following call drops into the embedded interpreter loop and stays there until the
// user chooses to exit from the Python interpreter.
- script_interpreter->ExecuteOneLine ("run_python_interpreter(ConsoleDict)", NULL);
+
+ run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str());
+ PyRun_SimpleString (run_string.GetData());
+ run_string.Clear ();
+
+ 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();
- PyRun_SimpleString ("sys.stdin = save_stdin");
- PyRun_SimpleString ("sys.stderr = save_stderr");
+ 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();
}
if (script_interpreter->m_embedded_thread_input_reader_sp)
script_interpreter->m_embedded_thread_input_reader_sp->SetIsDone (true);
script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor();
+
+ script_interpreter->m_pty_slave_is_open = false;
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT);
if (log)
log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton);
- // Clean up the input reader and make the debugger pop it off the stack.
- Debugger &debugger = script_interpreter->m_interpreter.GetDebugger();
+ // Clean up the input reader and make the debugger pop it off the stack.
+ Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger();
const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp;
script_interpreter->m_embedded_thread_input_reader_sp.reset();
debugger.PopInputReader (reader_sp);
+
+ script_interpreter->LeaveSession ();
return NULL;
}
+void
+ScriptInterpreterPython::Initialize ()
+{
+
+ Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
+
+ int input_fd = STDIN_FILENO;
+
+ struct termios stdin_termios;
+ bool valid_termios = ::tcgetattr (input_fd, &stdin_termios) == 0;
+
+ // Find the module that owns this code and use that path we get to
+ // set the PYTHONPATH appropriately.
+ FileSpec file_spec;
+ char python_dir_path[PATH_MAX];
+ if (Host::GetLLDBPath (ePathTypePythonDir, file_spec))
+ {
+ std::string python_path;
+ const char *curr_python_path = ::getenv ("PYTHONPATH");
+ if (curr_python_path)
+ {
+ // We have a current value for PYTHONPATH, so lets append to it
+ python_path.append (curr_python_path);
+ }
+
+ if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
+ {
+ if (!python_path.empty())
+ python_path.append (1, ':');
+ python_path.append (python_dir_path);
+ }
+
+ if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec))
+ {
+ if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
+ {
+ if (!python_path.empty())
+ python_path.append (1, ':');
+ python_path.append (python_dir_path);
+ }
+ }
+ const char *pathon_path_env_cstr = python_path.c_str();
+ ::setenv ("PYTHONPATH", pathon_path_env_cstr, 1);
+ }
+
+ Py_Initialize ();
+
+ PyObject *compiled_module = Py_CompileString (embedded_interpreter_string,
+ "embedded_interpreter.py",
+ Py_file_input);
+
+ PyObject *py_error = PyErr_Occurred ();
+ if (py_error != NULL)
+ {
+ PyErr_Print();
+ PyErr_Clear();
+ }
+
+
+ // This function is in the C++ output file generated by SWIG after it is
+ // run on all of the headers in "lldb/API/SB*.h"
+ init_lldb ();
+
+ // Update the path python uses to search for modules to include the current directory.
+
+ int success = PyRun_SimpleString ("import sys");
+ success = PyRun_SimpleString ("sys.path.append ('.')");
+
+ PyObject *pmod = NULL;
+
+ if (compiled_module)
+ {
+ pmod = PyImport_ExecCodeModule (const_cast<char*> ("embedded_interpreter"),
+ compiled_module);
+ Py_DECREF (compiled_module);
+ }
+
+ if (pmod != NULL)
+ {
+ PyRun_SimpleString ("from embedded_interpreter import run_python_interpreter");
+ PyRun_SimpleString ("from embedded_interpreter import run_one_line");
+ PyRun_SimpleString ("import sys");
+ PyRun_SimpleString ("from termios import *");
+ Py_DECREF (pmod);
+ }
+
+ if (valid_termios)
+ ::tcsetattr (input_fd, TCSANOW, &stdin_termios);
+}
+
+void
+ScriptInterpreterPython::Terminate ()
+{
+ // We are intentionally NOT calling Py_Finalize here (this would be the logical place to call it). Calling
+ // Py_Finalize here causes test suite runs to seg fault: The test suite runs in Python. It registers
+ // SBDebugger::Terminate to be called 'at_exit'. When the test suite Python harness finishes up, it calls
+ // Py_Finalize, which calls all the 'at_exit' registered functions. SBDebugger::Terminate calls Debugger::Terminate,
+ // which calls lldb::Terminate, which calls ScriptInterpreter::Terminate, which calls
+ // ScriptInterpreterPython::Terminate. So if we call Py_Finalize here, we end up with Py_Finalize being called from
+ // within Py_Finalize, which results in a seg fault.
+ //
+ // Since this function only gets called when lldb is shutting down and going away anyway, the fact that we don't
+ // actually call Py_Finalize should not cause any problems (everything should shut down/go away anyway when the
+ // process exits).
+ //
+// Py_Finalize ();
+}
Modified: lldb/trunk/source/Interpreter/embedded_interpreter.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/embedded_interpreter.py?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/Interpreter/embedded_interpreter.py (original)
+++ lldb/trunk/source/Interpreter/embedded_interpreter.py Thu Jan 13 18:29:16 2011
@@ -84,7 +84,20 @@
if not more:
break
+ def one_line (self, input):
+ line = self.process_input (input)
+ more = self.push(line)
+ if more:
+ self.write ("Input not a complete line.")
+ self.resetbuffer()
+ more = 0
+
def run_python_interpreter (dict):
# Pass in the dictionary, for continuity from one session to the next.
repl = SimpleREPL('>>> ', dict)
repl.interact()
+
+def run_one_line (dict, input_string):
+ repl = SimpleREPL ('', dict)
+ repl.one_line (input_string)
+
Modified: lldb/trunk/source/lldb.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/lldb.cpp?rev=123415&r1=123414&r2=123415&view=diff
==============================================================================
--- lldb/trunk/source/lldb.cpp (original)
+++ lldb/trunk/source/lldb.cpp Thu Jan 13 18:29:16 2011
@@ -14,6 +14,7 @@
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/Mutex.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
@@ -53,7 +54,7 @@
lldb_private::Initialize ()
{
// Make sure we inialize only once
- static Mutex g_inited_mutex(Mutex::eMutexTypeNormal);
+ static Mutex g_inited_mutex(Mutex::eMutexTypeRecursive);
static bool g_inited = false;
Mutex::Locker locker(g_inited_mutex);
@@ -75,6 +76,7 @@
UnwindAssemblyProfiler_x86::Initialize();
ArchDefaultUnwindPlan_x86::Initialize();
ArchVolatileRegs_x86::Initialize();
+ ScriptInterpreter::Initialize ();
#ifdef __APPLE__
ABIMacOSX_i386::Initialize();
@@ -114,6 +116,7 @@
UnwindAssemblyProfiler_x86::Terminate();
ArchDefaultUnwindPlan_x86::Terminate();
ArchVolatileRegs_x86::Terminate();
+ ScriptInterpreter::Terminate ();
#ifdef __APPLE__
DynamicLoaderMacOSXDYLD::Terminate();
More information about the lldb-commits
mailing list