2013-08-23 13:46:38 -04:00
//===-- ScriptInterpreterPython.cpp -----------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// In order to guarantee correct working with Python, Python.h *MUST* be
// the *FIRST* header file included here.
# ifdef LLDB_DISABLE_PYTHON
// Python is disabled in this build
# else
2013-12-03 13:51:59 -05:00
# include "lldb/lldb-python.h"
2013-08-23 13:46:38 -04:00
# include "lldb/Interpreter/ScriptInterpreterPython.h"
# include <stdlib.h>
# include <stdio.h>
# include <string>
# include "lldb/API/SBValue.h"
# include "lldb/Breakpoint/BreakpointLocation.h"
# include "lldb/Breakpoint/StoppointCallbackContext.h"
# include "lldb/Breakpoint/WatchpointOptions.h"
# include "lldb/Core/Debugger.h"
# include "lldb/Core/Timer.h"
# include "lldb/Host/Host.h"
# include "lldb/Interpreter/CommandInterpreter.h"
# include "lldb/Interpreter/CommandReturnObject.h"
# include "lldb/Target/Thread.h"
using namespace lldb ;
using namespace lldb_private ;
static ScriptInterpreter : : SWIGInitCallback g_swig_init_callback = NULL ;
static ScriptInterpreter : : SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL ;
static ScriptInterpreter : : SWIGWatchpointCallbackFunction g_swig_watchpoint_callback = NULL ;
static ScriptInterpreter : : SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL ;
static ScriptInterpreter : : SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = NULL ;
static ScriptInterpreter : : SWIGPythonCalculateNumChildren g_swig_calc_children = NULL ;
static ScriptInterpreter : : SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL ;
static ScriptInterpreter : : SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL ;
static ScriptInterpreter : : SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL ;
2013-11-06 11:48:53 -05:00
static ScriptInterpreter : : SWIGPythonGetValueObjectSPFromSBValue g_swig_get_valobj_sp_from_sbvalue = NULL ;
2013-08-23 13:46:38 -04:00
static ScriptInterpreter : : SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL ;
static ScriptInterpreter : : SWIGPythonMightHaveChildrenSynthProviderInstance g_swig_mighthavechildren_provider = NULL ;
static ScriptInterpreter : : SWIGPythonCallCommand g_swig_call_command = NULL ;
static ScriptInterpreter : : SWIGPythonCallModuleInit g_swig_call_module_init = NULL ;
static ScriptInterpreter : : SWIGPythonCreateOSPlugin g_swig_create_os_plugin = NULL ;
static ScriptInterpreter : : SWIGPythonScriptKeyword_Process g_swig_run_script_keyword_process = NULL ;
static ScriptInterpreter : : SWIGPythonScriptKeyword_Thread g_swig_run_script_keyword_thread = NULL ;
static ScriptInterpreter : : SWIGPythonScriptKeyword_Target g_swig_run_script_keyword_target = NULL ;
static ScriptInterpreter : : SWIGPythonScriptKeyword_Frame g_swig_run_script_keyword_frame = NULL ;
2013-11-06 11:48:53 -05:00
static ScriptInterpreter : : SWIGPython_GetDynamicSetting g_swig_plugin_get = NULL ;
2013-08-23 13:46:38 -04:00
static int
_check_and_flush ( FILE * stream )
{
int prev_fail = ferror ( stream ) ;
return fflush ( stream ) | | prev_fail ? EOF : 0 ;
}
ScriptInterpreterPython : : Locker : : Locker ( ScriptInterpreterPython * py_interpreter ,
uint16_t on_entry ,
uint16_t on_leave ,
FILE * wait_msg_handle ) :
ScriptInterpreterLocker ( ) ,
m_teardown_session ( ( on_leave & TearDownSession ) = = TearDownSession ) ,
m_python_interpreter ( py_interpreter ) ,
m_tmp_fh ( wait_msg_handle )
{
if ( m_python_interpreter & & ! m_tmp_fh )
m_tmp_fh = ( m_python_interpreter - > m_dbg_stdout ? m_python_interpreter - > m_dbg_stdout : stdout ) ;
DoAcquireLock ( ) ;
if ( ( on_entry & InitSession ) = = InitSession )
{
if ( DoInitSession ( ( on_entry & InitGlobals ) = = InitGlobals ) = = false )
{
// Don't teardown the session if we didn't init it.
m_teardown_session = false ;
}
}
}
bool
ScriptInterpreterPython : : Locker : : DoAcquireLock ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE ) ) ;
m_GILState = PyGILState_Ensure ( ) ;
if ( log )
log - > Printf ( " Ensured PyGILState. Previous state = %slocked \n " , m_GILState = = PyGILState_UNLOCKED ? " un " : " " ) ;
return true ;
}
bool
ScriptInterpreterPython : : Locker : : DoInitSession ( bool init_lldb_globals )
{
if ( ! m_python_interpreter )
return false ;
return m_python_interpreter - > EnterSession ( init_lldb_globals ) ;
}
bool
ScriptInterpreterPython : : Locker : : DoFreeLock ( )
{
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE ) ) ;
if ( log )
log - > Printf ( " Releasing PyGILState. Returning to state = %slocked \n " , m_GILState = = PyGILState_UNLOCKED ? " un " : " " ) ;
PyGILState_Release ( m_GILState ) ;
return true ;
}
bool
ScriptInterpreterPython : : Locker : : DoTearDownSession ( )
{
if ( ! m_python_interpreter )
return false ;
m_python_interpreter - > LeaveSession ( ) ;
return true ;
}
ScriptInterpreterPython : : Locker : : ~ Locker ( )
{
if ( m_teardown_session )
DoTearDownSession ( ) ;
DoFreeLock ( ) ;
}
ScriptInterpreterPython : : PythonInputReaderManager : : PythonInputReaderManager ( ScriptInterpreterPython * interpreter ) :
m_interpreter ( interpreter ) ,
m_debugger_sp ( ) ,
m_reader_sp ( ) ,
m_error ( false )
{
if ( m_interpreter = = NULL )
{
m_error = true ;
return ;
}
m_debugger_sp = m_interpreter - > GetCommandInterpreter ( ) . GetDebugger ( ) . shared_from_this ( ) ;
if ( ! m_debugger_sp )
{
m_error = true ;
return ;
}
m_reader_sp = InputReaderSP ( new InputReader ( * m_debugger_sp . get ( ) ) ) ;
if ( ! m_reader_sp )
{
m_error = true ;
return ;
}
Error error ( m_reader_sp - > Initialize ( ScriptInterpreterPython : : PythonInputReaderManager : : InputReaderCallback ,
m_interpreter , // baton
eInputReaderGranularityLine , // token size, to pass to callback function
NULL , // end token
NULL , // prompt
true ) ) ; // echo input
if ( error . Fail ( ) )
m_error = true ;
else
{
m_debugger_sp - > PushInputReader ( m_reader_sp ) ;
m_interpreter - > m_embedded_thread_input_reader_sp = m_reader_sp ;
}
}
ScriptInterpreterPython : : PythonInputReaderManager : : ~ PythonInputReaderManager ( )
{
// Nothing to do if either m_interpreter or m_reader_sp is invalid.
if ( ! m_interpreter | | ! m_reader_sp )
return ;
m_reader_sp - > SetIsDone ( true ) ;
if ( m_debugger_sp )
m_debugger_sp - > PopInputReader ( m_reader_sp ) ;
// Only mess with m_interpreter's counterpart if, indeed, they are the same object.
if ( m_reader_sp . get ( ) = = m_interpreter - > m_embedded_thread_input_reader_sp . get ( ) )
{
m_interpreter - > m_embedded_thread_pty . CloseSlaveFileDescriptor ( ) ;
m_interpreter - > m_embedded_thread_input_reader_sp . reset ( ) ;
}
}
size_t
ScriptInterpreterPython : : PythonInputReaderManager : : InputReaderCallback ( void * baton ,
InputReader & reader ,
InputReaderAction notification ,
const char * bytes ,
size_t bytes_len )
{
lldb : : thread_t embedded_interpreter_thread ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT ) ) ;
if ( baton = = NULL )
return 0 ;
ScriptInterpreterPython * script_interpreter = ( ScriptInterpreterPython * ) baton ;
if ( script_interpreter - > m_script_lang ! = eScriptLanguagePython )
return 0 ;
switch ( notification )
{
case eInputReaderActivate :
{
// Save terminal settings if we can
int input_fd = reader . GetDebugger ( ) . GetInputFile ( ) . GetDescriptor ( ) ;
if ( input_fd = = File : : kInvalidDescriptor )
input_fd = STDIN_FILENO ;
script_interpreter - > SaveTerminalState ( input_fd ) ;
char error_str [ 1024 ] ;
if ( script_interpreter - > m_embedded_thread_pty . OpenFirstAvailableMaster ( O_RDWR | O_NOCTTY , error_str ,
sizeof ( error_str ) ) )
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in opening master pty (fd = %d). " ,
script_interpreter - > m_embedded_thread_pty . GetMasterFileDescriptor ( ) ) ;
{
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 : : InitGlobals ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock ) ;
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 ( ) ;
}
}
embedded_interpreter_thread = Host : : ThreadCreate ( " <lldb.script-interpreter.noninteractive-python> " ,
ScriptInterpreterPython : : PythonInputReaderManager : : RunPythonInputReader ,
script_interpreter , NULL ) ;
if ( IS_VALID_LLDB_HOST_THREAD ( embedded_interpreter_thread ) )
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, succeeded in creating thread (thread_t = %p) " , ( void * ) embedded_interpreter_thread ) ;
Error detach_error ;
Host : : ThreadDetach ( embedded_interpreter_thread , & detach_error ) ;
}
else
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed in creating thread " ) ;
reader . SetIsDone ( true ) ;
}
}
else
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, Activate, failed to open master pty " ) ;
reader . SetIsDone ( true ) ;
}
}
break ;
case eInputReaderDeactivate :
// When another input reader is pushed, don't leave the session...
//script_interpreter->LeaveSession ();
break ;
case eInputReaderReactivate :
// {
// ScriptInterpreterPython::Locker locker(script_interpreter,
// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
// ScriptInterpreterPython::Locker::FreeAcquiredLock);
// }
break ;
case eInputReaderAsynchronousOutputWritten :
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 ) ;
}
else if ( log )
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, eInputReaderInterrupt, state = NULL " ) ;
}
break ;
case eInputReaderEndOfFile :
reader . SetIsDone ( true ) ;
break ;
case eInputReaderGotToken :
if ( script_interpreter - > m_embedded_thread_pty . GetMasterFileDescriptor ( ) ! = - 1 )
{
if ( log )
2013-11-06 11:48:53 -05:00
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %zu " , bytes ,
2013-08-23 13:46:38 -04:00
bytes_len ) ;
if ( bytes & & bytes_len )
: : write ( script_interpreter - > m_embedded_thread_pty . GetMasterFileDescriptor ( ) , bytes , bytes_len ) ;
: : write ( script_interpreter - > m_embedded_thread_pty . GetMasterFileDescriptor ( ) , " \n " , 1 ) ;
}
else
{
if ( log )
2013-11-06 11:48:53 -05:00
log - > Printf ( " ScriptInterpreterPython::NonInteractiveInputReaderCallback, GotToken, bytes='%s', byte_len = %zu, Master File Descriptor is bad. " ,
2013-08-23 13:46:38 -04:00
bytes ,
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 : : 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. " ) ;
script_interpreter - > RestoreTerminalState ( ) ;
script_interpreter - > m_embedded_thread_pty . CloseMasterFileDescriptor ( ) ;
}
break ;
}
return bytes_len ;
}
ScriptInterpreterPython : : ScriptInterpreterPython ( CommandInterpreter & interpreter ) :
ScriptInterpreter ( interpreter , eScriptLanguagePython ) ,
m_embedded_thread_pty ( ) ,
m_embedded_python_pty ( ) ,
m_embedded_thread_input_reader_sp ( ) ,
m_embedded_python_input_reader_sp ( ) ,
m_dbg_stdout ( interpreter . GetDebugger ( ) . GetOutputFile ( ) . GetStream ( ) ) ,
m_new_sysout ( NULL ) ,
m_old_sysout ( NULL ) ,
m_old_syserr ( NULL ) ,
m_run_one_line ( NULL ) ,
m_dictionary_name ( interpreter . GetDebugger ( ) . GetInstanceName ( ) . AsCString ( ) ) ,
m_terminal_state ( ) ,
m_session_is_active ( false ) ,
m_valid_session ( true ) ,
m_command_thread_state ( NULL )
{
static int g_initialized = false ;
if ( ! g_initialized )
{
g_initialized = true ;
ScriptInterpreterPython : : InitializePrivate ( ) ;
}
m_dictionary_name . append ( " _dict " ) ;
StreamString run_string ;
run_string . Printf ( " %s = dict() " , m_dictionary_name . c_str ( ) ) ;
Locker locker ( this ,
ScriptInterpreterPython : : Locker : : AcquireLock ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock ) ;
PyRun_SimpleString ( run_string . GetData ( ) ) ;
run_string . Clear ( ) ;
// 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 ( ) ;
run_string . Printf ( " run_one_line (%s, 'import copy, os, re, sys, uuid, lldb') " , m_dictionary_name . c_str ( ) ) ;
PyRun_SimpleString ( run_string . GetData ( ) ) ;
// WARNING: temporary code that loads Cocoa formatters - this should be done on a per-platform basis rather than loading the whole set
// and letting the individual formatter classes exploit APIs to check whether they can/cannot do their task
run_string . Clear ( ) ;
run_string . Printf ( " run_one_line (%s, 'import lldb.formatters, lldb.formatters.cpp, pydoc') " , m_dictionary_name . c_str ( ) ) ;
PyRun_SimpleString ( run_string . GetData ( ) ) ;
int new_count = Debugger : : TestDebuggerRefCount ( ) ;
if ( new_count > old_count )
Debugger : : Terminate ( ) ;
run_string . Clear ( ) ;
run_string . Printf ( " run_one_line (%s, 'lldb.debugger_unique_id = % " PRIu64 " ; pydoc.pager = pydoc.plainpager') " , m_dictionary_name . c_str ( ) ,
interpreter . GetDebugger ( ) . GetID ( ) ) ;
PyRun_SimpleString ( run_string . GetData ( ) ) ;
if ( m_dbg_stdout ! = NULL )
{
m_new_sysout = PyFile_FromFile ( m_dbg_stdout , ( char * ) " " , ( char * ) " w " , _check_and_flush ) ;
}
// get the output file handle from the debugger (if any)
File & out_file = interpreter . GetDebugger ( ) . GetOutputFile ( ) ;
if ( out_file . IsValid ( ) )
ResetOutputFileHandle ( out_file . GetStream ( ) ) ;
}
ScriptInterpreterPython : : ~ ScriptInterpreterPython ( )
{
Debugger & debugger = GetCommandInterpreter ( ) . GetDebugger ( ) ;
if ( m_embedded_thread_input_reader_sp . get ( ) ! = NULL )
{
m_embedded_thread_input_reader_sp - > SetIsDone ( true ) ;
m_embedded_thread_pty . CloseSlaveFileDescriptor ( ) ;
const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp ;
debugger . PopInputReader ( reader_sp ) ;
m_embedded_thread_input_reader_sp . reset ( ) ;
}
if ( m_embedded_python_input_reader_sp . get ( ) ! = NULL )
{
m_embedded_python_input_reader_sp - > SetIsDone ( true ) ;
m_embedded_python_pty . CloseSlaveFileDescriptor ( ) ;
const InputReaderSP reader_sp = m_embedded_python_input_reader_sp ;
debugger . PopInputReader ( reader_sp ) ;
m_embedded_python_input_reader_sp . reset ( ) ;
}
if ( m_new_sysout )
{
Locker locker ( this ,
ScriptInterpreterPython : : Locker : : AcquireLock ,
ScriptInterpreterPython : : Locker : : FreeLock ) ;
Py_XDECREF ( ( PyObject * ) m_new_sysout ) ;
}
}
void
ScriptInterpreterPython : : ResetOutputFileHandle ( FILE * fh )
{
if ( fh = = NULL )
return ;
m_dbg_stdout = fh ;
Locker locker ( this ,
ScriptInterpreterPython : : Locker : : AcquireLock ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock ) ;
m_new_sysout = PyFile_FromFile ( m_dbg_stdout , ( char * ) " " , ( char * ) " w " , _check_and_flush ) ;
}
void
ScriptInterpreterPython : : SaveTerminalState ( int fd )
{
// Python mucks with the terminal state of STDIN. If we can possibly avoid
// this by setting the file handles up correctly prior to entering the
// interpreter we should. For now we save and restore the terminal state
// on the input file handle.
m_terminal_state . Save ( fd , false ) ;
}
void
ScriptInterpreterPython : : RestoreTerminalState ( )
{
// Python mucks with the terminal state of STDIN. If we can possibly avoid
// this by setting the file handles up correctly prior to entering the
// interpreter we should. For now we save and restore the terminal state
// on the input file handle.
m_terminal_state . Restore ( ) ;
}
void
ScriptInterpreterPython : : LeaveSession ( )
{
Log * 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
// when destroying the SBDebugger, we can make do without clearing up stdout and stderr
// rdar://problem/11292882
// When the current thread state is NULL, PyThreadState_Get() issues a fatal error.
if ( PyThreadState_GetDict ( ) )
{
PyObject * sysmod = PyImport_AddModule ( " sys " ) ;
PyObject * sysdict = PyModule_GetDict ( sysmod ) ;
if ( m_new_sysout & & sysmod & & sysdict )
{
if ( m_old_sysout )
PyDict_SetItemString ( sysdict , " stdout " , ( PyObject * ) m_old_sysout ) ;
if ( m_old_syserr )
PyDict_SetItemString ( sysdict , " stderr " , ( PyObject * ) m_old_syserr ) ;
}
}
m_session_is_active = false ;
}
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.
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT ) ) ;
if ( m_session_is_active )
{
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 ;
StreamString run_string ;
if ( init_lldb_globals )
{
run_string . Printf ( " run_one_line (%s, 'lldb.debugger_unique_id = % " PRIu64 , m_dictionary_name . c_str ( ) , GetCommandInterpreter ( ) . GetDebugger ( ) . GetID ( ) ) ;
run_string . Printf ( " ; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (% " PRIu64 " ) " , GetCommandInterpreter ( ) . GetDebugger ( ) . GetID ( ) ) ;
run_string . PutCString ( " ; lldb.target = lldb.debugger.GetSelectedTarget() " ) ;
run_string . PutCString ( " ; lldb.process = lldb.target.GetProcess() " ) ;
run_string . PutCString ( " ; lldb.thread = lldb.process.GetSelectedThread () " ) ;
run_string . PutCString ( " ; lldb.frame = lldb.thread.GetSelectedFrame () " ) ;
run_string . PutCString ( " ') " ) ;
}
else
{
// If we aren't initing the globals, we should still always set the debugger (since that is always unique.)
run_string . Printf ( " run_one_line (%s, \" lldb.debugger_unique_id = % " PRIu64 , m_dictionary_name . c_str ( ) , GetCommandInterpreter ( ) . GetDebugger ( ) . GetID ( ) ) ;
run_string . Printf ( " ; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (% " PRIu64 " ) " , GetCommandInterpreter ( ) . GetDebugger ( ) . GetID ( ) ) ;
run_string . PutCString ( " \" ) " ) ;
}
PyRun_SimpleString ( run_string . GetData ( ) ) ;
run_string . Clear ( ) ;
PyObject * sysmod = PyImport_AddModule ( " sys " ) ;
PyObject * sysdict = PyModule_GetDict ( sysmod ) ;
if ( m_new_sysout & & sysmod & & sysdict )
{
m_old_sysout = PyDict_GetItemString ( sysdict , " stdout " ) ;
m_old_syserr = PyDict_GetItemString ( sysdict , " stderr " ) ;
if ( m_new_sysout )
{
PyDict_SetItemString ( sysdict , " stdout " , ( PyObject * ) m_new_sysout ) ;
PyDict_SetItemString ( sysdict , " stderr " , ( PyObject * ) m_new_sysout ) ;
}
}
if ( PyErr_Occurred ( ) )
PyErr_Clear ( ) ;
return true ;
}
static PyObject *
FindSessionDictionary ( const char * dict_name )
{
static std : : map < ConstString , PyObject * > g_dict_map ;
ConstString dict ( dict_name ) ;
std : : map < ConstString , PyObject * > : : iterator iter = g_dict_map . find ( dict ) ;
if ( iter ! = g_dict_map . end ( ) )
return iter - > second ;
PyObject * main_mod = PyImport_AddModule ( " __main__ " ) ;
if ( main_mod ! = NULL )
{
PyObject * main_dict = PyModule_GetDict ( main_mod ) ;
if ( ( main_dict ! = NULL )
& & PyDict_Check ( main_dict ) )
{
// Go through the main dictionary looking for the correct python script interpreter dictionary
PyObject * key , * value ;
Py_ssize_t pos = 0 ;
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 ) , dict_name ) = = 0 )
{
g_dict_map [ dict ] = value ;
return value ;
}
}
}
}
return NULL ;
}
static std : : string
GenerateUniqueName ( const char * base_name_wanted ,
uint32_t & functions_counter ,
void * name_token = NULL )
{
StreamString sstr ;
if ( ! base_name_wanted )
return std : : string ( ) ;
if ( ! name_token )
sstr . Printf ( " %s_%d " , base_name_wanted , functions_counter + + ) ;
else
sstr . Printf ( " %s_%p " , base_name_wanted , name_token ) ;
return sstr . GetString ( ) ;
}
bool
ScriptInterpreterPython : : ExecuteOneLine ( const char * command , CommandReturnObject * result , const ExecuteScriptOptions & options )
{
if ( ! m_valid_session )
return false ;
// We want to call run_one_line, passing in the dictionary and the command string. We cannot do this through
// PyRun_SimpleString here because the command string may contain escaped characters, and putting it inside
// another string to pass to PyRun_SimpleString messes up the escaping. So we use the following more complicated
// method to pass the command string directly down to Python.
Locker locker ( this ,
ScriptInterpreterPython : : Locker : : AcquireLock | ScriptInterpreterPython : : Locker : : InitSession | ( options . GetSetLLDBGlobals ( ) ? ScriptInterpreterPython : : Locker : : InitGlobals : 0 ) ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock | ScriptInterpreterPython : : Locker : : TearDownSession ) ;
bool success = false ;
if ( command )
{
// Find the correct script interpreter dictionary in the main module.
PyObject * script_interpreter_dict = FindSessionDictionary ( m_dictionary_name . c_str ( ) ) ;
if ( script_interpreter_dict ! = NULL )
{
PyObject * pfunc = ( PyObject * ) m_run_one_line ;
PyObject * pmod = PyImport_AddModule ( " lldb.embedded_interpreter " ) ;
if ( pmod ! = NULL )
{
PyObject * pmod_dict = PyModule_GetDict ( pmod ) ;
if ( ( pmod_dict ! = NULL )
& & PyDict_Check ( pmod_dict ) )
{
if ( ! pfunc )
{
PyObject * key , * value ;
Py_ssize_t pos = 0 ;
while ( PyDict_Next ( pmod_dict , & pos , & key , & value ) )
{
Py_INCREF ( key ) ;
Py_INCREF ( value ) ;
if ( strcmp ( PyString_AsString ( key ) , " run_one_line " ) = = 0 )
{
pfunc = value ;
break ;
}
}
m_run_one_line = pfunc ;
}
if ( pfunc & & PyCallable_Check ( pfunc ) )
{
PyObject * pargs = Py_BuildValue ( " (Os) " , script_interpreter_dict , command ) ;
if ( pargs ! = NULL )
{
PyObject * pvalue = NULL ;
{ // scope for PythonInputReaderManager
PythonInputReaderManager py_input ( options . GetEnableIO ( ) ? this : NULL ) ;
pvalue = PyObject_CallObject ( pfunc , pargs ) ;
}
Py_XDECREF ( pargs ) ;
if ( pvalue ! = NULL )
{
Py_XDECREF ( pvalue ) ;
success = true ;
}
else if ( options . GetMaskoutErrors ( ) & & PyErr_Occurred ( ) )
{
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
}
}
}
}
}
Py_INCREF ( script_interpreter_dict ) ;
}
if ( success )
return true ;
// The one-liner failed. Append the error message.
if ( result )
result - > AppendErrorWithFormat ( " python failed attempting to evaluate '%s' \n " , command ) ;
return false ;
}
if ( result )
result - > AppendError ( " empty command passed to python \n " ) ;
return false ;
}
size_t
ScriptInterpreterPython : : InputReaderCallback
(
void * baton ,
InputReader & reader ,
InputReaderAction notification ,
const char * bytes ,
size_t bytes_len
)
{
lldb : : thread_t embedded_interpreter_thread ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT ) ) ;
if ( baton = = NULL )
return 0 ;
ScriptInterpreterPython * script_interpreter = ( ScriptInterpreterPython * ) baton ;
if ( script_interpreter - > m_script_lang ! = eScriptLanguagePython )
return 0 ;
switch ( notification )
{
case eInputReaderActivate :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
if ( ! batch_mode )
{
out_stream - > Printf ( " Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D. \n " ) ;
out_stream - > Flush ( ) ;
}
// Save terminal settings if we can
int input_fd = reader . GetDebugger ( ) . GetInputFile ( ) . GetDescriptor ( ) ;
if ( input_fd = = File : : kInvalidDescriptor )
input_fd = STDIN_FILENO ;
script_interpreter - > SaveTerminalState ( input_fd ) ;
{
ScriptInterpreterPython : : Locker locker ( script_interpreter ,
ScriptInterpreterPython : : Locker : : AcquireLock | ScriptInterpreterPython : : Locker : : InitSession | ScriptInterpreterPython : : Locker : : InitGlobals ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock ) ;
}
char error_str [ 1024 ] ;
if ( script_interpreter - > m_embedded_python_pty . OpenFirstAvailableMaster ( O_RDWR | O_NOCTTY , error_str ,
sizeof ( error_str ) ) )
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in opening master pty (fd = %d). " ,
script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) ) ;
embedded_interpreter_thread = Host : : ThreadCreate ( " <lldb.script-interpreter.embedded-python-loop> " ,
ScriptInterpreterPython : : RunEmbeddedPythonInterpreter ,
script_interpreter , NULL ) ;
if ( IS_VALID_LLDB_HOST_THREAD ( embedded_interpreter_thread ) )
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in creating thread (thread_t = %p) " , ( void * ) embedded_interpreter_thread ) ;
Error detach_error ;
Host : : ThreadDetach ( embedded_interpreter_thread , & detach_error ) ;
}
else
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, Activate, failed in creating thread " ) ;
reader . SetIsDone ( true ) ;
}
}
else
{
if ( log )
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, Activate, failed to open master pty " ) ;
reader . SetIsDone ( true ) ;
}
}
break ;
case eInputReaderDeactivate :
// When another input reader is pushed, don't leave the session...
//script_interpreter->LeaveSession ();
break ;
case eInputReaderReactivate :
{
ScriptInterpreterPython : : Locker locker ( script_interpreter ,
ScriptInterpreterPython : : Locker : : AcquireLock | ScriptInterpreterPython : : Locker : : InitSession ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock ) ;
}
break ;
case eInputReaderAsynchronousOutputWritten :
break ;
case eInputReaderInterrupt :
: : write ( script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) , " raise KeyboardInterrupt \n " , 24 ) ;
break ;
case eInputReaderEndOfFile :
: : write ( script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) , " quit() \n " , 7 ) ;
break ;
case eInputReaderGotToken :
if ( script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) ! = - 1 )
{
if ( log )
2013-11-06 11:48:53 -05:00
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %zu " , bytes ,
2013-08-23 13:46:38 -04:00
bytes_len ) ;
if ( bytes & & bytes_len )
{
if ( ( int ) bytes [ 0 ] = = 4 )
: : write ( script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) , " quit() " , 6 ) ;
else
: : write ( script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) , bytes , bytes_len ) ;
}
: : write ( script_interpreter - > m_embedded_python_pty . GetMasterFileDescriptor ( ) , " \n " , 1 ) ;
}
else
{
if ( log )
2013-11-06 11:48:53 -05:00
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %zu, Master File Descriptor is bad. " ,
2013-08-23 13:46:38 -04:00
bytes ,
bytes_len ) ;
reader . SetIsDone ( true ) ;
}
break ;
case eInputReaderDone :
{
Locker locker ( script_interpreter ,
ScriptInterpreterPython : : Locker : : AcquireLock ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock ) ;
script_interpreter - > LeaveSession ( ) ;
}
// Restore terminal settings if they were validly saved
if ( log )
log - > Printf ( " ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader. " ) ;
script_interpreter - > RestoreTerminalState ( ) ;
script_interpreter - > m_embedded_python_pty . CloseMasterFileDescriptor ( ) ;
break ;
}
return bytes_len ;
}
void
ScriptInterpreterPython : : ExecuteInterpreterLoop ( )
{
Timer scoped_timer ( __PRETTY_FUNCTION__ , __PRETTY_FUNCTION__ ) ;
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
// try to embed a running interpreter loop inside the already running Python interpreter loop, so we won't
// do it.
if ( ! debugger . GetInputFile ( ) . IsValid ( ) )
return ;
InputReaderSP reader_sp ( new InputReader ( debugger ) ) ;
if ( reader_sp )
{
Error error ( reader_sp - > Initialize ( ScriptInterpreterPython : : InputReaderCallback ,
this , // baton
eInputReaderGranularityLine , // token size, to pass to callback function
NULL , // end token
NULL , // prompt
true ) ) ; // echo input
if ( error . Success ( ) )
{
debugger . PushInputReader ( reader_sp ) ;
m_embedded_python_input_reader_sp = reader_sp ;
}
}
}
bool
ScriptInterpreterPython : : ExecuteOneLineWithReturn ( const char * in_string ,
ScriptInterpreter : : ScriptReturnType return_type ,
void * ret_value ,
const ExecuteScriptOptions & options )
{
Locker locker ( this ,
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__ " ) ;
PyObject * globals = PyModule_GetDict ( mainmod ) ;
PyObject * locals = NULL ;
PyObject * py_error = NULL ;
bool ret_success = false ;
bool should_decrement_locals = false ;
int success ;
locals = FindSessionDictionary ( m_dictionary_name . c_str ( ) ) ;
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 )
{
{ // scope for PythonInputReaderManager
PythonInputReaderManager py_input ( options . GetEnableIO ( ) ? this : NULL ) ;
py_return = PyRun_String ( in_string , Py_eval_input , globals , locals ) ;
if ( py_return = = NULL )
{
py_error = PyErr_Occurred ( ) ;
if ( py_error ! = NULL )
PyErr_Clear ( ) ;
py_return = PyRun_String ( in_string , Py_single_input , globals , locals ) ;
}
}
if ( locals ! = NULL
& & should_decrement_locals )
Py_XDECREF ( locals ) ;
if ( py_return ! = NULL )
{
switch ( return_type )
{
case eScriptReturnTypeCharPtr : // "char *"
{
const char format [ 3 ] = " s# " ;
success = PyArg_Parse ( py_return , format , ( char * * ) ret_value ) ;
break ;
}
case eScriptReturnTypeCharStrOrNone : // char* or NULL if py_return == Py_None
{
const char format [ 3 ] = " z " ;
success = PyArg_Parse ( py_return , format , ( char * * ) ret_value ) ;
break ;
}
case eScriptReturnTypeBool :
{
const char format [ 2 ] = " b " ;
success = PyArg_Parse ( py_return , format , ( bool * ) ret_value ) ;
break ;
}
case eScriptReturnTypeShortInt :
{
const char format [ 2 ] = " h " ;
success = PyArg_Parse ( py_return , format , ( short * ) ret_value ) ;
break ;
}
case eScriptReturnTypeShortIntUnsigned :
{
const char format [ 2 ] = " H " ;
success = PyArg_Parse ( py_return , format , ( unsigned short * ) ret_value ) ;
break ;
}
case eScriptReturnTypeInt :
{
const char format [ 2 ] = " i " ;
success = PyArg_Parse ( py_return , format , ( int * ) ret_value ) ;
break ;
}
case eScriptReturnTypeIntUnsigned :
{
const char format [ 2 ] = " I " ;
success = PyArg_Parse ( py_return , format , ( unsigned int * ) ret_value ) ;
break ;
}
case eScriptReturnTypeLongInt :
{
const char format [ 2 ] = " l " ;
success = PyArg_Parse ( py_return , format , ( long * ) ret_value ) ;
break ;
}
case eScriptReturnTypeLongIntUnsigned :
{
const char format [ 2 ] = " k " ;
success = PyArg_Parse ( py_return , format , ( unsigned long * ) ret_value ) ;
break ;
}
case eScriptReturnTypeLongLong :
{
const char format [ 2 ] = " L " ;
success = PyArg_Parse ( py_return , format , ( long long * ) ret_value ) ;
break ;
}
case eScriptReturnTypeLongLongUnsigned :
{
const char format [ 2 ] = " K " ;
success = PyArg_Parse ( py_return , format , ( unsigned long long * ) ret_value ) ;
break ;
}
case eScriptReturnTypeFloat :
{
const char format [ 2 ] = " f " ;
success = PyArg_Parse ( py_return , format , ( float * ) ret_value ) ;
break ;
}
case eScriptReturnTypeDouble :
{
const char format [ 2 ] = " d " ;
success = PyArg_Parse ( py_return , format , ( double * ) ret_value ) ;
break ;
}
case eScriptReturnTypeChar :
{
const char format [ 2 ] = " c " ;
success = PyArg_Parse ( py_return , format , ( char * ) ret_value ) ;
break ;
}
2013-11-06 11:48:53 -05:00
case eScriptReturnTypeOpaqueObject :
{
success = true ;
Py_XINCREF ( py_return ) ;
* ( ( PyObject * * ) ret_value ) = py_return ;
break ;
}
2013-08-23 13:46:38 -04:00
}
Py_XDECREF ( py_return ) ;
if ( success )
ret_success = true ;
else
ret_success = false ;
}
}
py_error = PyErr_Occurred ( ) ;
if ( py_error ! = NULL )
{
ret_success = false ;
if ( options . GetMaskoutErrors ( ) )
{
if ( PyErr_GivenExceptionMatches ( py_error , PyExc_SyntaxError ) )
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
}
}
return ret_success ;
}
bool
ScriptInterpreterPython : : ExecuteMultipleLines ( const char * in_string , const ExecuteScriptOptions & options )
{
Locker locker ( this ,
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 ;
PyObject * mainmod = PyImport_AddModule ( " __main__ " ) ;
PyObject * globals = PyModule_GetDict ( mainmod ) ;
PyObject * locals = NULL ;
PyObject * py_error = NULL ;
bool should_decrement_locals = false ;
locals = FindSessionDictionary ( m_dictionary_name . c_str ( ) ) ;
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 ) ;
if ( compiled_node )
{
PyCodeObject * compiled_code = PyNode_Compile ( compiled_node , " temp.py " ) ;
if ( compiled_code )
{
{ // scope for PythonInputReaderManager
PythonInputReaderManager py_input ( options . GetEnableIO ( ) ? this : NULL ) ;
py_return = PyEval_EvalCode ( compiled_code , globals , locals ) ;
}
if ( py_return ! = NULL )
{
success = true ;
Py_XDECREF ( py_return ) ;
}
if ( locals & & should_decrement_locals )
Py_XDECREF ( locals ) ;
}
}
}
py_error = PyErr_Occurred ( ) ;
if ( py_error ! = NULL )
{
success = false ;
if ( options . GetMaskoutErrors ( ) )
{
if ( PyErr_GivenExceptionMatches ( py_error , PyExc_SyntaxError ) )
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
}
}
return success ;
}
static const char * g_reader_instructions = " Enter your Python command(s). Type 'DONE' to end. " ;
static const char * g_bkpt_command_reader_instructions = " Enter your Python command(s). Type 'DONE' to end. \n "
" def function(frame,bp_loc,internal_dict): \n "
" \" \" \" frame: the SBFrame for the location at which you stopped \n "
" bp_loc: an SBBreakpointLocation for the breakpoint location information \n "
" internal_dict: an LLDB support object not to be used \" \" \" " ;
size_t
ScriptInterpreterPython : : GenerateBreakpointOptionsCommandCallback
(
void * baton ,
InputReader & reader ,
InputReaderAction notification ,
const char * bytes ,
size_t bytes_len
)
{
static StringList commands_in_progress ;
switch ( notification )
{
case eInputReaderActivate :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
commands_in_progress . Clear ( ) ;
if ( ! batch_mode )
{
out_stream - > Printf ( " %s \n " , g_bkpt_command_reader_instructions ) ;
if ( reader . GetPrompt ( ) )
out_stream - > Printf ( " %s " , reader . GetPrompt ( ) ) ;
out_stream - > Flush ( ) ;
}
}
break ;
case eInputReaderDeactivate :
break ;
case eInputReaderReactivate :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
if ( reader . GetPrompt ( ) & & ! batch_mode )
{
out_stream - > Printf ( " %s " , reader . GetPrompt ( ) ) ;
out_stream - > Flush ( ) ;
}
}
break ;
case eInputReaderAsynchronousOutputWritten :
break ;
case eInputReaderGotToken :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
std : : string temp_string ( bytes , bytes_len ) ;
commands_in_progress . AppendString ( temp_string . c_str ( ) ) ;
if ( ! reader . IsDone ( ) & & reader . GetPrompt ( ) & & ! batch_mode )
{
out_stream - > Printf ( " %s " , reader . GetPrompt ( ) ) ;
out_stream - > Flush ( ) ;
}
}
break ;
case eInputReaderEndOfFile :
case eInputReaderInterrupt :
// Control-c (SIGINT) & control-d both mean finish & exit.
reader . SetIsDone ( true ) ;
// Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command.
if ( notification = = eInputReaderInterrupt )
commands_in_progress . Clear ( ) ;
// Fall through here...
case eInputReaderDone :
{
bool batch_mode = notification = = eInputReaderDone ?
reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) :
true ;
BreakpointOptions * bp_options = ( BreakpointOptions * ) baton ;
std : : unique_ptr < BreakpointOptions : : CommandData > data_ap ( new BreakpointOptions : : CommandData ( ) ) ;
data_ap - > user_source . AppendList ( commands_in_progress ) ;
if ( data_ap . get ( ) )
{
ScriptInterpreter * interpreter = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
if ( interpreter )
{
if ( interpreter - > GenerateBreakpointCommandCallbackData ( data_ap - > user_source ,
data_ap - > script_source ) )
{
BatonSP baton_sp ( new BreakpointOptions : : CommandBaton ( data_ap . release ( ) ) ) ;
bp_options - > SetCallback ( ScriptInterpreterPython : : BreakpointCallbackFunction , baton_sp ) ;
}
else if ( ! batch_mode )
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
out_stream - > Printf ( " Warning: No command attached to breakpoint. \n " ) ;
out_stream - > Flush ( ) ;
}
}
else
{
if ( ! batch_mode )
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
out_stream - > Printf ( " Warning: Unable to find script intepreter; no command attached to breakpoint. \n " ) ;
out_stream - > Flush ( ) ;
}
}
}
}
break ;
}
return bytes_len ;
}
size_t
ScriptInterpreterPython : : GenerateWatchpointOptionsCommandCallback
(
void * baton ,
InputReader & reader ,
InputReaderAction notification ,
const char * bytes ,
size_t bytes_len
)
{
static StringList commands_in_progress ;
switch ( notification )
{
case eInputReaderActivate :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
commands_in_progress . Clear ( ) ;
if ( ! batch_mode )
{
out_stream - > Printf ( " %s \n " , g_reader_instructions ) ;
if ( reader . GetPrompt ( ) )
out_stream - > Printf ( " %s " , reader . GetPrompt ( ) ) ;
out_stream - > Flush ( ) ;
}
}
break ;
case eInputReaderDeactivate :
break ;
case eInputReaderReactivate :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
if ( reader . GetPrompt ( ) & & ! batch_mode )
{
out_stream - > Printf ( " %s " , reader . GetPrompt ( ) ) ;
out_stream - > Flush ( ) ;
}
}
break ;
case eInputReaderAsynchronousOutputWritten :
break ;
case eInputReaderGotToken :
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
bool batch_mode = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) ;
std : : string temp_string ( bytes , bytes_len ) ;
commands_in_progress . AppendString ( temp_string . c_str ( ) ) ;
if ( ! reader . IsDone ( ) & & reader . GetPrompt ( ) & & ! batch_mode )
{
out_stream - > Printf ( " %s " , reader . GetPrompt ( ) ) ;
out_stream - > Flush ( ) ;
}
}
break ;
case eInputReaderEndOfFile :
case eInputReaderInterrupt :
// Control-c (SIGINT) & control-d both mean finish & exit.
reader . SetIsDone ( true ) ;
// Control-c (SIGINT) ALSO means cancel; do NOT create a breakpoint command.
if ( notification = = eInputReaderInterrupt )
commands_in_progress . Clear ( ) ;
// Fall through here...
case eInputReaderDone :
{
bool batch_mode = notification = = eInputReaderDone ?
reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetBatchCommandMode ( ) :
true ;
WatchpointOptions * wp_options = ( WatchpointOptions * ) baton ;
std : : unique_ptr < WatchpointOptions : : CommandData > data_ap ( new WatchpointOptions : : CommandData ( ) ) ;
data_ap - > user_source . AppendList ( commands_in_progress ) ;
if ( data_ap . get ( ) )
{
ScriptInterpreter * interpreter = reader . GetDebugger ( ) . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
if ( interpreter )
{
if ( interpreter - > GenerateWatchpointCommandCallbackData ( data_ap - > user_source ,
data_ap - > script_source ) )
{
BatonSP baton_sp ( new WatchpointOptions : : CommandBaton ( data_ap . release ( ) ) ) ;
wp_options - > SetCallback ( ScriptInterpreterPython : : WatchpointCallbackFunction , baton_sp ) ;
}
else if ( ! batch_mode )
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
out_stream - > Printf ( " Warning: No command attached to breakpoint. \n " ) ;
out_stream - > Flush ( ) ;
}
}
else
{
if ( ! batch_mode )
{
StreamSP out_stream = reader . GetDebugger ( ) . GetAsyncOutputStream ( ) ;
out_stream - > Printf ( " Warning: Unable to find script intepreter; no command attached to breakpoint. \n " ) ;
out_stream - > Flush ( ) ;
}
}
}
}
break ;
}
return bytes_len ;
}
void
ScriptInterpreterPython : : CollectDataForBreakpointCommandCallback ( BreakpointOptions * bp_options ,
CommandReturnObject & result )
{
Debugger & debugger = GetCommandInterpreter ( ) . GetDebugger ( ) ;
InputReaderSP reader_sp ( new InputReader ( debugger ) ) ;
if ( reader_sp )
{
Error err = reader_sp - > Initialize (
ScriptInterpreterPython : : GenerateBreakpointOptionsCommandCallback ,
bp_options , // baton
eInputReaderGranularityLine , // token size, for feeding data to callback function
" DONE " , // end token
" " , // prompt
true ) ; // echo input
if ( err . Success ( ) )
debugger . PushInputReader ( reader_sp ) ;
else
{
result . AppendError ( err . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendError ( " out of memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
void
ScriptInterpreterPython : : CollectDataForWatchpointCommandCallback ( WatchpointOptions * wp_options ,
CommandReturnObject & result )
{
Debugger & debugger = GetCommandInterpreter ( ) . GetDebugger ( ) ;
InputReaderSP reader_sp ( new InputReader ( debugger ) ) ;
if ( reader_sp )
{
Error err = reader_sp - > Initialize (
ScriptInterpreterPython : : GenerateWatchpointOptionsCommandCallback ,
wp_options , // baton
eInputReaderGranularityLine , // token size, for feeding data to callback function
" DONE " , // end token
" > " , // prompt
true ) ; // echo input
if ( err . Success ( ) )
debugger . PushInputReader ( reader_sp ) ;
else
{
result . AppendError ( err . AsCString ( ) ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
else
{
result . AppendError ( " out of memory " ) ;
result . SetStatus ( eReturnStatusFailed ) ;
}
}
// Set a Python one-liner as the callback for the breakpoint.
void
ScriptInterpreterPython : : SetBreakpointCommandCallback ( BreakpointOptions * bp_options ,
const char * oneliner )
{
std : : unique_ptr < BreakpointOptions : : CommandData > data_ap ( new BreakpointOptions : : CommandData ( ) ) ;
// It's necessary to set both user_source and script_source to the oneliner.
// The former is used to generate callback description (as in breakpoint command list)
// while the latter is used for Python to interpret during the actual callback.
data_ap - > user_source . AppendString ( oneliner ) ;
data_ap - > script_source . assign ( oneliner ) ;
if ( GenerateBreakpointCommandCallbackData ( data_ap - > user_source , data_ap - > script_source ) )
{
BatonSP baton_sp ( new BreakpointOptions : : CommandBaton ( data_ap . release ( ) ) ) ;
bp_options - > SetCallback ( ScriptInterpreterPython : : BreakpointCallbackFunction , baton_sp ) ;
}
return ;
}
// Set a Python one-liner as the callback for the watchpoint.
void
ScriptInterpreterPython : : SetWatchpointCommandCallback ( WatchpointOptions * wp_options ,
const char * oneliner )
{
std : : unique_ptr < WatchpointOptions : : CommandData > data_ap ( new WatchpointOptions : : CommandData ( ) ) ;
// It's necessary to set both user_source and script_source to the oneliner.
// The former is used to generate callback description (as in watchpoint command list)
// while the latter is used for Python to interpret during the actual callback.
data_ap - > user_source . AppendString ( oneliner ) ;
data_ap - > script_source . assign ( oneliner ) ;
if ( GenerateWatchpointCommandCallbackData ( data_ap - > user_source , data_ap - > script_source ) )
{
BatonSP baton_sp ( new WatchpointOptions : : CommandBaton ( data_ap . release ( ) ) ) ;
wp_options - > SetCallback ( ScriptInterpreterPython : : WatchpointCallbackFunction , baton_sp ) ;
}
return ;
}
bool
ScriptInterpreterPython : : ExportFunctionDefinitionToInterpreter ( StringList & function_def )
{
// Convert StringList to one long, newline delimited, const char *.
std : : string function_def_string ( function_def . CopyList ( ) ) ;
return ExecuteMultipleLines ( function_def_string . c_str ( ) , ScriptInterpreter : : ExecuteScriptOptions ( ) . SetEnableIO ( false ) ) ;
}
bool
ScriptInterpreterPython : : GenerateFunction ( const char * signature , const StringList & input )
{
int num_lines = input . GetSize ( ) ;
if ( num_lines = = 0 )
return false ;
if ( ! signature | | * signature = = 0 )
return false ;
StreamString sstr ;
StringList auto_generated_function ;
auto_generated_function . AppendString ( signature ) ;
auto_generated_function . AppendString ( " global_dict = globals() " ) ; // Grab the global dictionary
auto_generated_function . AppendString ( " new_keys = internal_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 (internal_dict) " ) ; // Add the session dictionary to the
// global dictionary.
// Wrap everything up inside the function, increasing the indentation.
auto_generated_function . AppendString ( " if True: " ) ;
for ( int i = 0 ; i < num_lines ; + + i )
{
sstr . Clear ( ) ;
sstr . Printf ( " %s " , input . GetStringAtIndex ( i ) ) ;
auto_generated_function . AppendString ( sstr . GetData ( ) ) ;
}
auto_generated_function . AppendString ( " for key in new_keys: " ) ; // Iterate over all the keys from session dict
auto_generated_function . AppendString ( " internal_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 ;
return true ;
}
bool
ScriptInterpreterPython : : GenerateTypeScriptFunction ( StringList & user_input , std : : string & output , void * name_token )
{
static uint32_t num_created_functions = 0 ;
user_input . RemoveBlankLines ( ) ;
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.
std : : string auto_generated_function_name ( GenerateUniqueName ( " lldb_autogen_python_type_print_func " , num_created_functions , name_token ) ) ;
sstr . Printf ( " def %s (valobj, internal_dict): " , auto_generated_function_name . c_str ( ) ) ;
if ( ! GenerateFunction ( sstr . GetData ( ) , user_input ) )
return false ;
// Store the name of the auto-generated function to be called.
output . assign ( auto_generated_function_name ) ;
return true ;
}
bool
ScriptInterpreterPython : : GenerateScriptAliasFunction ( StringList & user_input , std : : string & output )
{
static uint32_t num_created_functions = 0 ;
user_input . RemoveBlankLines ( ) ;
StreamString sstr ;
// Check to see if we have any data; if not, just return.
if ( user_input . GetSize ( ) = = 0 )
return false ;
std : : string auto_generated_function_name ( GenerateUniqueName ( " lldb_autogen_python_cmd_alias_func " , num_created_functions ) ) ;
sstr . Printf ( " def %s (debugger, args, result, internal_dict): " , auto_generated_function_name . c_str ( ) ) ;
if ( ! GenerateFunction ( sstr . GetData ( ) , user_input ) )
return false ;
// Store the name of the auto-generated function to be called.
output . assign ( auto_generated_function_name ) ;
return true ;
}
bool
ScriptInterpreterPython : : GenerateTypeSynthClass ( StringList & user_input , std : : string & output , void * name_token )
{
static uint32_t num_created_classes = 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 ;
// Wrap all user input into a Python class
std : : string auto_generated_class_name ( GenerateUniqueName ( " lldb_autogen_python_type_synth_class " , num_created_classes , name_token ) ) ;
StringList auto_generated_class ;
// Create the function name & definition string.
sstr . Printf ( " class %s: " , auto_generated_class_name . c_str ( ) ) ;
auto_generated_class . AppendString ( sstr . GetData ( ) ) ;
// Wrap everything up inside the class, increasing the indentation.
// we don't need to play any fancy indentation tricks here because there is no
// surrounding code whose indentation we need to honor
for ( int i = 0 ; i < num_lines ; + + i )
{
sstr . Clear ( ) ;
sstr . Printf ( " %s " , user_input . GetStringAtIndex ( i ) ) ;
auto_generated_class . AppendString ( sstr . GetData ( ) ) ;
}
// Verify that the results are valid Python.
// (even though the method is ExportFunctionDefinitionToInterpreter, a class will actually be exported)
// (TODO: rename that method to ExportDefinitionToInterpreter)
if ( ! ExportFunctionDefinitionToInterpreter ( auto_generated_class ) )
return false ;
// Store the name of the auto-generated class
output . assign ( auto_generated_class_name ) ;
return true ;
}
lldb : : ScriptInterpreterObjectSP
ScriptInterpreterPython : : OSPlugin_CreatePluginObject ( const char * class_name , lldb : : ProcessSP process_sp )
{
if ( class_name = = NULL | | class_name [ 0 ] = = ' \0 ' )
return lldb : : ScriptInterpreterObjectSP ( ) ;
if ( ! process_sp )
return lldb : : ScriptInterpreterObjectSP ( ) ;
void * ret_val ;
{
Locker py_lock ( this , Locker : : AcquireLock , Locker : : FreeLock ) ;
ret_val = g_swig_create_os_plugin ( class_name ,
m_dictionary_name . c_str ( ) ,
process_sp ) ;
}
return MakeScriptObject ( ret_val ) ;
}
lldb : : ScriptInterpreterObjectSP
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 ( ! 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 , NULL ) ;
// if it fails, print the error but otherwise go on
if ( PyErr_Occurred ( ) )
{
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
}
return MakeScriptObject ( py_return ) ;
}
lldb : : ScriptInterpreterObjectSP
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 ( ! 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 , NULL ) ;
// if it fails, print the error but otherwise go on
if ( PyErr_Occurred ( ) )
{
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
}
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_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 = const_cast < char * > ( GetPythonValueFormatString ( tid ) ) ;
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 , tid ) ;
// if it fails, print the error but otherwise go on
if ( PyErr_Occurred ( ) )
{
PyErr_Print ( ) ;
PyErr_Clear ( ) ;
}
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 ) ;
}
2013-11-06 11:48:53 -05:00
lldb : : ScriptInterpreterObjectSP
ScriptInterpreterPython : : LoadPluginModule ( const FileSpec & file_spec ,
lldb_private : : Error & error )
{
if ( ! file_spec . Exists ( ) )
{
error . SetErrorString ( " no such file " ) ;
return lldb : : ScriptInterpreterObjectSP ( ) ;
}
ScriptInterpreterObjectSP module_sp ;
if ( LoadScriptingModule ( file_spec . GetPath ( ) . c_str ( ) , true , true , error , & module_sp ) )
return module_sp ;
return lldb : : ScriptInterpreterObjectSP ( ) ;
}
lldb : : ScriptInterpreterObjectSP
ScriptInterpreterPython : : GetDynamicSettings ( lldb : : ScriptInterpreterObjectSP plugin_module_sp ,
Target * target ,
const char * setting_name ,
lldb_private : : Error & error )
{
if ( ! plugin_module_sp | | ! target | | ! setting_name | | ! setting_name [ 0 ] )
return lldb : : ScriptInterpreterObjectSP ( ) ;
if ( ! g_swig_plugin_get )
return lldb : : ScriptInterpreterObjectSP ( ) ;
PyObject * reply_pyobj = nullptr ;
{
Locker py_lock ( this ) ;
TargetSP target_sp ( target - > shared_from_this ( ) ) ;
reply_pyobj = ( PyObject * ) g_swig_plugin_get ( plugin_module_sp - > GetObject ( ) , setting_name , target_sp ) ;
}
return MakeScriptObject ( reply_pyobj ) ;
}
2013-08-23 13:46:38 -04:00
lldb : : ScriptInterpreterObjectSP
ScriptInterpreterPython : : CreateSyntheticScriptedProvider ( const char * class_name ,
lldb : : ValueObjectSP valobj )
{
if ( class_name = = NULL | | class_name [ 0 ] = = ' \0 ' )
return lldb : : ScriptInterpreterObjectSP ( ) ;
if ( ! valobj . get ( ) )
return lldb : : ScriptInterpreterObjectSP ( ) ;
ExecutionContext exe_ctx ( valobj - > GetExecutionContextRef ( ) ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
if ( ! target )
return lldb : : ScriptInterpreterObjectSP ( ) ;
Debugger & debugger = target - > GetDebugger ( ) ;
ScriptInterpreter * script_interpreter = debugger . GetCommandInterpreter ( ) . GetScriptInterpreter ( ) ;
ScriptInterpreterPython * python_interpreter = ( ScriptInterpreterPython * ) script_interpreter ;
if ( ! script_interpreter )
return lldb : : ScriptInterpreterObjectSP ( ) ;
void * ret_val ;
{
Locker py_lock ( this ) ;
ret_val = g_swig_synthetic_script ( class_name ,
python_interpreter - > m_dictionary_name . c_str ( ) ,
valobj ) ;
}
return MakeScriptObject ( ret_val ) ;
}
bool
ScriptInterpreterPython : : GenerateTypeScriptFunction ( const char * oneliner , std : : string & output , void * name_token )
{
StringList input ;
input . SplitIntoLines ( oneliner , strlen ( oneliner ) ) ;
return GenerateTypeScriptFunction ( input , output , name_token ) ;
}
bool
ScriptInterpreterPython : : GenerateTypeSynthClass ( const char * oneliner , std : : string & output , void * name_token )
{
StringList input ;
input . SplitIntoLines ( oneliner , strlen ( oneliner ) ) ;
return GenerateTypeSynthClass ( input , output , name_token ) ;
}
bool
ScriptInterpreterPython : : GenerateBreakpointCommandCallbackData ( StringList & user_input , std : : string & output )
{
static uint32_t num_created_functions = 0 ;
user_input . RemoveBlankLines ( ) ;
StreamString sstr ;
if ( user_input . GetSize ( ) = = 0 )
return false ;
std : : string auto_generated_function_name ( GenerateUniqueName ( " lldb_autogen_python_bp_callback_func_ " , num_created_functions ) ) ;
sstr . Printf ( " def %s (frame, bp_loc, internal_dict): " , auto_generated_function_name . c_str ( ) ) ;
if ( ! GenerateFunction ( sstr . GetData ( ) , user_input ) )
return false ;
// Store the name of the auto-generated function to be called.
output . assign ( auto_generated_function_name ) ;
return true ;
}
bool
ScriptInterpreterPython : : GenerateWatchpointCommandCallbackData ( StringList & user_input , std : : string & output )
{
static uint32_t num_created_functions = 0 ;
user_input . RemoveBlankLines ( ) ;
StreamString sstr ;
if ( user_input . GetSize ( ) = = 0 )
return false ;
std : : string auto_generated_function_name ( GenerateUniqueName ( " lldb_autogen_python_wp_callback_func_ " , num_created_functions ) ) ;
sstr . Printf ( " def %s (frame, wp, internal_dict): " , auto_generated_function_name . c_str ( ) ) ;
if ( ! GenerateFunction ( sstr . GetData ( ) , user_input ) )
return false ;
// Store the name of the auto-generated function to be called.
output . assign ( auto_generated_function_name ) ;
return true ;
}
bool
ScriptInterpreterPython : : GetScriptedSummary ( const char * python_function_name ,
lldb : : ValueObjectSP valobj ,
lldb : : ScriptInterpreterObjectSP & callee_wrapper_sp ,
std : : string & retval )
{
Timer scoped_timer ( __PRETTY_FUNCTION__ , __PRETTY_FUNCTION__ ) ;
if ( ! valobj . get ( ) )
{
retval . assign ( " <no object> " ) ;
return false ;
}
void * old_callee = ( callee_wrapper_sp ? callee_wrapper_sp - > GetObject ( ) : NULL ) ;
void * new_callee = old_callee ;
bool ret_val ;
if ( python_function_name
& & * python_function_name )
{
{
Locker py_lock ( this ) ;
{
Timer scoped_timer ( " g_swig_typescript_callback " , " g_swig_typescript_callback " ) ;
ret_val = g_swig_typescript_callback ( python_function_name ,
FindSessionDictionary ( m_dictionary_name . c_str ( ) ) ,
valobj ,
& new_callee ,
retval ) ;
}
}
}
else
{
retval . assign ( " <no function name> " ) ;
return false ;
}
if ( new_callee & & old_callee ! = new_callee )
callee_wrapper_sp = MakeScriptObject ( new_callee ) ;
return ret_val ;
}
bool
ScriptInterpreterPython : : BreakpointCallbackFunction
(
void * baton ,
StoppointCallbackContext * context ,
user_id_t break_id ,
user_id_t break_loc_id
)
{
BreakpointOptions : : CommandData * bp_option_data = ( BreakpointOptions : : CommandData * ) baton ;
const char * python_function_name = bp_option_data - > script_source . c_str ( ) ;
if ( ! context )
return true ;
ExecutionContext exe_ctx ( context - > exe_ctx_ref ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
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 ' )
{
const StackFrameSP stop_frame_sp ( exe_ctx . GetFrameSP ( ) ) ;
BreakpointSP breakpoint_sp = target - > GetBreakpointByID ( break_id ) ;
if ( breakpoint_sp )
{
const BreakpointLocationSP bp_loc_sp ( breakpoint_sp - > FindLocationByID ( break_loc_id ) ) ;
if ( stop_frame_sp & & bp_loc_sp )
{
bool ret_val = true ;
{
Locker py_lock ( python_interpreter ) ;
ret_val = g_swig_breakpoint_callback ( python_function_name ,
python_interpreter - > m_dictionary_name . c_str ( ) ,
stop_frame_sp ,
bp_loc_sp ) ;
}
return ret_val ;
}
}
}
// We currently always true so we stop in case anything goes wrong when
// trying to call the script function
return true ;
}
bool
ScriptInterpreterPython : : WatchpointCallbackFunction
(
void * baton ,
StoppointCallbackContext * context ,
user_id_t watch_id
)
{
WatchpointOptions : : CommandData * wp_option_data = ( WatchpointOptions : : CommandData * ) baton ;
const char * python_function_name = wp_option_data - > script_source . c_str ( ) ;
if ( ! context )
return true ;
ExecutionContext exe_ctx ( context - > exe_ctx_ref ) ;
Target * target = exe_ctx . GetTargetPtr ( ) ;
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 ' )
{
const StackFrameSP stop_frame_sp ( exe_ctx . GetFrameSP ( ) ) ;
WatchpointSP wp_sp = target - > GetWatchpointList ( ) . FindByID ( watch_id ) ;
if ( wp_sp )
{
if ( stop_frame_sp & & wp_sp )
{
bool ret_val = true ;
{
Locker py_lock ( python_interpreter ) ;
ret_val = g_swig_watchpoint_callback ( python_function_name ,
python_interpreter - > m_dictionary_name . c_str ( ) ,
stop_frame_sp ,
wp_sp ) ;
}
return ret_val ;
}
}
}
// We currently always true so we stop in case anything goes wrong when
// trying to call the script function
return true ;
}
lldb : : thread_result_t
ScriptInterpreterPython : : RunEmbeddedPythonInterpreter ( lldb : : thread_arg_t baton )
{
ScriptInterpreterPython * script_interpreter = ( ScriptInterpreterPython * ) baton ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT ) ) ;
if ( log )
log - > Printf ( " %p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread starting... " , baton ) ;
char error_str [ 1024 ] ;
const char * pty_slave_name = script_interpreter - > m_embedded_python_pty . GetSlaveName ( error_str , sizeof ( error_str ) ) ;
if ( pty_slave_name ! = NULL )
{
StreamString run_string ;
// Ensure we have the GIL before running any Python code.
// Since we're only running a few one-liners and then dropping to the interpreter (which will release the GIL when needed),
// we can just release the GIL after finishing our work.
// If finer-grained locking is desirable, we can lock and unlock the GIL only when calling a python function.
Locker locker ( script_interpreter ,
ScriptInterpreterPython : : Locker : : AcquireLock | ScriptInterpreterPython : : Locker : : InitSession | ScriptInterpreterPython : : Locker : : InitGlobals ,
ScriptInterpreterPython : : Locker : : FreeAcquiredLock | ScriptInterpreterPython : : Locker : : TearDownSession ) ;
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.
// This embedded interpreter will, as any Python code that performs I/O, unlock the GIL before
// a system call that can hang, and lock it when the syscall has returned.
// We need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and
// PyGILState_Release (using the Locker above). This is because Python has a global lock which must be held whenever we want
// to touch any Python objects. Otherwise, if the user calls Python code, the interpreter state will be off,
// and things could hang (it's happened before).
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 ( ) ;
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_python_input_reader_sp )
script_interpreter - > m_embedded_python_input_reader_sp - > SetIsDone ( true ) ;
script_interpreter - > m_embedded_python_pty . CloseSlaveFileDescriptor ( ) ;
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 - > GetCommandInterpreter ( ) . GetDebugger ( ) ;
const InputReaderSP reader_sp = script_interpreter - > m_embedded_python_input_reader_sp ;
if ( reader_sp )
{
debugger . PopInputReader ( reader_sp ) ;
script_interpreter - > m_embedded_python_input_reader_sp . reset ( ) ;
}
return NULL ;
}
lldb : : thread_result_t
ScriptInterpreterPython : : PythonInputReaderManager : : RunPythonInputReader ( lldb : : thread_arg_t baton )
{
ScriptInterpreterPython * script_interpreter = ( ScriptInterpreterPython * ) baton ;
const InputReaderSP reader_sp = script_interpreter - > m_embedded_thread_input_reader_sp ;
if ( reader_sp )
reader_sp - > WaitOnReaderIsDone ( ) ;
return NULL ;
}
size_t
ScriptInterpreterPython : : CalculateNumChildren ( const lldb : : ScriptInterpreterObjectSP & implementor_sp )
{
if ( ! implementor_sp )
return 0 ;
void * implementor = implementor_sp - > GetObject ( ) ;
if ( ! implementor )
return 0 ;
if ( ! g_swig_calc_children )
return 0 ;
uint32_t ret_val = 0 ;
{
Locker py_lock ( this ) ;
ret_val = g_swig_calc_children ( implementor ) ;
}
return ret_val ;
}
lldb : : ValueObjectSP
ScriptInterpreterPython : : GetChildAtIndex ( const lldb : : ScriptInterpreterObjectSP & implementor_sp , uint32_t idx )
{
if ( ! implementor_sp )
return lldb : : ValueObjectSP ( ) ;
void * implementor = implementor_sp - > GetObject ( ) ;
if ( ! implementor )
return lldb : : ValueObjectSP ( ) ;
if ( ! g_swig_get_child_index | | ! g_swig_cast_to_sbvalue )
return lldb : : ValueObjectSP ( ) ;
lldb : : ValueObjectSP ret_val ;
{
Locker py_lock ( this ) ;
2013-11-06 11:48:53 -05:00
void * child_ptr = g_swig_get_child_index ( implementor , idx ) ;
2013-08-23 13:46:38 -04:00
if ( child_ptr ! = NULL & & child_ptr ! = Py_None )
{
2013-11-06 11:48:53 -05:00
lldb : : SBValue * sb_value_ptr = ( lldb : : SBValue * ) g_swig_cast_to_sbvalue ( child_ptr ) ;
if ( sb_value_ptr = = NULL )
2013-08-23 13:46:38 -04:00
Py_XDECREF ( child_ptr ) ;
else
2013-11-06 11:48:53 -05:00
ret_val = g_swig_get_valobj_sp_from_sbvalue ( sb_value_ptr ) ;
2013-08-23 13:46:38 -04:00
}
else
{
Py_XDECREF ( child_ptr ) ;
}
}
return ret_val ;
}
int
ScriptInterpreterPython : : GetIndexOfChildWithName ( const lldb : : ScriptInterpreterObjectSP & implementor_sp , const char * child_name )
{
if ( ! implementor_sp )
return UINT32_MAX ;
void * implementor = implementor_sp - > GetObject ( ) ;
if ( ! implementor )
return UINT32_MAX ;
if ( ! g_swig_get_index_child )
return UINT32_MAX ;
int ret_val = UINT32_MAX ;
{
Locker py_lock ( this ) ;
ret_val = g_swig_get_index_child ( implementor , child_name ) ;
}
return ret_val ;
}
bool
ScriptInterpreterPython : : UpdateSynthProviderInstance ( const lldb : : ScriptInterpreterObjectSP & implementor_sp )
{
bool ret_val = false ;
if ( ! implementor_sp )
return ret_val ;
void * implementor = implementor_sp - > GetObject ( ) ;
if ( ! implementor )
return ret_val ;
if ( ! g_swig_update_provider )
return ret_val ;
{
Locker py_lock ( this ) ;
ret_val = g_swig_update_provider ( implementor ) ;
}
return ret_val ;
}
bool
ScriptInterpreterPython : : MightHaveChildrenSynthProviderInstance ( const lldb : : ScriptInterpreterObjectSP & implementor_sp )
{
bool ret_val = false ;
if ( ! implementor_sp )
return ret_val ;
void * implementor = implementor_sp - > GetObject ( ) ;
if ( ! implementor )
return ret_val ;
if ( ! g_swig_mighthavechildren_provider )
return ret_val ;
{
Locker py_lock ( this ) ;
ret_val = g_swig_mighthavechildren_provider ( implementor ) ;
}
return ret_val ;
}
static std : : string
ReadPythonBacktrace ( PyObject * py_backtrace )
{
PyObject * traceback_module = NULL ,
* stringIO_module = NULL ,
* stringIO_builder = NULL ,
* stringIO_buffer = NULL ,
* printTB = NULL ,
* printTB_args = NULL ,
* printTB_result = NULL ,
* stringIO_getvalue = NULL ,
* printTB_string = NULL ;
std : : string retval ( " backtrace unavailable " ) ;
if ( py_backtrace & & py_backtrace ! = Py_None )
{
traceback_module = PyImport_ImportModule ( " traceback " ) ;
stringIO_module = PyImport_ImportModule ( " StringIO " ) ;
if ( traceback_module & & traceback_module ! = Py_None & & stringIO_module & & stringIO_module ! = Py_None )
{
stringIO_builder = PyObject_GetAttrString ( stringIO_module , " StringIO " ) ;
if ( stringIO_builder & & stringIO_builder ! = Py_None )
{
stringIO_buffer = PyObject_CallObject ( stringIO_builder , NULL ) ;
if ( stringIO_buffer & & stringIO_buffer ! = Py_None )
{
printTB = PyObject_GetAttrString ( traceback_module , " print_tb " ) ;
if ( printTB & & printTB ! = Py_None )
{
printTB_args = Py_BuildValue ( " OOO " , py_backtrace , Py_None , stringIO_buffer ) ;
printTB_result = PyObject_CallObject ( printTB , printTB_args ) ;
stringIO_getvalue = PyObject_GetAttrString ( stringIO_buffer , " getvalue " ) ;
if ( stringIO_getvalue & & stringIO_getvalue ! = Py_None )
{
printTB_string = PyObject_CallObject ( stringIO_getvalue , NULL ) ;
if ( printTB_string & & printTB_string ! = Py_None & & PyString_Check ( printTB_string ) )
retval . assign ( PyString_AsString ( printTB_string ) ) ;
}
}
}
}
}
}
Py_XDECREF ( traceback_module ) ;
Py_XDECREF ( stringIO_module ) ;
Py_XDECREF ( stringIO_builder ) ;
Py_XDECREF ( stringIO_buffer ) ;
Py_XDECREF ( printTB ) ;
Py_XDECREF ( printTB_args ) ;
Py_XDECREF ( printTB_result ) ;
Py_XDECREF ( stringIO_getvalue ) ;
Py_XDECREF ( printTB_string ) ;
return retval ;
}
bool
ScriptInterpreterPython : : RunScriptFormatKeyword ( const char * impl_function ,
Process * process ,
std : : string & output ,
Error & error )
{
bool ret_val ;
if ( ! process )
{
error . SetErrorString ( " no process " ) ;
return false ;
}
if ( ! impl_function | | ! impl_function [ 0 ] )
{
error . SetErrorString ( " no function to execute " ) ;
return false ;
}
if ( ! g_swig_run_script_keyword_process )
{
error . SetErrorString ( " internal helper function missing " ) ;
return false ;
}
{
ProcessSP process_sp ( process - > shared_from_this ( ) ) ;
Locker py_lock ( this ) ;
ret_val = g_swig_run_script_keyword_process ( impl_function , m_dictionary_name . c_str ( ) , process_sp , output ) ;
if ( ! ret_val )
error . SetErrorString ( " python script evaluation failed " ) ;
}
return ret_val ;
}
bool
ScriptInterpreterPython : : RunScriptFormatKeyword ( const char * impl_function ,
Thread * thread ,
std : : string & output ,
Error & error )
{
bool ret_val ;
if ( ! thread )
{
error . SetErrorString ( " no thread " ) ;
return false ;
}
if ( ! impl_function | | ! impl_function [ 0 ] )
{
error . SetErrorString ( " no function to execute " ) ;
return false ;
}
if ( ! g_swig_run_script_keyword_thread )
{
error . SetErrorString ( " internal helper function missing " ) ;
return false ;
}
{
ThreadSP thread_sp ( thread - > shared_from_this ( ) ) ;
Locker py_lock ( this ) ;
ret_val = g_swig_run_script_keyword_thread ( impl_function , m_dictionary_name . c_str ( ) , thread_sp , output ) ;
if ( ! ret_val )
error . SetErrorString ( " python script evaluation failed " ) ;
}
return ret_val ;
}
bool
ScriptInterpreterPython : : RunScriptFormatKeyword ( const char * impl_function ,
Target * target ,
std : : string & output ,
Error & error )
{
bool ret_val ;
if ( ! target )
{
error . SetErrorString ( " no thread " ) ;
return false ;
}
if ( ! impl_function | | ! impl_function [ 0 ] )
{
error . SetErrorString ( " no function to execute " ) ;
return false ;
}
if ( ! g_swig_run_script_keyword_target )
{
error . SetErrorString ( " internal helper function missing " ) ;
return false ;
}
{
TargetSP target_sp ( target - > shared_from_this ( ) ) ;
Locker py_lock ( this ) ;
ret_val = g_swig_run_script_keyword_target ( impl_function , m_dictionary_name . c_str ( ) , target_sp , output ) ;
if ( ! ret_val )
error . SetErrorString ( " python script evaluation failed " ) ;
}
return ret_val ;
}
bool
ScriptInterpreterPython : : RunScriptFormatKeyword ( const char * impl_function ,
StackFrame * frame ,
std : : string & output ,
Error & error )
{
bool ret_val ;
if ( ! frame )
{
error . SetErrorString ( " no frame " ) ;
return false ;
}
if ( ! impl_function | | ! impl_function [ 0 ] )
{
error . SetErrorString ( " no function to execute " ) ;
return false ;
}
if ( ! g_swig_run_script_keyword_frame )
{
error . SetErrorString ( " internal helper function missing " ) ;
return false ;
}
{
StackFrameSP frame_sp ( frame - > shared_from_this ( ) ) ;
Locker py_lock ( this ) ;
ret_val = g_swig_run_script_keyword_frame ( impl_function , m_dictionary_name . c_str ( ) , frame_sp , output ) ;
if ( ! ret_val )
error . SetErrorString ( " python script evaluation failed " ) ;
}
return ret_val ;
}
uint64_t replace_all ( std : : string & str , const std : : string & oldStr , const std : : string & newStr )
{
size_t pos = 0 ;
uint64_t matches = 0 ;
while ( ( pos = str . find ( oldStr , pos ) ) ! = std : : string : : npos )
{
matches + + ;
str . replace ( pos , oldStr . length ( ) , newStr ) ;
pos + = newStr . length ( ) ;
}
return matches ;
}
bool
ScriptInterpreterPython : : LoadScriptingModule ( const char * pathname ,
bool can_reload ,
bool init_session ,
2013-11-06 11:48:53 -05:00
lldb_private : : Error & error ,
lldb : : ScriptInterpreterObjectSP * module_sp )
2013-08-23 13:46:38 -04:00
{
if ( ! pathname | | ! pathname [ 0 ] )
{
error . SetErrorString ( " invalid pathname " ) ;
return false ;
}
if ( ! g_swig_call_module_init )
{
error . SetErrorString ( " internal helper function missing " ) ;
return false ;
}
lldb : : DebuggerSP debugger_sp = m_interpreter . GetDebugger ( ) . shared_from_this ( ) ;
{
FileSpec target_file ( pathname , true ) ;
std : : string basename ( target_file . GetFilename ( ) . GetCString ( ) ) ;
StreamString command_stream ;
// Before executing Pyton code, lock the GIL.
Locker py_lock ( this ,
Locker : : AcquireLock | ( init_session ? Locker : : InitSession : 0 ) ,
Locker : : FreeAcquiredLock | ( init_session ? Locker : : TearDownSession : 0 ) ) ;
if ( target_file . GetFileType ( ) = = FileSpec : : eFileTypeInvalid | |
target_file . GetFileType ( ) = = FileSpec : : eFileTypeUnknown )
{
// if not a valid file of any sort, check if it might be a filename still
// dot can't be used but / and \ can, and if either is found, reject
if ( strchr ( pathname , ' \\ ' ) | | strchr ( pathname , ' / ' ) )
{
error . SetErrorString ( " invalid pathname " ) ;
return false ;
}
basename = pathname ; // not a filename, probably a package of some sort, let it go through
}
else if ( target_file . GetFileType ( ) = = FileSpec : : eFileTypeDirectory | |
target_file . GetFileType ( ) = = FileSpec : : eFileTypeRegular | |
target_file . GetFileType ( ) = = FileSpec : : eFileTypeSymbolicLink )
{
std : : string directory ( target_file . GetDirectory ( ) . GetCString ( ) ) ;
replace_all ( directory , " ' " , " \\ ' " ) ;
// 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.insert(1,'%s'); \n \n " ,
directory . c_str ( ) ,
directory . c_str ( ) ) ;
bool syspath_retval = ExecuteMultipleLines ( command_stream . GetData ( ) , ScriptInterpreter : : ExecuteScriptOptions ( ) . SetEnableIO ( false ) . SetSetLLDBGlobals ( false ) ) ;
if ( ! syspath_retval )
{
error . SetErrorString ( " Python sys.path handling failed " ) ;
return false ;
}
// strip .py or .pyc extension
ConstString extension = target_file . GetFileNameExtension ( ) ;
if ( extension )
{
if ( : : strcmp ( extension . GetCString ( ) , " py " ) = = 0 )
basename . resize ( basename . length ( ) - 3 ) ;
else if ( : : strcmp ( extension . GetCString ( ) , " pyc " ) = = 0 )
basename . resize ( basename . length ( ) - 4 ) ;
}
}
else
{
error . SetErrorString ( " no known way to import this module specification " ) ;
return false ;
}
// check if the module is already import-ed
command_stream . Clear ( ) ;
command_stream . Printf ( " sys.modules.__contains__('%s') " , basename . c_str ( ) ) ;
bool does_contain = false ;
int refcount = 0 ;
// this call will succeed if the module was ever imported in any Debugger in the lifetime of the process
// in which this LLDB framework is living
bool was_imported_globally = ( ExecuteOneLineWithReturn ( command_stream . GetData ( ) ,
ScriptInterpreterPython : : eScriptReturnTypeBool ,
& does_contain ,
ScriptInterpreter : : ExecuteScriptOptions ( ) . SetEnableIO ( false ) . SetSetLLDBGlobals ( false ) ) & & does_contain ) ;
// this call will fail if the module was not imported in this Debugger before
command_stream . Clear ( ) ;
command_stream . Printf ( " sys.getrefcount(%s) " , basename . c_str ( ) ) ;
bool was_imported_locally = ( ExecuteOneLineWithReturn ( command_stream . GetData ( ) ,
ScriptInterpreterPython : : eScriptReturnTypeInt ,
& refcount ,
ScriptInterpreter : : ExecuteScriptOptions ( ) . SetEnableIO ( false ) . SetSetLLDBGlobals ( false ) ) & & refcount > 0 ) ;
bool was_imported = ( was_imported_globally | | was_imported_locally ) ;
if ( was_imported = = true & & can_reload = = false )
{
error . SetErrorString ( " module already imported " ) ;
return false ;
}
// now actually do the import
command_stream . Clear ( ) ;
if ( was_imported )
{
if ( ! was_imported_locally )
command_stream . Printf ( " import %s ; reload(%s) " , basename . c_str ( ) , basename . c_str ( ) ) ;
else
command_stream . Printf ( " reload(%s) " , basename . c_str ( ) ) ;
}
else
command_stream . Printf ( " import %s " , basename . c_str ( ) ) ;
bool import_retval = ExecuteMultipleLines ( command_stream . GetData ( ) , ScriptInterpreter : : ExecuteScriptOptions ( ) . SetEnableIO ( false ) . SetSetLLDBGlobals ( false ) . SetMaskoutErrors ( false ) ) ;
PyObject * py_error = PyErr_Occurred ( ) ; // per Python docs: "you do not need to Py_DECREF()" the return of this function
if ( py_error | | ! import_retval ) // check for failure of the import
{
if ( py_error ) // if we have a Python error..
{
PyObject * type = NULL , * value = NULL , * traceback = NULL ;
PyErr_Fetch ( & type , & value , & traceback ) ;
if ( PyErr_GivenExceptionMatches ( py_error , PyExc_ImportError ) ) // and it is an ImportError
{
if ( value & & value ! = Py_None )
error . SetErrorString ( PyString_AsString ( PyObject_Str ( value ) ) ) ;
else
error . SetErrorString ( " ImportError raised by imported module " ) ;
}
else // any other error
{
// get the backtrace
std : : string bt = ReadPythonBacktrace ( traceback ) ;
if ( value & & value ! = Py_None )
error . SetErrorStringWithFormat ( " Python error raised while importing module: %s - traceback: %s " , PyString_AsString ( PyObject_Str ( value ) ) , bt . c_str ( ) ) ;
else
error . SetErrorStringWithFormat ( " Python raised an error while importing module - traceback: %s " , bt . c_str ( ) ) ;
}
Py_XDECREF ( type ) ;
Py_XDECREF ( value ) ;
Py_XDECREF ( traceback ) ;
}
else // we failed but have no error to explain why
{
error . SetErrorString ( " unknown error while importing module " ) ;
}
// anyway, clear the error indicator and return false
PyErr_Clear ( ) ;
return false ;
}
// if we are here, everything worked
// call __lldb_init_module(debugger,dict)
if ( ! g_swig_call_module_init ( basename . c_str ( ) ,
m_dictionary_name . c_str ( ) ,
debugger_sp ) )
{
error . SetErrorString ( " calling __lldb_init_module failed " ) ;
return false ;
}
2013-11-06 11:48:53 -05:00
if ( module_sp )
{
// everything went just great, now set the module object
command_stream . Clear ( ) ;
command_stream . Printf ( " %s " , basename . c_str ( ) ) ;
void * module_pyobj = nullptr ;
if ( ExecuteOneLineWithReturn ( command_stream . GetData ( ) , ScriptInterpreter : : eScriptReturnTypeOpaqueObject , & module_pyobj ) & & module_pyobj )
* module_sp = MakeScriptObject ( module_pyobj ) ;
}
2013-08-23 13:46:38 -04:00
return true ;
}
}
lldb : : ScriptInterpreterObjectSP
ScriptInterpreterPython : : MakeScriptObject ( void * object )
{
return lldb : : ScriptInterpreterObjectSP ( new ScriptInterpreterPythonObject ( object ) ) ;
}
ScriptInterpreterPython : : SynchronicityHandler : : SynchronicityHandler ( lldb : : DebuggerSP debugger_sp ,
ScriptedCommandSynchronicity synchro ) :
m_debugger_sp ( debugger_sp ) ,
m_synch_wanted ( synchro ) ,
m_old_asynch ( debugger_sp - > GetAsyncExecution ( ) )
{
if ( m_synch_wanted = = eScriptedCommandSynchronicitySynchronous )
m_debugger_sp - > SetAsyncExecution ( false ) ;
else if ( m_synch_wanted = = eScriptedCommandSynchronicityAsynchronous )
m_debugger_sp - > SetAsyncExecution ( true ) ;
}
ScriptInterpreterPython : : SynchronicityHandler : : ~ SynchronicityHandler ( )
{
if ( m_synch_wanted ! = eScriptedCommandSynchronicityCurrentValue )
m_debugger_sp - > SetAsyncExecution ( m_old_asynch ) ;
}
bool
ScriptInterpreterPython : : RunScriptBasedCommand ( const char * impl_function ,
const char * args ,
ScriptedCommandSynchronicity synchronicity ,
lldb_private : : CommandReturnObject & cmd_retobj ,
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 ;
}
lldb : : DebuggerSP debugger_sp = m_interpreter . GetDebugger ( ) . shared_from_this ( ) ;
if ( ! debugger_sp . get ( ) )
{
error . SetErrorString ( " invalid Debugger pointer " ) ;
return false ;
}
bool ret_val = false ;
std : : string err_msg ;
{
Locker py_lock ( this ,
Locker : : AcquireLock | Locker : : InitSession ,
Locker : : FreeLock | Locker : : TearDownSession ) ;
SynchronicityHandler synch_handler ( debugger_sp ,
synchronicity ) ;
// we need to save the thread state when we first start the command
// because we might decide to interrupt it while some action is taking
// place outside of Python (e.g. printing to screen, waiting for the network, ...)
// in that case, _PyThreadState_Current will be NULL - and we would be unable
// to set the asynchronous exception - not a desirable situation
m_command_thread_state = _PyThreadState_Current ;
PythonInputReaderManager py_input ( this ) ;
ret_val = g_swig_call_command ( impl_function ,
m_dictionary_name . c_str ( ) ,
debugger_sp ,
args ,
cmd_retobj ) ;
}
if ( ! ret_val )
error . SetErrorString ( " unable to execute script function " ) ;
else
error . Clear ( ) ;
return ret_val ;
}
// in Python, a special attribute __doc__ contains the docstring
// for an object (function, method, class, ...) if any is defined
// Otherwise, the attribute's value is None
bool
ScriptInterpreterPython : : GetDocumentationForItem ( const char * item , std : : string & dest )
{
dest . clear ( ) ;
if ( ! item | | ! * item )
return false ;
std : : string command ( item ) ;
command + = " .__doc__ " ;
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 ) ) )
{
if ( result_ptr )
dest . assign ( result_ptr ) ;
return true ;
}
else
{
StreamString str_stream ;
str_stream . Printf ( " Function %s was not found. Containing module might be missing. " , item ) ;
dest . assign ( str_stream . GetData ( ) ) ;
return false ;
}
}
std : : unique_ptr < ScriptInterpreterLocker >
ScriptInterpreterPython : : AcquireInterpreterLock ( )
{
std : : unique_ptr < ScriptInterpreterLocker > py_lock ( new Locker ( this ,
Locker : : AcquireLock | Locker : : InitSession ,
Locker : : FreeLock | Locker : : TearDownSession ) ) ;
return py_lock ;
}
void
2013-11-06 11:48:53 -05:00
ScriptInterpreterPython : : InitializeInterpreter ( SWIGInitCallback swig_init_callback ,
SWIGBreakpointCallbackFunction swig_breakpoint_callback ,
SWIGWatchpointCallbackFunction swig_watchpoint_callback ,
SWIGPythonTypeScriptCallbackFunction swig_typescript_callback ,
SWIGPythonCreateSyntheticProvider swig_synthetic_script ,
SWIGPythonCalculateNumChildren swig_calc_children ,
SWIGPythonGetChildAtIndex swig_get_child_index ,
SWIGPythonGetIndexOfChildWithName swig_get_index_child ,
SWIGPythonCastPyObjectToSBValue swig_cast_to_sbvalue ,
SWIGPythonGetValueObjectSPFromSBValue swig_get_valobj_sp_from_sbvalue ,
SWIGPythonUpdateSynthProviderInstance swig_update_provider ,
SWIGPythonMightHaveChildrenSynthProviderInstance swig_mighthavechildren_provider ,
SWIGPythonCallCommand swig_call_command ,
SWIGPythonCallModuleInit swig_call_module_init ,
SWIGPythonCreateOSPlugin swig_create_os_plugin ,
SWIGPythonScriptKeyword_Process swig_run_script_keyword_process ,
SWIGPythonScriptKeyword_Thread swig_run_script_keyword_thread ,
SWIGPythonScriptKeyword_Target swig_run_script_keyword_target ,
SWIGPythonScriptKeyword_Frame swig_run_script_keyword_frame ,
SWIGPython_GetDynamicSetting swig_plugin_get )
{
g_swig_init_callback = swig_init_callback ;
g_swig_breakpoint_callback = swig_breakpoint_callback ;
g_swig_watchpoint_callback = swig_watchpoint_callback ;
g_swig_typescript_callback = swig_typescript_callback ;
g_swig_synthetic_script = swig_synthetic_script ;
g_swig_calc_children = swig_calc_children ;
g_swig_get_child_index = swig_get_child_index ;
g_swig_get_index_child = swig_get_index_child ;
g_swig_cast_to_sbvalue = swig_cast_to_sbvalue ;
g_swig_get_valobj_sp_from_sbvalue = swig_get_valobj_sp_from_sbvalue ;
g_swig_update_provider = swig_update_provider ;
g_swig_mighthavechildren_provider = swig_mighthavechildren_provider ;
g_swig_call_command = swig_call_command ;
g_swig_call_module_init = swig_call_module_init ;
g_swig_create_os_plugin = swig_create_os_plugin ;
g_swig_run_script_keyword_process = swig_run_script_keyword_process ;
g_swig_run_script_keyword_thread = swig_run_script_keyword_thread ;
g_swig_run_script_keyword_target = swig_run_script_keyword_target ;
g_swig_run_script_keyword_frame = swig_run_script_keyword_frame ;
g_swig_plugin_get = swig_plugin_get ;
2013-08-23 13:46:38 -04:00
}
void
ScriptInterpreterPython : : InitializePrivate ( )
{
Timer scoped_timer ( __PRETTY_FUNCTION__ , __PRETTY_FUNCTION__ ) ;
// Python will muck with STDIN terminal state, so save off any current TTY
// settings so we can restore them.
TerminalState stdin_tty_state ;
stdin_tty_state . Save ( STDIN_FILENO , false ) ;
PyGILState_STATE gstate ;
Log * log ( lldb_private : : GetLogIfAllCategoriesSet ( LIBLLDB_LOG_SCRIPT | LIBLLDB_LOG_VERBOSE ) ) ;
bool threads_already_initialized = false ;
if ( PyEval_ThreadsInitialized ( ) ) {
gstate = PyGILState_Ensure ( ) ;
if ( log )
log - > Printf ( " Ensured PyGILState. Previous state = %slocked \n " , gstate = = PyGILState_UNLOCKED ? " un " : " " ) ;
threads_already_initialized = true ;
} else {
// InitThreads acquires the GIL if it hasn't been called before.
PyEval_InitThreads ( ) ;
}
Py_InitializeEx ( 0 ) ;
// Initialize SWIG after setting up python
assert ( g_swig_init_callback ! = NULL ) ;
g_swig_init_callback ( ) ;
// Update the path python uses to search for modules to include the current directory.
PyRun_SimpleString ( " import sys " ) ;
PyRun_SimpleString ( " sys.path.append ('.') " ) ;
// Find the module that owns this code and use that path we get to
// set the sys.path appropriately.
FileSpec file_spec ;
char python_dir_path [ PATH_MAX ] ;
if ( Host : : GetLLDBPath ( ePathTypePythonDir , file_spec ) )
{
std : : string python_path ( " sys.path.insert(0, \" " ) ;
size_t orig_len = python_path . length ( ) ;
if ( file_spec . GetPath ( python_dir_path , sizeof ( python_dir_path ) ) )
{
python_path . append ( python_dir_path ) ;
python_path . append ( " \" ) " ) ;
PyRun_SimpleString ( python_path . c_str ( ) ) ;
python_path . resize ( orig_len ) ;
}
if ( Host : : GetLLDBPath ( ePathTypeLLDBShlibDir , file_spec ) )
{
if ( file_spec . GetPath ( python_dir_path , sizeof ( python_dir_path ) ) )
{
python_path . append ( python_dir_path ) ;
python_path . append ( " \" ) " ) ;
PyRun_SimpleString ( python_path . c_str ( ) ) ;
python_path . resize ( orig_len ) ;
}
}
}
PyRun_SimpleString ( " sys.dont_write_bytecode = 1; import lldb.embedded_interpreter; from lldb.embedded_interpreter import run_python_interpreter; from lldb.embedded_interpreter import run_one_line; from termios import * " ) ;
if ( threads_already_initialized ) {
if ( log )
log - > Printf ( " Releasing PyGILState. Returning to state = %slocked \n " , gstate = = PyGILState_UNLOCKED ? " un " : " " ) ;
PyGILState_Release ( gstate ) ;
} else {
// We initialized the threads in this function, just unlock the GIL.
PyEval_SaveThread ( ) ;
}
stdin_tty_state . Restore ( ) ;
}
//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 ();
//}
# endif // #ifdef LLDB_DISABLE_PYTHON