2010-06-08 16:52:24 +00: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
|
2011-10-23 16:49:03 +00:00
|
|
|
// the *FIRST* header file included here.
|
2011-11-04 03:34:56 +00:00
|
|
|
#ifdef LLDB_DISABLE_PYTHON
|
|
|
|
|
|
|
|
|
|
// Python is disabled in this build
|
|
|
|
|
|
|
|
|
|
#else
|
2011-10-23 16:49:03 +00:00
|
|
|
|
|
|
|
|
#if defined (__APPLE__)
|
|
|
|
|
#include <Python/Python.h>
|
|
|
|
|
#else
|
|
|
|
|
#include <Python.h>
|
|
|
|
|
#endif
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
#include "lldb/Interpreter/ScriptInterpreterPython.h"
|
|
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
#include "lldb/API/SBValue.h"
|
2011-09-17 08:33:22 +00:00
|
|
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
2010-06-23 01:19:29 +00:00
|
|
|
#include "lldb/Breakpoint/StoppointCallbackContext.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#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"
|
2010-10-07 17:14:24 +00:00
|
|
|
#include "lldb/Target/Thread.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
using namespace lldb;
|
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
2011-03-22 01:14:58 +00:00
|
|
|
|
|
|
|
|
static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
|
|
|
|
|
static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
|
2011-07-15 02:26:42 +00:00
|
|
|
static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
|
2011-07-24 00:14:56 +00:00
|
|
|
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;
|
2011-07-29 19:53:35 +00:00
|
|
|
static ScriptInterpreter::SWIGPythonUpdateSynthProviderInstance g_swig_update_provider = NULL;
|
2011-08-16 16:49:25 +00:00
|
|
|
static ScriptInterpreter::SWIGPythonCallCommand g_swig_call_command = NULL;
|
2011-10-17 21:45:27 +00:00
|
|
|
static ScriptInterpreter::SWIGPythonCallModuleInit g_swig_call_module_init = NULL;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
static int
|
|
|
|
|
_check_and_flush (FILE *stream)
|
|
|
|
|
{
|
|
|
|
|
int prev_fail = ferror (stream);
|
|
|
|
|
return fflush (stream) || prev_fail ? EOF : 0;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-17 21:55:19 +00:00
|
|
|
static Predicate<lldb::tid_t> &
|
|
|
|
|
PythonMutexPredicate ()
|
2011-01-14 00:29:16 +00:00
|
|
|
{
|
2011-01-17 21:55:19 +00:00
|
|
|
static lldb_private::Predicate<lldb::tid_t> g_interpreter_is_running (LLDB_INVALID_THREAD_ID);
|
|
|
|
|
return g_interpreter_is_running;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::Locker::CurrentThreadHasPythonLock ()
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
|
|
|
|
TimeValue timeout;
|
|
|
|
|
|
|
|
|
|
timeout = TimeValue::Now(); // Don't wait any time.
|
|
|
|
|
|
|
|
|
|
return PythonMutexPredicate().WaitForValueEqualTo (Host::GetCurrentThreadID(), &timeout, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::Locker::TryGetPythonLock (uint32_t seconds_to_wait)
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
TimeValue timeout;
|
|
|
|
|
|
|
|
|
|
if (seconds_to_wait != UINT32_MAX)
|
|
|
|
|
{
|
|
|
|
|
timeout = TimeValue::Now();
|
|
|
|
|
timeout.OffsetWithSeconds (seconds_to_wait);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return PythonMutexPredicate().WaitForValueEqualToAndSetValueTo (LLDB_INVALID_THREAD_ID,
|
|
|
|
|
Host::GetCurrentThreadID(), &timeout, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
void
|
|
|
|
|
ScriptInterpreterPython::Locker::ReleasePythonLock ()
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
|
|
|
|
PythonMutexPredicate().SetValue (LLDB_INVALID_THREAD_ID, eBroadcastAlways);
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
|
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
ScriptInterpreterPython::Locker::Locker (ScriptInterpreterPython *py_interpreter,
|
|
|
|
|
uint16_t on_entry,
|
|
|
|
|
uint16_t on_leave,
|
|
|
|
|
FILE* wait_msg_handle) :
|
|
|
|
|
m_need_session( (on_leave & TearDownSession) == TearDownSession ),
|
|
|
|
|
m_release_lock ( false ), // decide in constructor body
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
if ( (on_entry & AcquireLock) == AcquireLock )
|
|
|
|
|
{
|
|
|
|
|
if (CurrentThreadHasPythonLock())
|
|
|
|
|
{
|
|
|
|
|
if ( (on_leave & FreeLock) == FreeLock )
|
|
|
|
|
m_release_lock = true;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
DoAcquireLock();
|
|
|
|
|
if ( (on_leave & FreeLock) == FreeLock )
|
|
|
|
|
m_release_lock = true;
|
|
|
|
|
if ( (on_leave & FreeAcquiredLock) == FreeAcquiredLock )
|
|
|
|
|
m_release_lock = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if ( (on_entry & InitSession) == InitSession )
|
|
|
|
|
DoInitSession();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::Locker::DoAcquireLock()
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
{
|
|
|
|
|
if (!CurrentThreadHasPythonLock())
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
while (!TryGetPythonLock (1))
|
|
|
|
|
if (m_tmp_fh)
|
|
|
|
|
fprintf (m_tmp_fh,
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
"Python interpreter locked on another thread; waiting to acquire lock...\n");
|
|
|
|
|
}
|
2011-10-24 17:22:21 +00:00
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::Locker::DoInitSession()
|
|
|
|
|
{
|
|
|
|
|
if (!m_python_interpreter)
|
|
|
|
|
return false;
|
|
|
|
|
m_python_interpreter->EnterSession ();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::Locker::DoFreeLock()
|
|
|
|
|
{
|
|
|
|
|
ReleasePythonLock ();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::Locker::DoTearDownSession()
|
|
|
|
|
{
|
|
|
|
|
if (!m_python_interpreter)
|
|
|
|
|
return false;
|
|
|
|
|
m_python_interpreter->LeaveSession ();
|
|
|
|
|
return true;
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ScriptInterpreterPython::Locker::~Locker()
|
|
|
|
|
{
|
|
|
|
|
if (m_need_session)
|
2011-10-24 17:22:21 +00:00
|
|
|
DoTearDownSession();
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
if (m_release_lock)
|
2011-10-24 17:22:21 +00:00
|
|
|
DoFreeLock();
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
}
|
|
|
|
|
|
2010-06-23 01:19:29 +00:00
|
|
|
ScriptInterpreterPython::ScriptInterpreterPython (CommandInterpreter &interpreter) :
|
2010-09-18 01:14:36 +00:00
|
|
|
ScriptInterpreter (interpreter, eScriptLanguagePython),
|
2011-01-14 00:29:16 +00:00
|
|
|
m_embedded_python_pty (),
|
|
|
|
|
m_embedded_thread_input_reader_sp (),
|
2011-02-09 01:08:52 +00:00
|
|
|
m_dbg_stdout (interpreter.GetDebugger().GetOutputFile().GetStream()),
|
2011-01-14 00:29:16 +00:00
|
|
|
m_new_sysout (NULL),
|
|
|
|
|
m_dictionary_name (interpreter.GetDebugger().GetInstanceName().AsCString()),
|
2011-02-07 23:24:47 +00:00
|
|
|
m_terminal_state (),
|
2011-01-14 00:29:16 +00:00
|
|
|
m_session_is_active (false),
|
|
|
|
|
m_valid_session (true)
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-01-27 01:01:10 +00:00
|
|
|
static int g_initialized = false;
|
|
|
|
|
|
|
|
|
|
if (!g_initialized)
|
|
|
|
|
{
|
|
|
|
|
g_initialized = true;
|
2011-03-22 01:14:58 +00:00
|
|
|
ScriptInterpreterPython::InitializePrivate ();
|
2011-01-27 01:01:10 +00:00
|
|
|
}
|
2011-01-17 21:55:19 +00:00
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker locker(this,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeAcquiredLock);
|
2011-01-17 21:55:19 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
m_dictionary_name.append("_dict");
|
|
|
|
|
StreamString run_string;
|
|
|
|
|
run_string.Printf ("%s = dict()", m_dictionary_name.c_str());
|
|
|
|
|
PyRun_SimpleString (run_string.GetData());
|
|
|
|
|
|
|
|
|
|
run_string.Clear();
|
|
|
|
|
|
|
|
|
|
// 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();
|
2012-02-01 08:09:32 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-02-01 08:09:32 +00:00
|
|
|
run_string.Printf ("run_one_line (%s, 'import copy, os, re, sys, uuid, lldb, gnu_libstdcpp, objc')", m_dictionary_name.c_str());
|
2011-01-14 00:29:16 +00:00
|
|
|
PyRun_SimpleString (run_string.GetData());
|
2010-10-18 18:24:17 +00:00
|
|
|
|
2012-02-23 23:10:03 +00:00
|
|
|
// 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 CFString, CFArray, CFDictionary, NSData, NSMachPort, NSSet, NSNotification, NSException, CFBag, CFBinaryHeap, NSURL, NSBundle, NSNumber')", m_dictionary_name.c_str());
|
|
|
|
|
PyRun_SimpleString (run_string.GetData());
|
2012-02-01 08:09:32 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
int new_count = Debugger::TestDebuggerRefCount();
|
2010-10-18 18:24:17 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (new_count > old_count)
|
|
|
|
|
Debugger::Terminate();
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
run_string.Clear();
|
2011-10-19 18:09:39 +00:00
|
|
|
run_string.Printf ("run_one_line (%s, 'lldb.debugger_unique_id = %llu')", m_dictionary_name.c_str(),
|
2011-01-14 00:29:16 +00:00
|
|
|
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);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
ScriptInterpreterPython::~ScriptInterpreterPython ()
|
|
|
|
|
{
|
|
|
|
|
Debugger &debugger = GetCommandInterpreter().GetDebugger();
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (m_embedded_thread_input_reader_sp.get() != NULL)
|
|
|
|
|
{
|
|
|
|
|
m_embedded_thread_input_reader_sp->SetIsDone (true);
|
|
|
|
|
m_embedded_python_pty.CloseSlaveFileDescriptor();
|
|
|
|
|
const InputReaderSP reader_sp = m_embedded_thread_input_reader_sp;
|
|
|
|
|
m_embedded_thread_input_reader_sp.reset();
|
|
|
|
|
debugger.PopInputReader (reader_sp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_new_sysout)
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker locker(this,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeLock);
|
|
|
|
|
Py_DECREF ((PyObject*)m_new_sysout);
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
void
|
|
|
|
|
ScriptInterpreterPython::ResetOutputFileHandle (FILE *fh)
|
|
|
|
|
{
|
|
|
|
|
if (fh == NULL)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_dbg_stdout = fh;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
|
|
|
|
|
m_new_sysout = PyFile_FromFile (m_dbg_stdout, (char *) "", (char *) "w", _check_and_flush);
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-02-07 23:24:47 +00:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
void
|
|
|
|
|
ScriptInterpreterPython::LeaveSession ()
|
|
|
|
|
{
|
2012-02-29 01:52:13 +00:00
|
|
|
PyObject *sysmod = PyImport_AddModule ("sys");
|
|
|
|
|
PyObject *sysdict = PyModule_GetDict (sysmod);
|
|
|
|
|
|
|
|
|
|
if (m_new_sysout && sysmod && sysdict)
|
|
|
|
|
{
|
|
|
|
|
PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_old_sysout);
|
|
|
|
|
PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_old_sysout);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
m_session_is_active = false;
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
void
|
|
|
|
|
ScriptInterpreterPython::EnterSession ()
|
|
|
|
|
{
|
|
|
|
|
// If we have already entered the session, without having officially 'left' it, then there is no need to
|
|
|
|
|
// 'enter' it again.
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (m_session_is_active)
|
|
|
|
|
return;
|
2010-10-18 18:24:17 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
m_session_is_active = true;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-17 21:55:19 +00:00
|
|
|
StreamString run_string;
|
|
|
|
|
|
2012-01-28 02:11:02 +00:00
|
|
|
run_string.Printf ( "run_one_line (%s, 'lldb.debugger_unique_id = %llu", m_dictionary_name.c_str(), GetCommandInterpreter().GetDebugger().GetID());
|
|
|
|
|
run_string.Printf ( "; lldb.debugger = lldb.SBDebugger.FindDebuggerWithID (%llu)", 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 ()");
|
|
|
|
|
// Make sure STDIN is closed since when we run this as an embedded
|
|
|
|
|
// interpreter we don't want someone to call "line = sys.stdin.readline()"
|
|
|
|
|
// and lock up. We don't have multiple windows and when the interpreter is
|
|
|
|
|
// embedded we don't know we should be feeding input to the embedded
|
|
|
|
|
// interpreter or to the python sys.stdin. We also don't want to let python
|
|
|
|
|
// play with the real stdin from this process, so we need to close it...
|
2012-02-03 01:30:30 +00:00
|
|
|
//run_string.PutCString ("; sys.stdin.close()");
|
2012-01-28 02:11:02 +00:00
|
|
|
run_string.PutCString ("')");
|
2011-05-03 21:21:50 +00:00
|
|
|
|
|
|
|
|
PyRun_SimpleString (run_string.GetData());
|
|
|
|
|
run_string.Clear();
|
2012-02-29 01:52:13 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
PyObject *sysmod = PyImport_AddModule ("sys");
|
|
|
|
|
PyObject *sysdict = PyModule_GetDict (sysmod);
|
2012-02-29 01:52:13 +00:00
|
|
|
|
2012-01-28 02:11:02 +00:00
|
|
|
if (m_new_sysout && sysmod && sysdict)
|
|
|
|
|
{
|
2012-02-29 01:52:13 +00:00
|
|
|
m_old_sysout = PyDict_GetItemString(sysdict, "stdout");
|
|
|
|
|
m_old_syserr = PyDict_GetItemString(sysdict, "stderr");
|
2012-01-28 02:11:02 +00:00
|
|
|
PyDict_SetItemString (sysdict, "stdout", (PyObject*)m_new_sysout);
|
|
|
|
|
PyDict_SetItemString (sysdict, "stderr", (PyObject*)m_new_sysout);
|
|
|
|
|
}
|
2012-02-29 01:52:13 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (PyErr_Occurred())
|
|
|
|
|
PyErr_Clear ();
|
2012-01-28 02:11:02 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-07-30 22:33:14 +00:00
|
|
|
bool
|
2010-09-18 01:14:36 +00:00
|
|
|
ScriptInterpreterPython::ExecuteOneLine (const char *command, CommandReturnObject *result)
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2011-01-14 00:29:16 +00:00
|
|
|
if (!m_valid_session)
|
|
|
|
|
return false;
|
|
|
|
|
|
2011-01-14 21:09:29 +00:00
|
|
|
// 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.
|
|
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker locker(this,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
|
2011-01-14 21:09:29 +00:00
|
|
|
|
|
|
|
|
bool success = false;
|
|
|
|
|
|
2010-06-23 01:19:29 +00:00
|
|
|
if (command)
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2011-01-14 21:09:29 +00:00
|
|
|
// Find the correct script interpreter dictionary in the main module.
|
|
|
|
|
PyObject *main_mod = PyImport_AddModule ("__main__");
|
|
|
|
|
PyObject *script_interpreter_dict = NULL;
|
|
|
|
|
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), m_dictionary_name.c_str()) == 0)
|
|
|
|
|
{
|
|
|
|
|
script_interpreter_dict = value;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (script_interpreter_dict != NULL)
|
|
|
|
|
{
|
|
|
|
|
PyObject *pfunc = NULL;
|
|
|
|
|
PyObject *pmod = PyImport_AddModule ("embedded_interpreter");
|
|
|
|
|
if (pmod != NULL)
|
|
|
|
|
{
|
|
|
|
|
PyObject *pmod_dict = PyModule_GetDict (pmod);
|
|
|
|
|
if ((pmod_dict != NULL)
|
|
|
|
|
&& PyDict_Check (pmod_dict))
|
|
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyObject *string_arg = PyString_FromString (command);
|
|
|
|
|
if (pfunc && string_arg && PyCallable_Check (pfunc))
|
|
|
|
|
{
|
|
|
|
|
PyObject *pargs = PyTuple_New (2);
|
|
|
|
|
if (pargs != NULL)
|
|
|
|
|
{
|
|
|
|
|
PyTuple_SetItem (pargs, 0, script_interpreter_dict);
|
|
|
|
|
PyTuple_SetItem (pargs, 1, string_arg);
|
|
|
|
|
PyObject *pvalue = PyObject_CallObject (pfunc, pargs);
|
|
|
|
|
Py_DECREF (pargs);
|
|
|
|
|
if (pvalue != NULL)
|
|
|
|
|
{
|
|
|
|
|
Py_DECREF (pvalue);
|
|
|
|
|
success = true;
|
|
|
|
|
}
|
|
|
|
|
else if (PyErr_Occurred ())
|
|
|
|
|
{
|
|
|
|
|
PyErr_Print();
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
Py_INCREF (script_interpreter_dict);
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-23 01:19:29 +00:00
|
|
|
|
2011-01-14 21:09:29 +00:00
|
|
|
if (success)
|
2010-07-30 22:33:14 +00:00
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
// The one-liner failed. Append the error message.
|
|
|
|
|
if (result)
|
|
|
|
|
result->AppendErrorWithFormat ("python failed attempting to evaluate '%s'\n", command);
|
|
|
|
|
return false;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2010-07-30 22:33:14 +00:00
|
|
|
|
|
|
|
|
if (result)
|
|
|
|
|
result->AppendError ("empty command passed to python\n");
|
|
|
|
|
return false;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
ScriptInterpreterPython::InputReaderCallback
|
|
|
|
|
(
|
|
|
|
|
void *baton,
|
2010-06-23 01:19:29 +00:00
|
|
|
InputReader &reader,
|
2010-10-07 17:14:24 +00:00
|
|
|
InputReaderAction notification,
|
2010-06-08 16:52:24 +00:00
|
|
|
const char *bytes,
|
|
|
|
|
size_t bytes_len
|
|
|
|
|
)
|
|
|
|
|
{
|
2010-11-10 19:18:14 +00:00
|
|
|
lldb::thread_t embedded_interpreter_thread;
|
|
|
|
|
LogSP log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT));
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
if (baton == NULL)
|
|
|
|
|
return 0;
|
2011-01-14 00:29:16 +00:00
|
|
|
|
|
|
|
|
ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
|
2011-10-24 17:22:21 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (script_interpreter->m_script_lang != eScriptLanguagePython)
|
|
|
|
|
return 0;
|
|
|
|
|
|
2011-06-16 16:27:19 +00:00
|
|
|
StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
|
|
|
|
|
bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
switch (notification)
|
|
|
|
|
{
|
|
|
|
|
case eInputReaderActivate:
|
|
|
|
|
{
|
2011-06-16 16:27:19 +00:00
|
|
|
if (!batch_mode)
|
|
|
|
|
{
|
|
|
|
|
out_stream->Printf ("Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.\n");
|
|
|
|
|
out_stream->Flush();
|
|
|
|
|
}
|
2011-02-09 01:08:52 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
// Save terminal settings if we can
|
2011-02-09 01:08:52 +00:00
|
|
|
int input_fd = reader.GetDebugger().GetInputFile().GetDescriptor();
|
|
|
|
|
if (input_fd == File::kInvalidDescriptor)
|
Added a new Host call to find LLDB related paths:
static bool
Host::GetLLDBPath (lldb::PathType path_type, FileSpec &file_spec);
This will fill in "file_spec" with an appropriate path that is appropriate
for the current Host OS. MacOSX will return paths within the LLDB.framework,
and other unixes will return the paths they want. The current PathType
enums are:
typedef enum PathType
{
ePathTypeLLDBShlibDir, // The directory where the lldb.so (unix) or LLDB mach-o file in LLDB.framework (MacOSX) exists
ePathTypeSupportExecutableDir, // Find LLDB support executable directory (debugserver, etc)
ePathTypeHeaderDir, // Find LLDB header file directory
ePathTypePythonDir // Find Python modules (PYTHONPATH) directory
} PathType;
All places that were finding executables are and python paths are now updated
to use this Host call.
Added another new host call to launch the inferior in a terminal. This ability
will be very host specific and doesn't need to be supported on all systems.
MacOSX currently will create a new .command file and tell Terminal.app to open
the .command file. It also uses the new "darwin-debug" app which is a small
app that uses posix to exec (no fork) and stop at the entry point of the
program. The GDB remote plug-in is almost able launch a process and attach to
it, it currently will spawn the process, but it won't attach to it just yet.
This will let LLDB not have to share the terminal with another process and a
new terminal window will pop up when you launch. This won't get hooked up
until we work out all of the kinks. The new Host function is:
static lldb::pid_t
Host::LaunchInNewTerminal (
const char **argv, // argv[0] is executable
const char **envp,
const ArchSpec *arch_spec,
bool stop_at_entry,
bool disable_aslr);
Cleaned up FileSpec::GetPath to not use strncpy() as it was always zero
filling the entire path buffer.
Fixed an issue with the dynamic checker function where I missed a '$' prefix
that should have been added.
llvm-svn: 116690
2010-10-17 22:03:32 +00:00
|
|
|
input_fd = STDIN_FILENO;
|
2010-09-14 22:49:06 +00:00
|
|
|
|
2011-02-07 23:24:47 +00:00
|
|
|
script_interpreter->SaveTerminalState(input_fd);
|
2011-02-07 19:04:58 +00:00
|
|
|
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
ScriptInterpreterPython::Locker locker(script_interpreter,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeAcquiredLock);
|
2011-01-17 21:55:19 +00:00
|
|
|
}
|
|
|
|
|
|
2010-11-10 19:18:14 +00:00
|
|
|
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);
|
2011-02-08 01:34:25 +00:00
|
|
|
if (IS_VALID_LLDB_HOST_THREAD(embedded_interpreter_thread))
|
2010-11-10 19:18:14 +00:00
|
|
|
{
|
|
|
|
|
if (log)
|
2011-09-20 23:23:44 +00:00
|
|
|
log->Printf ("ScriptInterpreterPython::InputReaderCallback, Activate, succeeded in creating thread (thread_t = %p)", embedded_interpreter_thread);
|
2010-11-10 19:18:14 +00:00
|
|
|
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);
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case eInputReaderDeactivate:
|
2012-01-06 00:47:38 +00:00
|
|
|
// When another input reader is pushed, don't leave the session...
|
|
|
|
|
//script_interpreter->LeaveSession ();
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case eInputReaderReactivate:
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
2012-01-06 00:47:38 +00:00
|
|
|
// Don't try and acquire the interpreter lock here because code like
|
|
|
|
|
// this:
|
|
|
|
|
//
|
|
|
|
|
// (lldb) script
|
|
|
|
|
// >>> v = lldb.frame.EvaluateExpression("collection->get_at_index(12)")
|
|
|
|
|
//
|
|
|
|
|
// This will cause the process to run. The interpreter lock is taken
|
|
|
|
|
// by the input reader for the "script" command. If we try and acquire
|
|
|
|
|
// the lock here, when the process runs it might deactivate this input
|
|
|
|
|
// reader (if STDIN is hooked up to the inferior process) and
|
|
|
|
|
// reactivate it when the process stops which will deadlock.
|
|
|
|
|
//ScriptInterpreterPython::Locker locker(script_interpreter,
|
|
|
|
|
// ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
|
|
|
|
|
// ScriptInterpreterPython::Locker::FreeAcquiredLock);
|
2011-01-17 21:55:19 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
2010-11-19 20:47:54 +00:00
|
|
|
|
This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.
As part of this it introduces a new Stream class,
StreamAsynchronousIO. A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast. When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string. When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.
Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.
I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired. I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).
llvm-svn: 130721
2011-05-02 20:41:46 +00:00
|
|
|
case eInputReaderAsynchronousOutputWritten:
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-19 20:47:54 +00:00
|
|
|
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;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
case eInputReaderGotToken:
|
2010-11-10 19:18:14 +00:00
|
|
|
if (script_interpreter->m_embedded_python_pty.GetMasterFileDescriptor() != -1)
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2010-11-10 19:18:14 +00:00
|
|
|
if (log)
|
2011-09-20 21:44:10 +00:00
|
|
|
log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %lu", bytes,
|
2010-11-10 19:18:14 +00: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);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2010-11-10 19:18:14 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (log)
|
2011-09-20 21:44:10 +00:00
|
|
|
log->Printf ("ScriptInterpreterPython::InputReaderCallback, GotToken, bytes='%s', byte_len = %lu, Master File Descriptor is bad.",
|
2010-11-10 19:18:14 +00:00
|
|
|
bytes,
|
|
|
|
|
bytes_len);
|
|
|
|
|
reader.SetIsDone (true);
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case eInputReaderDone:
|
2011-01-14 00:29:16 +00:00
|
|
|
script_interpreter->LeaveSession ();
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
// Restore terminal settings if they were validly saved
|
2010-11-10 19:18:14 +00:00
|
|
|
if (log)
|
|
|
|
|
log->Printf ("ScriptInterpreterPython::InputReaderCallback, Done, closing down input reader.");
|
2010-09-14 22:49:06 +00:00
|
|
|
|
2011-02-07 23:24:47 +00:00
|
|
|
script_interpreter->RestoreTerminalState ();
|
|
|
|
|
|
2010-11-10 19:18:14 +00:00
|
|
|
script_interpreter->m_embedded_python_pty.CloseMasterFileDescriptor();
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bytes_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2010-09-18 01:14:36 +00:00
|
|
|
ScriptInterpreterPython::ExecuteInterpreterLoop ()
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
Debugger &debugger = GetCommandInterpreter().GetDebugger();
|
2010-09-14 22:49:06 +00:00
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
|
|
2011-02-09 01:08:52 +00:00
|
|
|
if (!debugger.GetInputFile().IsValid())
|
2010-09-14 22:49:06 +00:00
|
|
|
return;
|
|
|
|
|
|
2010-06-23 01:19:29 +00:00
|
|
|
InputReaderSP reader_sp (new InputReader(debugger));
|
2010-06-08 16:52:24 +00:00
|
|
|
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())
|
|
|
|
|
{
|
2010-06-23 01:19:29 +00:00
|
|
|
debugger.PushInputReader (reader_sp);
|
2010-11-10 19:18:14 +00:00
|
|
|
m_embedded_thread_input_reader_sp = reader_sp;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::ExecuteOneLineWithReturn (const char *in_string,
|
2011-10-17 21:45:27 +00:00
|
|
|
ScriptInterpreter::ScriptReturnType return_type,
|
2010-06-08 16:52:24 +00:00
|
|
|
void *ret_value)
|
|
|
|
|
{
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker locker(this,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
PyObject *py_return = NULL;
|
|
|
|
|
PyObject *mainmod = PyImport_AddModule ("__main__");
|
|
|
|
|
PyObject *globals = PyModule_GetDict (mainmod);
|
2011-01-14 00:29:16 +00:00
|
|
|
PyObject *locals = NULL;
|
2010-06-08 16:52:24 +00:00
|
|
|
PyObject *py_error = NULL;
|
2011-08-11 19:17:45 +00:00
|
|
|
bool ret_success = false;
|
2011-01-14 00:29:16 +00:00
|
|
|
bool should_decrement_locals = false;
|
2010-06-08 16:52:24 +00:00
|
|
|
int success;
|
2011-01-14 00:29:16 +00:00
|
|
|
|
|
|
|
|
if (PyDict_Check (globals))
|
|
|
|
|
{
|
|
|
|
|
PyObject *key, *value;
|
|
|
|
|
Py_ssize_t pos = 0;
|
|
|
|
|
|
|
|
|
|
int i = 0;
|
|
|
|
|
while (PyDict_Next (globals, &pos, &key, &value))
|
|
|
|
|
{
|
|
|
|
|
// We have stolen references to the key and value objects in the dictionary; we need to increment them now
|
|
|
|
|
// so that Python's garbage collector doesn't collect them out from under us.
|
|
|
|
|
Py_INCREF (key);
|
|
|
|
|
Py_INCREF (value);
|
|
|
|
|
char *c_str = PyString_AsString (key);
|
|
|
|
|
if (strcmp (c_str, m_dictionary_name.c_str()) == 0)
|
|
|
|
|
locals = value;
|
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
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();
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
if (in_string != 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);
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (locals != NULL
|
|
|
|
|
&& should_decrement_locals)
|
|
|
|
|
Py_DECREF (locals);
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
if (py_return != NULL)
|
|
|
|
|
{
|
|
|
|
|
switch (return_type)
|
|
|
|
|
{
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeCharPtr: // "char *"
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[3] = "s#";
|
2011-08-17 01:30:04 +00:00
|
|
|
success = PyArg_Parse (py_return, format, (char **) ret_value);
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeCharStrOrNone: // char* or NULL if py_return == Py_None
|
2011-08-16 16:49:25 +00:00
|
|
|
{
|
|
|
|
|
const char format[3] = "z";
|
2011-08-17 01:30:04 +00:00
|
|
|
success = PyArg_Parse (py_return, format, (char **) ret_value);
|
2011-08-16 16:49:25 +00:00
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeBool:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "b";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (bool *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeShortInt:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "h";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (short *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeShortIntUnsigned:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "H";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (unsigned short *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeInt:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "i";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (int *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeIntUnsigned:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "I";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (unsigned int *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeLongInt:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "l";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (long *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeLongIntUnsigned:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "k";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (unsigned long *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeLongLong:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "L";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (long long *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeLongLongUnsigned:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "K";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (unsigned long long *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeFloat:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "f";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (float *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeDouble:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "d";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (double *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2011-10-17 21:45:27 +00:00
|
|
|
case eScriptReturnTypeChar:
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
|
|
|
|
const char format[2] = "c";
|
|
|
|
|
success = PyArg_Parse (py_return, format, (char *) ret_value);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
default:
|
|
|
|
|
{}
|
|
|
|
|
}
|
|
|
|
|
Py_DECREF (py_return);
|
|
|
|
|
if (success)
|
|
|
|
|
ret_success = true;
|
|
|
|
|
else
|
|
|
|
|
ret_success = false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
py_error = PyErr_Occurred();
|
|
|
|
|
if (py_error != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
|
|
|
|
|
PyErr_Print ();
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
ret_success = false;
|
|
|
|
|
}
|
2011-01-17 21:55:19 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
return ret_success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::ExecuteMultipleLines (const char *in_string)
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
Locker locker(this,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
bool success = false;
|
|
|
|
|
PyObject *py_return = NULL;
|
|
|
|
|
PyObject *mainmod = PyImport_AddModule ("__main__");
|
|
|
|
|
PyObject *globals = PyModule_GetDict (mainmod);
|
2011-01-14 00:29:16 +00:00
|
|
|
PyObject *locals = NULL;
|
2010-06-08 16:52:24 +00:00
|
|
|
PyObject *py_error = NULL;
|
2011-01-14 00:29:16 +00:00
|
|
|
bool should_decrement_locals = false;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
if (PyDict_Check (globals))
|
|
|
|
|
{
|
|
|
|
|
PyObject *key, *value;
|
|
|
|
|
Py_ssize_t pos = 0;
|
|
|
|
|
|
|
|
|
|
while (PyDict_Next (globals, &pos, &key, &value))
|
|
|
|
|
{
|
|
|
|
|
// We have stolen references to the key and value objects in the dictionary; we need to increment them now
|
|
|
|
|
// so that Python's garbage collector doesn't collect them out from under us.
|
|
|
|
|
Py_INCREF (key);
|
|
|
|
|
Py_INCREF (value);
|
|
|
|
|
if (strcmp (PyString_AsString (key), m_dictionary_name.c_str()) == 0)
|
|
|
|
|
locals = value;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (locals == NULL)
|
|
|
|
|
{
|
|
|
|
|
locals = PyObject_GetAttrString (globals, m_dictionary_name.c_str());
|
|
|
|
|
should_decrement_locals = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (locals == NULL)
|
|
|
|
|
{
|
|
|
|
|
locals = globals;
|
|
|
|
|
should_decrement_locals = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
py_error = PyErr_Occurred();
|
|
|
|
|
if (py_error != NULL)
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
py_return = PyEval_EvalCode (compiled_code, globals, locals);
|
|
|
|
|
if (py_return != NULL)
|
|
|
|
|
{
|
|
|
|
|
success = true;
|
|
|
|
|
Py_DECREF (py_return);
|
|
|
|
|
}
|
2011-01-14 00:29:16 +00:00
|
|
|
if (locals && should_decrement_locals)
|
|
|
|
|
Py_DECREF (locals);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
py_error = PyErr_Occurred ();
|
|
|
|
|
if (py_error != NULL)
|
|
|
|
|
{
|
|
|
|
|
if (PyErr_GivenExceptionMatches (py_error, PyExc_SyntaxError))
|
|
|
|
|
PyErr_Print ();
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
success = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return success;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.";
|
|
|
|
|
|
|
|
|
|
size_t
|
|
|
|
|
ScriptInterpreterPython::GenerateBreakpointOptionsCommandCallback
|
|
|
|
|
(
|
|
|
|
|
void *baton,
|
2010-06-23 01:19:29 +00:00
|
|
|
InputReader &reader,
|
2010-10-07 17:14:24 +00:00
|
|
|
InputReaderAction notification,
|
2010-06-08 16:52:24 +00:00
|
|
|
const char *bytes,
|
|
|
|
|
size_t bytes_len
|
|
|
|
|
)
|
|
|
|
|
{
|
2011-06-16 16:27:19 +00:00
|
|
|
static StringList commands_in_progress;
|
|
|
|
|
|
|
|
|
|
StreamSP out_stream = reader.GetDebugger().GetAsyncOutputStream();
|
|
|
|
|
bool batch_mode = reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
switch (notification)
|
|
|
|
|
{
|
|
|
|
|
case eInputReaderActivate:
|
|
|
|
|
{
|
|
|
|
|
commands_in_progress.Clear();
|
2011-06-16 16:27:19 +00:00
|
|
|
if (!batch_mode)
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2011-06-16 16:27:19 +00:00
|
|
|
out_stream->Printf ("%s\n", g_reader_instructions);
|
2010-06-23 01:19:29 +00:00
|
|
|
if (reader.GetPrompt())
|
2011-06-16 16:27:19 +00:00
|
|
|
out_stream->Printf ("%s", reader.GetPrompt());
|
|
|
|
|
out_stream->Flush ();
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case eInputReaderDeactivate:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case eInputReaderReactivate:
|
2011-06-16 16:27:19 +00:00
|
|
|
if (reader.GetPrompt() && !batch_mode)
|
2010-10-27 18:34:42 +00:00
|
|
|
{
|
2011-06-16 16:27:19 +00:00
|
|
|
out_stream->Printf ("%s", reader.GetPrompt());
|
|
|
|
|
out_stream->Flush ();
|
2010-10-27 18:34:42 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
|
|
|
|
|
This patch captures and serializes all output being written by the
command line driver, including the lldb prompt being output by
editline, the asynchronous process output & error messages, and
asynchronous messages written by target stop-hooks.
As part of this it introduces a new Stream class,
StreamAsynchronousIO. A StreamAsynchronousIO object is created with a
broadcaster, who will eventually broadcast the stream's data for a
listener to handle, and an event type indicating what type of event
the broadcaster will broadcast. When the Write method is called on a
StreamAsynchronousIO object, the data is appended to an internal
string. When the Flush method is called on a StreamAsynchronousIO
object, it broadcasts it's data string and clears the string.
Anything in lldb-core that needs to generate asynchronous output for
the end-user should use the StreamAsynchronousIO objects.
I have also added a new notification type for InputReaders, to let
them know that a asynchronous output has been written. This is to
allow the input readers to, for example, refresh their prompts and
lines, if desired. I added the case statements to all the input
readers to catch this notification, but I haven't added any code for
handling them yet (except to the IOChannel input reader).
llvm-svn: 130721
2011-05-02 20:41:46 +00:00
|
|
|
case eInputReaderAsynchronousOutputWritten:
|
|
|
|
|
break;
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
case eInputReaderGotToken:
|
|
|
|
|
{
|
|
|
|
|
std::string temp_string (bytes, bytes_len);
|
|
|
|
|
commands_in_progress.AppendString (temp_string.c_str());
|
2011-06-16 16:27:19 +00:00
|
|
|
if (!reader.IsDone() && reader.GetPrompt() && !batch_mode)
|
2010-10-27 18:34:42 +00:00
|
|
|
{
|
2011-06-16 16:27:19 +00:00
|
|
|
out_stream->Printf ("%s", reader.GetPrompt());
|
|
|
|
|
out_stream->Flush ();
|
2010-10-27 18:34:42 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
2010-11-19 20:47:54 +00:00
|
|
|
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...
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
case eInputReaderDone:
|
|
|
|
|
{
|
|
|
|
|
BreakpointOptions *bp_options = (BreakpointOptions *)baton;
|
|
|
|
|
std::auto_ptr<BreakpointOptions::CommandData> data_ap(new BreakpointOptions::CommandData());
|
|
|
|
|
data_ap->user_source.AppendList (commands_in_progress);
|
|
|
|
|
if (data_ap.get())
|
|
|
|
|
{
|
2010-06-23 01:19:29 +00:00
|
|
|
ScriptInterpreter *interpreter = reader.GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
|
2010-06-08 16:52:24 +00:00
|
|
|
if (interpreter)
|
|
|
|
|
{
|
|
|
|
|
if (interpreter->GenerateBreakpointCommandCallbackData (data_ap->user_source,
|
|
|
|
|
data_ap->script_source))
|
|
|
|
|
{
|
|
|
|
|
if (data_ap->script_source.GetSize() == 1)
|
|
|
|
|
{
|
|
|
|
|
BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
|
|
|
|
|
bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
|
|
|
|
|
}
|
|
|
|
|
}
|
2011-06-16 16:27:19 +00:00
|
|
|
else if (!batch_mode)
|
|
|
|
|
{
|
|
|
|
|
out_stream->Printf ("Warning: No command attached to breakpoint.\n");
|
|
|
|
|
out_stream->Flush();
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-06-16 16:27:19 +00:00
|
|
|
if (!batch_mode)
|
|
|
|
|
{
|
|
|
|
|
out_stream->Printf ("Warning: Unable to find script intepreter; no command attached to breakpoint.\n");
|
|
|
|
|
out_stream->Flush();
|
|
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return bytes_len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
2010-09-18 01:14:36 +00:00
|
|
|
ScriptInterpreterPython::CollectDataForBreakpointCommandCallback (BreakpointOptions *bp_options,
|
2010-06-08 16:52:24 +00:00
|
|
|
CommandReturnObject &result)
|
|
|
|
|
{
|
2011-01-14 00:29:16 +00:00
|
|
|
Debugger &debugger = GetCommandInterpreter().GetDebugger();
|
|
|
|
|
|
2010-06-23 01:19:29 +00:00
|
|
|
InputReaderSP reader_sp (new InputReader (debugger));
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
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())
|
2010-06-23 01:19:29 +00:00
|
|
|
debugger.PushInputReader (reader_sp);
|
2010-06-08 16:52:24 +00:00
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result.AppendError (err.AsCString());
|
|
|
|
|
result.SetStatus (eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
result.AppendError("out of memory");
|
|
|
|
|
result.SetStatus (eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-09-11 00:23:59 +00:00
|
|
|
// Set a Python one-liner as the callback for the breakpoint.
|
Added the capability to specify a one-liner Python script as the callback
command for a breakpoint, for example:
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
The ScriptInterpreter interface has an extra method:
/// Set a one-liner as the callback for the breakpoint command.
virtual void
SetBreakpointCommandCallback (CommandInterpreter &interpreter,
BreakpointOptions *bp_options,
const char *oneliner);
to accomplish the above.
Also added a test case to demonstrate lldb's use of breakpoint callback command
to stop at function c() only when its immediate caller is function a(). The
following session shows the user entering the following commands:
1) command source .lldb (set up executable, breakpoint, and breakpoint command)
2) run (the callback mechanism will skip two breakpoints where c()'s immeidate caller is not a())
3) bt (to see that indeed c()'s immediate caller is a())
4) c (to continue and finish the program)
test/conditional_break $ ../../build/Debug/lldb
(lldb) command source .lldb
Executing commands in '.lldb'.
(lldb) file a.out
Current executable set to 'a.out' (x86_64).
(lldb) breakpoint set -n c
Breakpoint created: 1: name = 'c', locations = 1
(lldb) script import sys, os
(lldb) script sys.path.append(os.path.join(os.getcwd(), os.pardir))
(lldb) script import conditional_break
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
(lldb) run
run
Launching '/Volumes/data/lldb/svn/trunk/test/conditional_break/a.out' (x86_64)
(lldb) Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`a at main.c:25
frame #3: a.out`main at main.c:44
frame #4: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`main at main.c:47
frame #3: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`a at main.c:27
frame #2: a.out`main at main.c:50
frame #3: a.out`start
c called from a
Stopped at c() with immediate caller as a().
a(1) returns 4
b(2) returns 5
Process 20420 Stopped
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread
36
37 int c(int val)
38 {
39 -> return val + 3;
40 }
41
42 int main (int argc, char const *argv[])
(lldb) bt
bt
thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread
frame #0: 0x0000000100000de8 a.out`c + 7 at main.c:39
frame #1: 0x0000000100000dbc a.out`a + 44 at main.c:27
frame #2: 0x0000000100000e4b a.out`main + 91 at main.c:50
frame #3: 0x0000000100000d88 a.out`start + 52
(lldb) c
c
Resuming process 20420
Process 20420 Exited
a(3) returns 6
(lldb)
llvm-svn: 113596
2010-09-10 18:21:10 +00:00
|
|
|
void
|
2010-09-18 01:14:36 +00:00
|
|
|
ScriptInterpreterPython::SetBreakpointCommandCallback (BreakpointOptions *bp_options,
|
Added the capability to specify a one-liner Python script as the callback
command for a breakpoint, for example:
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
The ScriptInterpreter interface has an extra method:
/// Set a one-liner as the callback for the breakpoint command.
virtual void
SetBreakpointCommandCallback (CommandInterpreter &interpreter,
BreakpointOptions *bp_options,
const char *oneliner);
to accomplish the above.
Also added a test case to demonstrate lldb's use of breakpoint callback command
to stop at function c() only when its immediate caller is function a(). The
following session shows the user entering the following commands:
1) command source .lldb (set up executable, breakpoint, and breakpoint command)
2) run (the callback mechanism will skip two breakpoints where c()'s immeidate caller is not a())
3) bt (to see that indeed c()'s immediate caller is a())
4) c (to continue and finish the program)
test/conditional_break $ ../../build/Debug/lldb
(lldb) command source .lldb
Executing commands in '.lldb'.
(lldb) file a.out
Current executable set to 'a.out' (x86_64).
(lldb) breakpoint set -n c
Breakpoint created: 1: name = 'c', locations = 1
(lldb) script import sys, os
(lldb) script sys.path.append(os.path.join(os.getcwd(), os.pardir))
(lldb) script import conditional_break
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
(lldb) run
run
Launching '/Volumes/data/lldb/svn/trunk/test/conditional_break/a.out' (x86_64)
(lldb) Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`a at main.c:25
frame #3: a.out`main at main.c:44
frame #4: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`main at main.c:47
frame #3: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`a at main.c:27
frame #2: a.out`main at main.c:50
frame #3: a.out`start
c called from a
Stopped at c() with immediate caller as a().
a(1) returns 4
b(2) returns 5
Process 20420 Stopped
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread
36
37 int c(int val)
38 {
39 -> return val + 3;
40 }
41
42 int main (int argc, char const *argv[])
(lldb) bt
bt
thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread
frame #0: 0x0000000100000de8 a.out`c + 7 at main.c:39
frame #1: 0x0000000100000dbc a.out`a + 44 at main.c:27
frame #2: 0x0000000100000e4b a.out`main + 91 at main.c:50
frame #3: 0x0000000100000d88 a.out`start + 52
(lldb) c
c
Resuming process 20420
Process 20420 Exited
a(3) returns 6
(lldb)
llvm-svn: 113596
2010-09-10 18:21:10 +00:00
|
|
|
const char *oneliner)
|
|
|
|
|
{
|
|
|
|
|
std::auto_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.
|
|
|
|
|
|
2010-09-27 21:35:15 +00:00
|
|
|
data_ap->user_source.AppendString (oneliner);
|
Added the capability to specify a one-liner Python script as the callback
command for a breakpoint, for example:
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
The ScriptInterpreter interface has an extra method:
/// Set a one-liner as the callback for the breakpoint command.
virtual void
SetBreakpointCommandCallback (CommandInterpreter &interpreter,
BreakpointOptions *bp_options,
const char *oneliner);
to accomplish the above.
Also added a test case to demonstrate lldb's use of breakpoint callback command
to stop at function c() only when its immediate caller is function a(). The
following session shows the user entering the following commands:
1) command source .lldb (set up executable, breakpoint, and breakpoint command)
2) run (the callback mechanism will skip two breakpoints where c()'s immeidate caller is not a())
3) bt (to see that indeed c()'s immediate caller is a())
4) c (to continue and finish the program)
test/conditional_break $ ../../build/Debug/lldb
(lldb) command source .lldb
Executing commands in '.lldb'.
(lldb) file a.out
Current executable set to 'a.out' (x86_64).
(lldb) breakpoint set -n c
Breakpoint created: 1: name = 'c', locations = 1
(lldb) script import sys, os
(lldb) script sys.path.append(os.path.join(os.getcwd(), os.pardir))
(lldb) script import conditional_break
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
(lldb) run
run
Launching '/Volumes/data/lldb/svn/trunk/test/conditional_break/a.out' (x86_64)
(lldb) Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`a at main.c:25
frame #3: a.out`main at main.c:44
frame #4: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`main at main.c:47
frame #3: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`a at main.c:27
frame #2: a.out`main at main.c:50
frame #3: a.out`start
c called from a
Stopped at c() with immediate caller as a().
a(1) returns 4
b(2) returns 5
Process 20420 Stopped
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread
36
37 int c(int val)
38 {
39 -> return val + 3;
40 }
41
42 int main (int argc, char const *argv[])
(lldb) bt
bt
thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread
frame #0: 0x0000000100000de8 a.out`c + 7 at main.c:39
frame #1: 0x0000000100000dbc a.out`a + 44 at main.c:27
frame #2: 0x0000000100000e4b a.out`main + 91 at main.c:50
frame #3: 0x0000000100000d88 a.out`start + 52
(lldb) c
c
Resuming process 20420
Process 20420 Exited
a(3) returns 6
(lldb)
llvm-svn: 113596
2010-09-10 18:21:10 +00:00
|
|
|
|
2010-09-27 21:35:15 +00:00
|
|
|
if (GenerateBreakpointCommandCallbackData (data_ap->user_source, data_ap->script_source))
|
|
|
|
|
{
|
|
|
|
|
if (data_ap->script_source.GetSize() == 1)
|
|
|
|
|
{
|
|
|
|
|
BatonSP baton_sp (new BreakpointOptions::CommandBaton (data_ap.release()));
|
|
|
|
|
bp_options->SetCallback (ScriptInterpreterPython::BreakpointCallbackFunction, baton_sp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Added the capability to specify a one-liner Python script as the callback
command for a breakpoint, for example:
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
The ScriptInterpreter interface has an extra method:
/// Set a one-liner as the callback for the breakpoint command.
virtual void
SetBreakpointCommandCallback (CommandInterpreter &interpreter,
BreakpointOptions *bp_options,
const char *oneliner);
to accomplish the above.
Also added a test case to demonstrate lldb's use of breakpoint callback command
to stop at function c() only when its immediate caller is function a(). The
following session shows the user entering the following commands:
1) command source .lldb (set up executable, breakpoint, and breakpoint command)
2) run (the callback mechanism will skip two breakpoints where c()'s immeidate caller is not a())
3) bt (to see that indeed c()'s immediate caller is a())
4) c (to continue and finish the program)
test/conditional_break $ ../../build/Debug/lldb
(lldb) command source .lldb
Executing commands in '.lldb'.
(lldb) file a.out
Current executable set to 'a.out' (x86_64).
(lldb) breakpoint set -n c
Breakpoint created: 1: name = 'c', locations = 1
(lldb) script import sys, os
(lldb) script sys.path.append(os.path.join(os.getcwd(), os.pardir))
(lldb) script import conditional_break
(lldb) breakpoint command add -p 1 "conditional_break.stop_if_called_from_a()"
(lldb) run
run
Launching '/Volumes/data/lldb/svn/trunk/test/conditional_break/a.out' (x86_64)
(lldb) Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`a at main.c:25
frame #3: a.out`main at main.c:44
frame #4: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`b at main.c:34
frame #2: a.out`main at main.c:47
frame #3: a.out`start
c called from b
Continuing...
Checking call frames...
Stack trace for thread id=0x2e03 name=None queue=com.apple.main-thread:
frame #0: a.out`c at main.c:39
frame #1: a.out`a at main.c:27
frame #2: a.out`main at main.c:50
frame #3: a.out`start
c called from a
Stopped at c() with immediate caller as a().
a(1) returns 4
b(2) returns 5
Process 20420 Stopped
* thread #1: tid = 0x2e03, 0x0000000100000de8 a.out`c + 7 at main.c:39, stop reason = breakpoint 1.1, queue = com.apple.main-thread
36
37 int c(int val)
38 {
39 -> return val + 3;
40 }
41
42 int main (int argc, char const *argv[])
(lldb) bt
bt
thread #1: tid = 0x2e03, stop reason = breakpoint 1.1, queue = com.apple.main-thread
frame #0: 0x0000000100000de8 a.out`c + 7 at main.c:39
frame #1: 0x0000000100000dbc a.out`a + 44 at main.c:27
frame #2: 0x0000000100000e4b a.out`main + 91 at main.c:50
frame #3: 0x0000000100000d88 a.out`start + 52
(lldb) c
c
Resuming process 20420
Process 20420 Exited
a(3) returns 6
(lldb)
llvm-svn: 113596
2010-09-10 18:21:10 +00:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::ExportFunctionDefinitionToInterpreter (StringList &function_def)
|
|
|
|
|
{
|
|
|
|
|
// Convert StringList to one long, newline delimited, const char *.
|
|
|
|
|
std::string function_def_string;
|
|
|
|
|
|
|
|
|
|
int num_lines = function_def.GetSize();
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_lines; ++i)
|
|
|
|
|
{
|
|
|
|
|
function_def_string.append (function_def.GetStringAtIndex(i));
|
|
|
|
|
if (function_def_string.at (function_def_string.length() - 1) != '\n')
|
|
|
|
|
function_def_string.append ("\n");
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ExecuteMultipleLines (function_def_string.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-15 02:26:42 +00:00
|
|
|
// TODO move both GenerateTypeScriptFunction and GenerateBreakpointCommandCallbackData to actually
|
|
|
|
|
// use this code to generate their functions
|
|
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::GenerateFunction(std::string& signature, StringList &input, StringList &output)
|
|
|
|
|
{
|
|
|
|
|
int num_lines = input.GetSize ();
|
|
|
|
|
if (num_lines == 0)
|
|
|
|
|
return false;
|
|
|
|
|
StreamString sstr;
|
|
|
|
|
StringList auto_generated_function;
|
|
|
|
|
auto_generated_function.AppendString (signature.c_str());
|
|
|
|
|
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
|
|
|
|
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
|
|
|
|
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
|
|
|
|
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
|
|
|
|
// global dictionary.
|
|
|
|
|
|
|
|
|
|
// Wrap everything up inside the function, increasing the indentation.
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_lines; ++i)
|
|
|
|
|
{
|
|
|
|
|
sstr.Clear ();
|
|
|
|
|
sstr.Printf (" %s", 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 (" 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;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this implementation is identical to GenerateBreakpointCommandCallbackData (apart from the name
|
|
|
|
|
// given to generated functions, of course)
|
|
|
|
|
bool
|
2012-02-15 02:34:21 +00:00
|
|
|
ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, StringList &output, void* name_token)
|
2011-07-15 02:26:42 +00:00
|
|
|
{
|
|
|
|
|
static int num_created_functions = 0;
|
|
|
|
|
user_input.RemoveBlankLines ();
|
|
|
|
|
int num_lines = user_input.GetSize ();
|
|
|
|
|
StreamString sstr;
|
|
|
|
|
|
|
|
|
|
// Check to see if we have any data; if not, just return.
|
|
|
|
|
if (user_input.GetSize() == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
|
|
|
|
|
// ValueObject as parameter to the function.
|
|
|
|
|
|
2012-02-15 02:34:21 +00:00
|
|
|
if (!name_token)
|
|
|
|
|
sstr.Printf ("lldb_autogen_python_type_print_func_%d", num_created_functions);
|
|
|
|
|
else
|
|
|
|
|
sstr.Printf ("lldb_gen_python_type_print_func_%p", name_token);
|
2011-07-15 02:26:42 +00:00
|
|
|
++num_created_functions;
|
|
|
|
|
std::string auto_generated_function_name = sstr.GetData();
|
|
|
|
|
|
|
|
|
|
sstr.Clear();
|
|
|
|
|
StringList auto_generated_function;
|
|
|
|
|
|
|
|
|
|
// Create the function name & definition string.
|
|
|
|
|
|
|
|
|
|
sstr.Printf ("def %s (valobj, dict):", auto_generated_function_name.c_str());
|
|
|
|
|
auto_generated_function.AppendString (sstr.GetData());
|
|
|
|
|
|
|
|
|
|
// Pre-pend code for setting up the session dictionary.
|
|
|
|
|
|
|
|
|
|
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
|
|
|
|
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
|
|
|
|
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
|
|
|
|
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
|
|
|
|
// global dictionary.
|
|
|
|
|
|
|
|
|
|
// Wrap everything up inside the function, increasing the indentation.
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_lines; ++i)
|
|
|
|
|
{
|
|
|
|
|
sstr.Clear ();
|
|
|
|
|
sstr.Printf (" %s", user_input.GetStringAtIndex (i));
|
|
|
|
|
auto_generated_function.AppendString (sstr.GetData());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Append code to clean up the global dictionary and update the session dictionary (all updates in the function
|
|
|
|
|
// got written to the values in the global dictionary, not the session dictionary).
|
|
|
|
|
|
|
|
|
|
auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
|
|
|
|
|
auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
|
|
|
|
|
auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
|
|
|
|
|
auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
|
|
|
|
|
|
|
|
|
|
// Verify that the results are valid Python.
|
|
|
|
|
|
|
|
|
|
if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Store the name of the auto-generated function to be called.
|
|
|
|
|
|
|
|
|
|
output.AppendString (auto_generated_function_name.c_str());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-16 16:49:25 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::GenerateScriptAliasFunction (StringList &user_input, StringList &output)
|
|
|
|
|
{
|
|
|
|
|
static int num_created_functions = 0;
|
|
|
|
|
user_input.RemoveBlankLines ();
|
|
|
|
|
int num_lines = user_input.GetSize ();
|
|
|
|
|
StreamString sstr;
|
|
|
|
|
|
|
|
|
|
// Check to see if we have any data; if not, just return.
|
|
|
|
|
if (user_input.GetSize() == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
|
2011-10-24 17:22:21 +00:00
|
|
|
// required data as parameters to the function.
|
2011-08-16 16:49:25 +00:00
|
|
|
|
|
|
|
|
sstr.Printf ("lldb_autogen_python_cmd_alias_func_%d", num_created_functions);
|
|
|
|
|
++num_created_functions;
|
|
|
|
|
std::string auto_generated_function_name = sstr.GetData();
|
|
|
|
|
|
|
|
|
|
sstr.Clear();
|
|
|
|
|
StringList auto_generated_function;
|
|
|
|
|
|
|
|
|
|
// Create the function name & definition string.
|
|
|
|
|
|
2011-09-09 01:41:30 +00:00
|
|
|
sstr.Printf ("def %s (debugger, args, result, dict):", auto_generated_function_name.c_str());
|
2011-08-16 16:49:25 +00:00
|
|
|
auto_generated_function.AppendString (sstr.GetData());
|
|
|
|
|
|
|
|
|
|
// Pre-pend code for setting up the session dictionary.
|
|
|
|
|
|
|
|
|
|
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
|
|
|
|
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
|
|
|
|
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
|
|
|
|
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
|
|
|
|
// global dictionary.
|
|
|
|
|
|
|
|
|
|
// Wrap everything up inside the function, increasing the indentation.
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < num_lines; ++i)
|
|
|
|
|
{
|
|
|
|
|
sstr.Clear ();
|
|
|
|
|
sstr.Printf (" %s", user_input.GetStringAtIndex (i));
|
|
|
|
|
auto_generated_function.AppendString (sstr.GetData());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Append code to clean up the global dictionary and update the session dictionary (all updates in the function
|
|
|
|
|
// got written to the values in the global dictionary, not the session dictionary).
|
|
|
|
|
|
|
|
|
|
auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
|
|
|
|
|
auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
|
|
|
|
|
auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
|
|
|
|
|
auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
|
|
|
|
|
|
|
|
|
|
// Verify that the results are valid Python.
|
|
|
|
|
|
|
|
|
|
if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// Store the name of the auto-generated function to be called.
|
|
|
|
|
|
|
|
|
|
output.AppendString (auto_generated_function_name.c_str());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2011-07-25 16:59:05 +00:00
|
|
|
bool
|
2012-02-15 02:34:21 +00:00
|
|
|
ScriptInterpreterPython::GenerateTypeSynthClass (StringList &user_input, StringList &output, void* name_token)
|
2011-07-25 16:59:05 +00:00
|
|
|
{
|
|
|
|
|
static int 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
|
|
|
|
|
|
2012-02-15 02:34:21 +00:00
|
|
|
if (!name_token)
|
|
|
|
|
sstr.Printf ("lldb_autogen_python_type_synth_class_%d", num_created_classes);
|
|
|
|
|
else
|
|
|
|
|
sstr.Printf ("lldb_gen_python_type_synth_class_%p", name_token);
|
2011-07-25 16:59:05 +00:00
|
|
|
++num_created_classes;
|
|
|
|
|
std::string auto_generated_class_name = sstr.GetData();
|
|
|
|
|
|
|
|
|
|
sstr.Clear();
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
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.AppendString (auto_generated_class_name.c_str());
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-24 00:14:56 +00:00
|
|
|
void*
|
|
|
|
|
ScriptInterpreterPython::CreateSyntheticScriptedProvider (std::string class_name,
|
|
|
|
|
lldb::ValueObjectSP valobj)
|
|
|
|
|
{
|
|
|
|
|
if (class_name.empty())
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
if (!valobj.get())
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2012-02-17 07:49:44 +00:00
|
|
|
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
|
|
|
|
|
Target *target = exe_ctx.GetTargetPtr();
|
2011-07-24 00:14:56 +00:00
|
|
|
|
|
|
|
|
if (!target)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
Debugger &debugger = target->GetDebugger();
|
|
|
|
|
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
|
|
|
|
|
ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
|
|
|
|
|
|
|
|
|
|
if (!script_interpreter)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
void* ret_val;
|
2011-10-24 17:22:21 +00:00
|
|
|
|
2011-07-24 00:14:56 +00:00
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
2011-07-24 00:14:56 +00:00
|
|
|
ret_val = g_swig_synthetic_script (class_name,
|
|
|
|
|
python_interpreter->m_dictionary_name.c_str(),
|
|
|
|
|
valobj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-15 02:26:42 +00:00
|
|
|
bool
|
2012-02-15 02:34:21 +00:00
|
|
|
ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, StringList &output, void* name_token)
|
2011-07-15 02:26:42 +00:00
|
|
|
{
|
2012-02-15 02:34:21 +00:00
|
|
|
StringList input;
|
|
|
|
|
input.SplitIntoLines(oneliner, strlen(oneliner));
|
|
|
|
|
return GenerateTypeScriptFunction(input, output, name_token);
|
2011-07-15 02:26:42 +00:00
|
|
|
}
|
|
|
|
|
|
2012-02-15 02:34:21 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::GenerateTypeSynthClass (const char* oneliner, StringList &output, void* name_token)
|
|
|
|
|
{
|
|
|
|
|
StringList input;
|
|
|
|
|
input.SplitIntoLines(oneliner, strlen(oneliner));
|
|
|
|
|
return GenerateTypeSynthClass(input, output, name_token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::GenerateBreakpointCommandCallbackData (StringList &user_input, StringList &callback_data)
|
|
|
|
|
{
|
|
|
|
|
static int num_created_functions = 0;
|
|
|
|
|
user_input.RemoveBlankLines ();
|
2010-09-27 18:00:20 +00:00
|
|
|
int num_lines = user_input.GetSize ();
|
|
|
|
|
StreamString sstr;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-11-19 20:47:54 +00:00
|
|
|
// Check to see if we have any data; if not, just return.
|
|
|
|
|
if (user_input.GetSize() == 0)
|
|
|
|
|
return false;
|
|
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
// Take what the user wrote, wrap it all up inside one big auto-generated Python function, passing in the
|
|
|
|
|
// frame and breakpoint location as parameters to the function.
|
2010-06-08 16:52:24 +00:00
|
|
|
|
|
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
sstr.Printf ("lldb_autogen_python_bp_callback_func_%d", num_created_functions);
|
|
|
|
|
++num_created_functions;
|
|
|
|
|
std::string auto_generated_function_name = sstr.GetData();
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
sstr.Clear();
|
2010-09-21 19:25:28 +00:00
|
|
|
StringList auto_generated_function;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
// Create the function name & definition string.
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
sstr.Printf ("def %s (frame, bp_loc, dict):", auto_generated_function_name.c_str());
|
2010-09-27 18:00:20 +00:00
|
|
|
auto_generated_function.AppendString (sstr.GetData());
|
2011-01-14 00:29:16 +00:00
|
|
|
|
|
|
|
|
// Pre-pend code for setting up the session dictionary.
|
|
|
|
|
|
|
|
|
|
auto_generated_function.AppendString (" global_dict = globals()"); // Grab the global dictionary
|
|
|
|
|
auto_generated_function.AppendString (" new_keys = dict.keys()"); // Make a list of keys in the session dict
|
|
|
|
|
auto_generated_function.AppendString (" old_keys = global_dict.keys()"); // Save list of keys in global dict
|
|
|
|
|
auto_generated_function.AppendString (" global_dict.update (dict)"); // Add the session dictionary to the
|
|
|
|
|
// global dictionary.
|
2010-09-21 19:25:28 +00:00
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
// Wrap everything up inside the function, increasing the indentation.
|
2010-09-21 19:25:28 +00:00
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
for (int i = 0; i < num_lines; ++i)
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2010-09-27 18:00:20 +00:00
|
|
|
sstr.Clear ();
|
|
|
|
|
sstr.Printf (" %s", user_input.GetStringAtIndex (i));
|
|
|
|
|
auto_generated_function.AppendString (sstr.GetData());
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
// Append code to clean up the global dictionary and update the session dictionary (all updates in the function
|
|
|
|
|
// got written to the values in the global dictionary, not the session dictionary).
|
|
|
|
|
|
|
|
|
|
auto_generated_function.AppendString (" for key in new_keys:"); // Iterate over all the keys from session dict
|
|
|
|
|
auto_generated_function.AppendString (" dict[key] = global_dict[key]"); // Update session dict values
|
|
|
|
|
auto_generated_function.AppendString (" if key not in old_keys:"); // If key was not originally in global dict
|
|
|
|
|
auto_generated_function.AppendString (" del global_dict[key]"); // ...then remove key/value from global dict
|
|
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
// Verify that the results are valid Python.
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
if (!ExportFunctionDefinitionToInterpreter (auto_generated_function))
|
2010-06-08 16:52:24 +00:00
|
|
|
{
|
2010-09-21 19:25:28 +00:00
|
|
|
return false;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
// Store the name of the auto-generated function to be called.
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-09-27 18:00:20 +00:00
|
|
|
callback_data.AppendString (auto_generated_function_name.c_str());
|
|
|
|
|
return true;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2010-09-27 18:00:20 +00:00
|
|
|
|
2011-07-15 02:26:42 +00:00
|
|
|
std::string
|
|
|
|
|
ScriptInterpreterPython::CallPythonScriptFunction (const char *python_function_name,
|
|
|
|
|
lldb::ValueObjectSP valobj)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (!python_function_name || !(*python_function_name))
|
|
|
|
|
return "<no function>";
|
|
|
|
|
|
|
|
|
|
if (!valobj.get())
|
|
|
|
|
return "<no object>";
|
|
|
|
|
|
2012-02-17 07:49:44 +00:00
|
|
|
ExecutionContext exe_ctx (valobj->GetExecutionContextRef());
|
|
|
|
|
Target *target = exe_ctx.GetTargetPtr();
|
2011-07-15 02:26:42 +00:00
|
|
|
|
|
|
|
|
if (!target)
|
|
|
|
|
return "<no target>";
|
|
|
|
|
|
|
|
|
|
Debugger &debugger = target->GetDebugger();
|
|
|
|
|
ScriptInterpreter *script_interpreter = debugger.GetCommandInterpreter().GetScriptInterpreter();
|
|
|
|
|
ScriptInterpreterPython *python_interpreter = (ScriptInterpreterPython *) script_interpreter;
|
|
|
|
|
|
|
|
|
|
if (!script_interpreter)
|
|
|
|
|
return "<no python>";
|
|
|
|
|
|
|
|
|
|
std::string ret_val;
|
|
|
|
|
|
|
|
|
|
if (python_function_name
|
|
|
|
|
&& *python_function_name)
|
|
|
|
|
{
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(python_interpreter);
|
2011-07-15 02:26:42 +00:00
|
|
|
ret_val = g_swig_typescript_callback (python_function_name,
|
|
|
|
|
python_interpreter->m_dictionary_name.c_str(),
|
|
|
|
|
valobj);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return "<no function name>";
|
|
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-07 17:14:24 +00:00
|
|
|
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.GetStringAtIndex (0);
|
2011-01-14 00:29:16 +00:00
|
|
|
|
|
|
|
|
if (!context)
|
|
|
|
|
return true;
|
|
|
|
|
|
2012-02-21 00:09:25 +00:00
|
|
|
ExecutionContext exe_ctx (context->exe_ctx_ref);
|
|
|
|
|
Target *target = exe_ctx.GetTargetPtr();
|
2011-01-14 00:29:16 +00:00
|
|
|
|
|
|
|
|
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;
|
2010-10-07 17:14:24 +00:00
|
|
|
|
|
|
|
|
if (python_function_name != NULL
|
|
|
|
|
&& python_function_name[0] != '\0')
|
|
|
|
|
{
|
2012-02-21 00:09:25 +00:00
|
|
|
const StackFrameSP stop_frame_sp (exe_ctx.GetFrameSP());
|
2010-10-07 17:14:24 +00:00
|
|
|
BreakpointSP breakpoint_sp = target->GetBreakpointByID (break_id);
|
2011-03-22 01:14:58 +00:00
|
|
|
if (breakpoint_sp)
|
2011-01-14 00:29:16 +00:00
|
|
|
{
|
2011-03-22 01:14:58 +00:00
|
|
|
const BreakpointLocationSP bp_loc_sp (breakpoint_sp->FindLocationByID (break_loc_id));
|
|
|
|
|
|
|
|
|
|
if (stop_frame_sp && bp_loc_sp)
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
2011-03-22 01:14:58 +00:00
|
|
|
bool ret_val = true;
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(python_interpreter);
|
2011-03-22 01:14:58 +00:00
|
|
|
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;
|
2011-01-17 21:55:19 +00:00
|
|
|
}
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
2010-10-07 17:14:24 +00:00
|
|
|
}
|
|
|
|
|
// We currently always true so we stop in case anything goes wrong when
|
|
|
|
|
// trying to call the script function
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2010-11-10 19:18:14 +00:00
|
|
|
|
|
|
|
|
lldb::thread_result_t
|
|
|
|
|
ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
|
|
|
|
|
{
|
|
|
|
|
ScriptInterpreterPython *script_interpreter = (ScriptInterpreterPython *) baton;
|
|
|
|
|
|
|
|
|
|
LogSP 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));
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker locker(script_interpreter,
|
|
|
|
|
ScriptInterpreterPython::Locker::AcquireLock | ScriptInterpreterPython::Locker::InitSession,
|
|
|
|
|
ScriptInterpreterPython::Locker::FreeAcquiredLock | ScriptInterpreterPython::Locker::TearDownSession);
|
|
|
|
|
|
|
|
|
|
if (pty_slave_name != NULL)
|
2011-01-17 21:55:19 +00:00
|
|
|
{
|
2010-11-10 19:18:14 +00:00
|
|
|
StreamString run_string;
|
2011-01-14 00:29:16 +00:00
|
|
|
|
|
|
|
|
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());
|
2010-11-10 19:18:14 +00:00
|
|
|
PyRun_SimpleString (run_string.GetData());
|
2011-01-14 00:29:16 +00:00
|
|
|
run_string.Clear ();
|
2010-11-10 19:18:14 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
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 ();
|
|
|
|
|
|
2011-03-11 00:28:50 +00:00
|
|
|
// The following call drops into the embedded interpreter loop and stays there until the
|
|
|
|
|
// user chooses to exit from the Python interpreter.
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-03-11 00:21:55 +00:00
|
|
|
// When in the embedded interpreter, the user can call arbitrary system and Python stuff, which may require
|
2011-03-11 00:28:50 +00:00
|
|
|
// the ability to run multi-threaded stuff, so we need to surround the call to the embedded interpreter with
|
2011-03-11 00:21:55 +00:00
|
|
|
// calls to Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS.
|
|
|
|
|
|
|
|
|
|
// We ALSO need to surround the call to the embedded interpreter with calls to PyGILState_Ensure and
|
|
|
|
|
// PyGILState_Release. This is because this embedded interpreter is being run on a DIFFERENT THREAD than
|
|
|
|
|
// the thread on which the call to Py_Initialize (and PyEval_InitThreads) was called. Those initializations
|
|
|
|
|
// called PyGILState_Ensure on *that* thread, but it also needs to be called on *this* thread. Otherwise,
|
|
|
|
|
// if the user calls Python code that does threading stuff, the interpreter state will be off, and things could
|
|
|
|
|
// hang (it's happened before).
|
|
|
|
|
|
2011-03-07 23:24:28 +00:00
|
|
|
Py_BEGIN_ALLOW_THREADS
|
|
|
|
|
PyGILState_STATE gstate = PyGILState_Ensure();
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
run_string.Printf ("run_python_interpreter (%s)", script_interpreter->m_dictionary_name.c_str());
|
|
|
|
|
PyRun_SimpleString (run_string.GetData());
|
|
|
|
|
run_string.Clear ();
|
|
|
|
|
|
2011-03-07 23:24:28 +00:00
|
|
|
PyGILState_Release (gstate);
|
|
|
|
|
Py_END_ALLOW_THREADS
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
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();
|
2010-11-10 19:18:14 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
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();
|
2011-01-17 21:55:19 +00:00
|
|
|
|
2010-11-10 19:18:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (script_interpreter->m_embedded_thread_input_reader_sp)
|
|
|
|
|
script_interpreter->m_embedded_thread_input_reader_sp->SetIsDone (true);
|
|
|
|
|
|
|
|
|
|
script_interpreter->m_embedded_python_pty.CloseSlaveFileDescriptor();
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2010-11-10 19:18:14 +00:00
|
|
|
log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_SCRIPT);
|
|
|
|
|
if (log)
|
|
|
|
|
log->Printf ("%p ScriptInterpreterPython::RunEmbeddedPythonInterpreter () thread exiting...", baton);
|
|
|
|
|
|
|
|
|
|
|
2011-03-11 00:28:50 +00:00
|
|
|
// Clean up the input reader and make the debugger pop it off the stack.
|
2011-01-14 00:29:16 +00:00
|
|
|
Debugger &debugger = script_interpreter->GetCommandInterpreter().GetDebugger();
|
2010-11-10 19:18:14 +00:00
|
|
|
const InputReaderSP reader_sp = script_interpreter->m_embedded_thread_input_reader_sp;
|
|
|
|
|
script_interpreter->m_embedded_thread_input_reader_sp.reset();
|
|
|
|
|
debugger.PopInputReader (reader_sp);
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2010-11-10 19:18:14 +00:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-24 00:14:56 +00:00
|
|
|
uint32_t
|
|
|
|
|
ScriptInterpreterPython::CalculateNumChildren (void *implementor)
|
|
|
|
|
{
|
|
|
|
|
if (!implementor)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
if (!g_swig_calc_children)
|
|
|
|
|
return 0;
|
2011-10-24 17:22:21 +00:00
|
|
|
|
2011-07-24 00:14:56 +00:00
|
|
|
uint32_t ret_val = 0;
|
|
|
|
|
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
2011-07-24 00:14:56 +00:00
|
|
|
ret_val = g_swig_calc_children (implementor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
|
}
|
|
|
|
|
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
lldb::ValueObjectSP
|
2011-07-24 00:14:56 +00:00
|
|
|
ScriptInterpreterPython::GetChildAtIndex (void *implementor, uint32_t idx)
|
|
|
|
|
{
|
|
|
|
|
if (!implementor)
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
return lldb::ValueObjectSP();
|
2011-07-24 00:14:56 +00:00
|
|
|
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
if (!g_swig_get_child_index || !g_swig_cast_to_sbvalue)
|
|
|
|
|
return lldb::ValueObjectSP();
|
2011-07-24 00:14:56 +00:00
|
|
|
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
void* child_ptr = NULL;
|
|
|
|
|
lldb::SBValue* value_sb = NULL;
|
|
|
|
|
lldb::ValueObjectSP ret_val;
|
2011-07-24 00:14:56 +00:00
|
|
|
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
Redesign of the interaction between Python and frozen objects:
- introduced two new classes ValueObjectConstResultChild and ValueObjectConstResultImpl: the first one is a ValueObjectChild obtained from
a ValueObjectConstResult, the second is a common implementation backend for VOCR and VOCRCh of method calls meant to read through pointers stored
in frozen objects ; now such reads transparently move from host to target as required
- as a consequence of the above, removed code that made target-memory copies of expression results in several places throughout LLDB, and also
removed code that enabled to recognize an expression result VO as such
- introduced a new GetPointeeData() method in ValueObject that lets you read a given amount of objects of type T from a VO
representing a T* or T[], and doing dereferences transparently
in private layer it returns a DataExtractor ; in public layer it returns an instance of a newly created lldb::SBData
- as GetPointeeData() does the right thing for both frozen and non-frozen ValueObject's, reimplemented ReadPointedString() to use it
en lieu of doing the raw read itself
- introduced a new GetData() method in ValueObject that lets you get a copy of the data that backs the ValueObject (for pointers,
this returns the address without any previous dereferencing steps ; for arrays it actually reads the whole chunk of memory)
in public layer this returns an SBData, just like GetPointeeData()
- introduced a new CreateValueFromData() method in SBValue that lets you create a new SBValue from a chunk of data wrapped in an SBData
the limitation to remember for this kind of SBValue is that they have no address: extracting the address-of for these objects (with any
of GetAddress(), GetLoadAddress() and AddressOf()) will return invalid values
- added several tests to check that "p"-ing objects (STL classes, char* and char[]) will do the right thing
Solved a bug where global pointers to global variables were not dereferenced correctly for display
New target setting "max-string-summary-length" gives the maximum number of characters to show in a string when summarizing it, instead of the hardcoded 128
Solved a bug where the summary for char[] and char* would not be shown if the ValueObject's were dumped via the "p" command
Removed m_pointers_point_to_load_addrs from ValueObject. Introduced a new m_address_type_of_children, which each ValueObject can set to tell the address type
of any pointers and/or references it creates. In the current codebase, this is load address most of the time (the only notable exception being file
addresses that generate file address children UNLESS we have a live process)
Updated help text for summary-string
Fixed an issue in STL formatters where std::stlcontainer::iterator would match the container's synthetic children providers
Edited the syntax and help for some commands to have proper argument types
llvm-svn: 139160
2011-09-06 19:20:51 +00:00
|
|
|
child_ptr = g_swig_get_child_index (implementor,idx);
|
|
|
|
|
if (child_ptr != NULL && child_ptr != Py_None)
|
|
|
|
|
{
|
|
|
|
|
value_sb = (lldb::SBValue*)g_swig_cast_to_sbvalue(child_ptr);
|
|
|
|
|
if (value_sb == NULL)
|
|
|
|
|
Py_XDECREF(child_ptr);
|
|
|
|
|
else
|
|
|
|
|
ret_val = value_sb->get_sp();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
Py_XDECREF(child_ptr);
|
|
|
|
|
}
|
2011-07-24 00:14:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
ScriptInterpreterPython::GetIndexOfChildWithName (void *implementor, const char* child_name)
|
|
|
|
|
{
|
|
|
|
|
if (!implementor)
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
|
|
|
|
|
if (!g_swig_get_index_child)
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
|
|
|
|
|
|
int ret_val = UINT32_MAX;
|
|
|
|
|
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
2011-07-24 00:14:56 +00:00
|
|
|
ret_val = g_swig_get_index_child (implementor, child_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret_val;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-29 19:53:35 +00:00
|
|
|
void
|
|
|
|
|
ScriptInterpreterPython::UpdateSynthProviderInstance (void* implementor)
|
|
|
|
|
{
|
|
|
|
|
if (!implementor)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!g_swig_update_provider)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
2011-07-29 19:53:35 +00:00
|
|
|
g_swig_update_provider (implementor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2011-10-17 21:45:27 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::LoadScriptingModule (const char* pathname,
|
2011-11-07 22:57:04 +00:00
|
|
|
bool can_reload,
|
2011-10-17 21:45:27 +00:00
|
|
|
lldb_private::Error& error)
|
|
|
|
|
{
|
|
|
|
|
if (!pathname || !pathname[0])
|
|
|
|
|
{
|
|
|
|
|
error.SetErrorString("invalid pathname");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!g_swig_call_module_init)
|
|
|
|
|
{
|
|
|
|
|
error.SetErrorString("internal helper function missing");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-29 20:56:30 +00:00
|
|
|
lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
|
2011-10-24 17:22:21 +00:00
|
|
|
|
2011-10-17 21:45:27 +00:00
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
2011-10-17 21:45:27 +00:00
|
|
|
|
|
|
|
|
FileSpec target_file(pathname, true);
|
|
|
|
|
|
|
|
|
|
// TODO: would we want to reject any other value?
|
|
|
|
|
if (target_file.GetFileType() == FileSpec::eFileTypeInvalid ||
|
|
|
|
|
target_file.GetFileType() == FileSpec::eFileTypeUnknown)
|
|
|
|
|
{
|
|
|
|
|
error.SetErrorString("invalid pathname");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const char* directory = target_file.GetDirectory().GetCString();
|
|
|
|
|
std::string basename(target_file.GetFilename().GetCString());
|
|
|
|
|
|
|
|
|
|
// now make sure that Python has "directory" in the search path
|
|
|
|
|
StreamString command_stream;
|
|
|
|
|
command_stream.Printf("if not (sys.path.__contains__('%s')):\n sys.path.append('%s');\n\n",
|
|
|
|
|
directory,
|
|
|
|
|
directory);
|
2011-10-24 17:22:21 +00:00
|
|
|
bool syspath_retval = ExecuteMultipleLines(command_stream.GetData());
|
2011-10-17 21:45:27 +00:00
|
|
|
if (!syspath_retval)
|
|
|
|
|
{
|
|
|
|
|
error.SetErrorString("Python sys.path handling failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// strip .py or .pyc extension
|
|
|
|
|
ConstString extension = target_file.GetFileNameExtension();
|
|
|
|
|
if (::strcmp(extension.GetCString(), "py") == 0)
|
|
|
|
|
basename.resize(basename.length()-3);
|
|
|
|
|
else if(::strcmp(extension.GetCString(), "pyc") == 0)
|
|
|
|
|
basename.resize(basename.length()-4);
|
|
|
|
|
|
|
|
|
|
// check if the module is already import-ed
|
|
|
|
|
command_stream.Clear();
|
|
|
|
|
command_stream.Printf("sys.getrefcount(%s)",basename.c_str());
|
|
|
|
|
int refcount = 0;
|
|
|
|
|
// this call will fail if the module does not exist (because the parameter to it is not a string
|
|
|
|
|
// but an actual Python module object, which is non-existant if the module was not imported before)
|
2011-11-07 22:57:04 +00:00
|
|
|
bool was_imported = (ExecuteOneLineWithReturn(command_stream.GetData(),
|
|
|
|
|
ScriptInterpreterPython::eScriptReturnTypeInt, &refcount) && refcount > 0);
|
|
|
|
|
if (was_imported == true && can_reload == false)
|
2011-10-17 21:45:27 +00:00
|
|
|
{
|
|
|
|
|
error.SetErrorString("module already imported");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// now actually do the import
|
|
|
|
|
command_stream.Clear();
|
|
|
|
|
command_stream.Printf("import %s",basename.c_str());
|
2011-10-24 17:22:21 +00:00
|
|
|
bool import_retval = ExecuteOneLine(command_stream.GetData(), NULL);
|
2011-10-17 21:45:27 +00:00
|
|
|
if (!import_retval)
|
|
|
|
|
{
|
|
|
|
|
error.SetErrorString("Python import statement failed");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-15 02:34:21 +00:00
|
|
|
// call __lldb_init_module(debugger,dict)
|
2011-10-17 21:45:27 +00:00
|
|
|
if (!g_swig_call_module_init (basename,
|
2011-10-24 17:22:21 +00:00
|
|
|
m_dictionary_name.c_str(),
|
2011-10-17 21:45:27 +00:00
|
|
|
debugger_sp))
|
|
|
|
|
{
|
2012-02-15 02:34:21 +00:00
|
|
|
error.SetErrorString("calling __lldb_init_module failed");
|
2011-10-17 21:45:27 +00:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-07 22:57:04 +00:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-16 16:49:25 +00:00
|
|
|
bool
|
|
|
|
|
ScriptInterpreterPython::RunScriptBasedCommand(const char* impl_function,
|
|
|
|
|
const char* args,
|
2011-11-07 22:57:04 +00:00
|
|
|
ScriptedCommandSynchronicity synchronicity,
|
2011-08-16 23:24:13 +00:00
|
|
|
lldb_private::CommandReturnObject& cmd_retobj,
|
2011-08-16 16:49:25 +00:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-29 20:56:30 +00:00
|
|
|
lldb::DebuggerSP debugger_sp = m_interpreter.GetDebugger().shared_from_this();
|
2011-11-07 22:57:04 +00:00
|
|
|
|
|
|
|
|
if (!debugger_sp.get())
|
|
|
|
|
{
|
|
|
|
|
error.SetErrorString("invalid Debugger pointer");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2011-08-16 16:49:25 +00:00
|
|
|
|
|
|
|
|
bool ret_val;
|
|
|
|
|
|
|
|
|
|
std::string err_msg;
|
2011-11-07 22:57:04 +00:00
|
|
|
|
2011-08-16 16:49:25 +00:00
|
|
|
{
|
2011-10-24 17:22:21 +00:00
|
|
|
Locker py_lock(this);
|
2011-11-07 22:57:04 +00:00
|
|
|
SynchronicityHandler synch_handler(debugger_sp,
|
|
|
|
|
synchronicity);
|
|
|
|
|
|
2011-08-16 16:49:25 +00:00
|
|
|
ret_val = g_swig_call_command (impl_function,
|
2011-10-24 17:22:21 +00:00
|
|
|
m_dictionary_name.c_str(),
|
2011-08-16 16:49:25 +00:00
|
|
|
debugger_sp,
|
|
|
|
|
args,
|
|
|
|
|
err_msg,
|
2011-08-19 23:56:34 +00:00
|
|
|
cmd_retobj);
|
2011-08-16 16:49:25 +00:00
|
|
|
}
|
2011-11-07 22:57:04 +00:00
|
|
|
|
2011-08-16 16:49:25 +00:00
|
|
|
if (!ret_val)
|
|
|
|
|
error.SetErrorString(err_msg.c_str());
|
|
|
|
|
else
|
|
|
|
|
error.Clear();
|
|
|
|
|
|
2011-11-07 22:57:04 +00:00
|
|
|
return ret_val;
|
2011-08-16 16:49:25 +00:00
|
|
|
}
|
|
|
|
|
|
2011-08-17 01:30:04 +00:00
|
|
|
// 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
|
|
|
|
|
std::string
|
|
|
|
|
ScriptInterpreterPython::GetDocumentationForItem(const char* item)
|
|
|
|
|
{
|
|
|
|
|
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(),
|
2011-10-17 21:45:27 +00:00
|
|
|
ScriptInterpreter::eScriptReturnTypeCharStrOrNone,
|
2011-08-17 01:30:04 +00:00
|
|
|
&result_ptr) && result_ptr)
|
|
|
|
|
{
|
|
|
|
|
return std::string(result_ptr);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return std::string("");
|
|
|
|
|
}
|
2010-11-10 19:18:14 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
void
|
2011-03-22 01:14:58 +00:00
|
|
|
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
|
2011-07-15 02:26:42 +00:00
|
|
|
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
|
2011-07-24 00:14:56 +00:00
|
|
|
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback,
|
|
|
|
|
SWIGPythonCreateSyntheticProvider python_swig_synthetic_script,
|
|
|
|
|
SWIGPythonCalculateNumChildren python_swig_calc_children,
|
|
|
|
|
SWIGPythonGetChildAtIndex python_swig_get_child_index,
|
|
|
|
|
SWIGPythonGetIndexOfChildWithName python_swig_get_index_child,
|
2011-07-29 19:53:35 +00:00
|
|
|
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue,
|
2011-08-16 16:49:25 +00:00
|
|
|
SWIGPythonUpdateSynthProviderInstance python_swig_update_provider,
|
2011-10-17 21:45:27 +00:00
|
|
|
SWIGPythonCallCommand python_swig_call_command,
|
|
|
|
|
SWIGPythonCallModuleInit python_swig_call_mod_init)
|
2011-03-22 01:14:58 +00:00
|
|
|
{
|
|
|
|
|
g_swig_init_callback = python_swig_init_callback;
|
2011-07-15 02:26:42 +00:00
|
|
|
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
|
|
|
|
|
g_swig_typescript_callback = python_swig_typescript_callback;
|
2011-07-24 00:14:56 +00:00
|
|
|
g_swig_synthetic_script = python_swig_synthetic_script;
|
|
|
|
|
g_swig_calc_children = python_swig_calc_children;
|
|
|
|
|
g_swig_get_child_index = python_swig_get_child_index;
|
|
|
|
|
g_swig_get_index_child = python_swig_get_index_child;
|
|
|
|
|
g_swig_cast_to_sbvalue = python_swig_cast_to_sbvalue;
|
2011-07-29 19:53:35 +00:00
|
|
|
g_swig_update_provider = python_swig_update_provider;
|
2011-08-16 16:49:25 +00:00
|
|
|
g_swig_call_command = python_swig_call_command;
|
2011-10-17 21:45:27 +00:00
|
|
|
g_swig_call_module_init = python_swig_call_mod_init;
|
2011-03-22 01:14:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
ScriptInterpreterPython::InitializePrivate ()
|
2011-01-14 00:29:16 +00:00
|
|
|
{
|
|
|
|
|
Timer scoped_timer (__PRETTY_FUNCTION__, __PRETTY_FUNCTION__);
|
|
|
|
|
|
2011-02-07 23:24:47 +00:00
|
|
|
// 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);
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-08-27 01:24:08 +00:00
|
|
|
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 ('.')");
|
|
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
// Find the module that owns this code and use that path we get to
|
2011-08-27 01:24:08 +00:00
|
|
|
// set the sys.path appropriately.
|
2010-11-10 19:18:14 +00:00
|
|
|
|
2011-01-14 00:29:16 +00:00
|
|
|
FileSpec file_spec;
|
|
|
|
|
char python_dir_path[PATH_MAX];
|
|
|
|
|
if (Host::GetLLDBPath (ePathTypePythonDir, file_spec))
|
|
|
|
|
{
|
2011-08-27 01:24:08 +00:00
|
|
|
std::string python_path("sys.path.insert(0,\"");
|
|
|
|
|
size_t orig_len = python_path.length();
|
2011-01-14 00:29:16 +00:00
|
|
|
if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
|
|
|
|
|
{
|
|
|
|
|
python_path.append (python_dir_path);
|
2011-08-27 01:24:08 +00:00
|
|
|
python_path.append ("\")");
|
|
|
|
|
PyRun_SimpleString (python_path.c_str());
|
|
|
|
|
python_path.resize (orig_len);
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Host::GetLLDBPath (ePathTypeLLDBShlibDir, file_spec))
|
|
|
|
|
{
|
|
|
|
|
if (file_spec.GetPath(python_dir_path, sizeof (python_dir_path)))
|
|
|
|
|
{
|
|
|
|
|
python_path.append (python_dir_path);
|
2011-08-27 01:24:08 +00:00
|
|
|
python_path.append ("\")");
|
|
|
|
|
PyRun_SimpleString (python_path.c_str());
|
|
|
|
|
python_path.resize (orig_len);
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-08-22 19:10:09 +00:00
|
|
|
PyRun_SimpleString ("sys.dont_write_bytecode = 1");
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-06-13 21:33:00 +00:00
|
|
|
PyRun_SimpleString ("import embedded_interpreter");
|
2011-01-14 00:29:16 +00:00
|
|
|
|
2011-06-13 21:33:00 +00:00
|
|
|
PyRun_SimpleString ("from embedded_interpreter import run_python_interpreter");
|
|
|
|
|
PyRun_SimpleString ("from embedded_interpreter import run_one_line");
|
|
|
|
|
PyRun_SimpleString ("from termios import *");
|
2011-02-07 19:04:58 +00:00
|
|
|
|
2011-02-07 23:24:47 +00:00
|
|
|
stdin_tty_state.Restore();
|
2011-01-14 00:29:16 +00:00
|
|
|
}
|
|
|
|
|
|
2011-03-22 01:14:58 +00:00
|
|
|
//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 ();
|
|
|
|
|
//}
|
2011-11-04 03:34:56 +00:00
|
|
|
|
|
|
|
|
#endif // #ifdef LLDB_DISABLE_PYTHON
|