Python synthetic children:

- you can now define a Python class as a synthetic children producer for a type
   the class must adhere to this "interface":
        def __init__(self, valobj, dict):
     	def get_child_at_index(self, index):
     	def get_child_index(self, name):
   then using type synth add -l className typeName
   (e.g. type synth add -l fooSynthProvider foo)
   (This is still WIP with lots to be added)
   A small test case is available also as reference

llvm-svn: 135865
This commit is contained in:
Enrico Granata 2011-07-24 00:14:56 +00:00
parent fb66d5cc9c
commit a37a065c33
26 changed files with 1319 additions and 136 deletions

View file

@ -14,6 +14,10 @@
#include <stdio.h>
#ifndef SWIG
class lldb_private::SyntheticScriptProvider;
#endif
namespace lldb {
class SBValue
@ -205,7 +209,9 @@ protected:
friend class SBFrame;
#ifndef SWIG
// need this to decapsulate the SP from here
friend class lldb_private::SyntheticScriptProvider;
// Mimic shared pointer...
lldb_private::ValueObject *
get() const;

View file

@ -477,6 +477,11 @@ public:
class Formatting
{
public:
// use this call to force the FM to consider itself updated even when there is no apparent reason for that
static void
ForceUpdate();
class ValueFormats
{
public:
@ -507,7 +512,7 @@ public:
lldb::SummaryFormatSP& entry);
static bool
GetSyntheticFilter(ValueObject& vobj,
lldb::SyntheticFilterSP& entry);
lldb::SyntheticChildrenSP& entry);
class NamedSummaryFormats
{

View file

@ -12,6 +12,12 @@
// C Includes
#if defined (__APPLE__)
#include <Python/Python.h>
#else
#include <Python.h>
#endif
#include <stdint.h>
#include <unistd.h>
@ -25,6 +31,7 @@
#include "lldb/lldb-public.h"
#include "lldb/lldb-enumerations.h"
#include "lldb/API/SBValue.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Interpreter/ScriptInterpreterPython.h"
#include "lldb/Symbol/SymbolContext.h"
@ -82,19 +89,90 @@ struct ValueFormat
};
struct SyntheticFilter
class SyntheticChildrenFrontEnd
{
protected:
lldb::ValueObjectSP m_backend;
public:
SyntheticChildrenFrontEnd(lldb::ValueObjectSP be) :
m_backend(be)
{}
virtual
~SyntheticChildrenFrontEnd()
{
}
virtual uint32_t
CalculateNumChildren() = 0;
virtual lldb::ValueObjectSP
GetChildAtIndex (uint32_t idx, bool can_create) = 0;
virtual uint32_t
GetIndexOfChildWithName (const ConstString &name) = 0;
typedef lldb::SharedPtr<SyntheticChildrenFrontEnd>::Type SharedPointer;
};
class SyntheticChildren
{
public:
bool m_cascades;
bool m_skip_pointers;
bool m_skip_references;
std::vector<std::string> m_expression_paths;
public:
SyntheticChildren(bool casc = false,
bool skipptr = false,
bool skipref = false) :
m_cascades(casc),
m_skip_pointers(skipptr),
m_skip_references(skipref)
{
}
virtual
~SyntheticChildren()
{
}
bool
Cascades() const
{
return m_cascades;
}
bool
SkipsPointers() const
{
return m_skip_pointers;
}
bool
SkipsReferences() const
{
return m_skip_references;
}
virtual std::string
GetDescription() = 0;
virtual SyntheticChildrenFrontEnd::SharedPointer
GetFrontEnd(lldb::ValueObjectSP backend) = 0;
typedef lldb::SharedPtr<SyntheticChildren>::Type SharedPointer;
typedef bool(*SyntheticChildrenCallback)(void*, const char*, const SyntheticChildren::SharedPointer&);
};
class SyntheticFilter : public SyntheticChildren
{
std::vector<std::string> m_expression_paths;
public:
SyntheticFilter(bool casc = false,
bool skipptr = false,
bool skipref = false) :
m_cascades(casc),
m_skip_pointers(skipptr),
m_skip_references(skipref),
SyntheticChildren(casc, skipptr, skipref),
m_expression_paths()
{
}
@ -129,10 +207,149 @@ struct SyntheticFilter
std::string
GetDescription();
typedef lldb::SharedPtr<SyntheticFilter>::Type SharedPointer;
typedef bool(*SyntheticFilterCallback)(void*, const char*, const SyntheticFilter::SharedPointer&);
class FrontEnd : public SyntheticChildrenFrontEnd
{
private:
SyntheticFilter* filter;
public:
FrontEnd(SyntheticFilter* flt,
lldb::ValueObjectSP be) :
SyntheticChildrenFrontEnd(be),
filter(flt)
{}
virtual
~FrontEnd()
{
}
virtual uint32_t
CalculateNumChildren()
{
return filter->GetCount();
}
virtual lldb::ValueObjectSP
GetChildAtIndex (uint32_t idx, bool can_create)
{
if (idx >= filter->GetCount())
return lldb::ValueObjectSP();
return m_backend->GetSyntheticExpressionPathChild(filter->GetExpressionPathAtIndex(idx).c_str(), can_create);
}
virtual uint32_t
GetIndexOfChildWithName (const ConstString &name)
{
const char* name_cstr = name.GetCString();
for (int i = 0; i < filter->GetCount(); i++)
{
const char* expr_cstr = filter->GetExpressionPathAtIndex(i).c_str();
if (::strcmp(name_cstr, expr_cstr))
return i;
}
return UINT32_MAX;
}
typedef lldb::SharedPtr<SyntheticChildrenFrontEnd>::Type SharedPointer;
};
virtual SyntheticChildrenFrontEnd::SharedPointer
GetFrontEnd(lldb::ValueObjectSP backend)
{
return SyntheticChildrenFrontEnd::SharedPointer(new FrontEnd(this, backend));
}
};
class SyntheticScriptProvider : public SyntheticChildren
{
std::string m_python_class;
public:
SyntheticScriptProvider(bool casc = false,
bool skipptr = false,
bool skipref = false,
std::string pclass = "") :
SyntheticChildren(casc, skipptr, skipref),
m_python_class(pclass)
{
}
std::string
GetPythonClassName() { return m_python_class; }
std::string
GetDescription();
class FrontEnd : public SyntheticChildrenFrontEnd
{
private:
std::string m_python_class;
PyObject* m_wrapper;
ScriptInterpreter *m_interpreter;
public:
FrontEnd(std::string pclass,
lldb::ValueObjectSP be);
virtual
~FrontEnd()
{
Py_XDECREF(m_wrapper);
}
virtual uint32_t
CalculateNumChildren()
{
if (m_wrapper == NULL)
return 0;
return m_interpreter->CalculateNumChildren(m_wrapper);
}
virtual lldb::ValueObjectSP
GetChildAtIndex (uint32_t idx, bool can_create)
{
if (m_wrapper == NULL)
return lldb::ValueObjectSP();
PyObject* py_return = (PyObject*)m_interpreter->GetChildAtIndex(m_wrapper, idx);
if (py_return == NULL || py_return == Py_None)
{
Py_XDECREF(py_return);
return lldb::ValueObjectSP();
}
lldb::SBValue *sb_ptr = m_interpreter->CastPyObjectToSBValue(py_return);
if (py_return == NULL)
return lldb::ValueObjectSP();
return sb_ptr->m_opaque_sp;
}
virtual uint32_t
GetIndexOfChildWithName (const ConstString &name)
{
if (m_wrapper == NULL)
return UINT32_MAX;
return m_interpreter->GetIndexOfChildWithName(m_wrapper, name.GetCString());
}
typedef lldb::SharedPtr<SyntheticChildrenFrontEnd>::Type SharedPointer;
};
virtual SyntheticChildrenFrontEnd::SharedPointer
GetFrontEnd(lldb::ValueObjectSP backend)
{
return SyntheticChildrenFrontEnd::SharedPointer(new FrontEnd(m_python_class, backend));
}
};
struct SummaryFormat
{
bool m_cascades;

View file

@ -545,7 +545,7 @@ public:
bool
Get(ValueObject& vobj,
lldb::SyntheticFilterSP& entry,
lldb::SyntheticChildrenSP& entry,
uint32_t* reason = NULL)
{
if (!IsEnabled())
@ -791,7 +791,7 @@ public:
bool
Get(ValueObject& vobj,
lldb::SyntheticFilterSP& entry)
lldb::SyntheticChildrenSP& entry)
{
Mutex::Locker(m_map_mutex);
@ -803,7 +803,7 @@ public:
for (begin = m_active_categories.begin(); begin != end; begin++)
{
FormatCategory::SharedPointer category = *begin;
lldb::SyntheticFilterSP current_format;
lldb::SyntheticChildrenSP current_format;
if (!category->Get(vobj, current_format, &reason_why))
continue;
if (reason_why == lldb::eFormatterDirectChoice)
@ -947,7 +947,7 @@ public:
}
bool
Get(ValueObject& vobj,
lldb::SyntheticFilterSP& entry)
lldb::SyntheticChildrenSP& entry)
{
return m_categories_map.Get(vobj, entry);
}

View file

@ -739,13 +739,14 @@ protected:
// as an independent ValueObjectConstResult, which isn't managed by us.
ValueObject *m_deref_valobj;
lldb::Format m_format;
uint32_t m_last_format_mgr_revision;
lldb::SummaryFormatSP m_last_summary_format;
lldb::SummaryFormatSP m_forced_summary_format;
lldb::ValueFormatSP m_last_value_format;
lldb::SyntheticFilterSP m_last_synthetic_filter;
lldb::user_id_t m_user_id_of_forced_summary;
lldb::Format m_format;
uint32_t m_last_format_mgr_revision;
lldb::SummaryFormatSP m_last_summary_format;
lldb::SummaryFormatSP m_forced_summary_format;
lldb::ValueFormatSP m_last_value_format;
lldb::SyntheticChildrenSP m_last_synthetic_filter;
lldb::user_id_t m_user_id_of_forced_summary;
bool m_value_is_valid:1,
m_value_did_change:1,
m_children_count_valid:1,

View file

@ -12,6 +12,7 @@
// C Includes
// C++ Includes
#include <map>
#include <ostream>
#include <vector>
// Other libraries and framework includes
@ -21,14 +22,17 @@
namespace lldb_private {
//----------------------------------------------------------------------
// A ValueObject that represents memory at a given address, viewed as some
// set lldb type.
// A ValueObject that obtains its children from some source other than
// real information
// This is currently used to implement children filtering, where only
// a subset of the real children are shown, but it can be used for any
// source of made-up children information
//----------------------------------------------------------------------
class ValueObjectSyntheticFilter : public ValueObject
class ValueObjectSynthetic : public ValueObject
{
public:
virtual
~ValueObjectSyntheticFilter();
~ValueObjectSynthetic();
virtual size_t
GetByteSize();
@ -105,16 +109,25 @@ protected:
lldb::TypeSP m_type_sp;
lldb::ValueObjectSP m_owning_valobj_sp;
lldb::SyntheticValueType m_use_synthetic;
lldb::SyntheticFilterSP m_synth_filter;
lldb::SyntheticChildrenFrontEndSP m_synth_filter;
typedef std::map<uint32_t, lldb::ValueObjectSP> ByIndexMap;
typedef std::map<const char*, uint32_t> NameToIndexMap;
typedef ByIndexMap::iterator ByIndexIterator;
typedef NameToIndexMap::iterator NameToIndexIterator;
ByIndexMap m_children_byindex;
NameToIndexMap m_name_toindex;
private:
friend class ValueObject;
ValueObjectSyntheticFilter (ValueObject &parent, lldb::SyntheticFilterSP filter);
ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter);
//------------------------------------------------------------------
// For ValueObject only
//------------------------------------------------------------------
DISALLOW_COPY_AND_ASSIGN (ValueObjectSyntheticFilter);
DISALLOW_COPY_AND_ASSIGN (ValueObjectSynthetic);
};
} // namespace lldb_private

View file

@ -10,10 +10,13 @@
#ifndef liblldb_ScriptInterpreter_h_
#define liblldb_ScriptInterpreter_h_
#include "lldb/API/SBValue.h"
#include "lldb/lldb-private.h"
#include "lldb/Core/Broadcaster.h"
#include "lldb/Utility/PseudoTerminal.h"
namespace lldb_private {
class ScriptInterpreter
@ -30,6 +33,15 @@ public:
typedef std::string (*SWIGPythonTypeScriptCallbackFunction) (const char *python_function_name,
const char *session_dictionary_name,
const lldb::ValueObjectSP& valobj_sp);
typedef void* (*SWIGPythonCreateSyntheticProvider) (const std::string python_class_name,
const char *session_dictionary_name,
const lldb::ValueObjectSP& valobj_sp);
typedef uint32_t (*SWIGPythonCalculateNumChildren) (void *implementor);
typedef void* (*SWIGPythonGetChildAtIndex) (void *implementor, uint32_t idx);
typedef int (*SWIGPythonGetIndexOfChildWithName) (void *implementor, const char* child_name);
typedef lldb::SBValue* (*SWIGPythonCastPyObjectToSBValue) (void* data);
typedef enum
{
@ -89,6 +101,13 @@ public:
return false;
}
virtual void*
CreateSyntheticScriptedProvider (std::string class_name,
lldb::ValueObjectSP valobj)
{
return NULL;
}
// use this if the function code is just a one-liner script
virtual bool
GenerateTypeScriptFunction (const char* oneliner, StringList &output)
@ -113,6 +132,30 @@ public:
{
return;
}
virtual uint32_t
CalculateNumChildren (void *implementor)
{
return 0;
}
virtual void*
GetChildAtIndex (void *implementor, uint32_t idx)
{
return NULL;
}
virtual int
GetIndexOfChildWithName (void *implementor, const char* child_name)
{
return UINT32_MAX;
}
virtual lldb::SBValue*
CastPyObjectToSBValue (void* data)
{
return NULL;
}
const char *
GetScriptInterpreterPtyName ();
@ -129,7 +172,12 @@ public:
static void
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
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,
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue);
static void
TerminateInterpreter ();

View file

@ -56,6 +56,22 @@ public:
bool
GenerateTypeScriptFunction (const char* oneliner, StringList &output);
void*
CreateSyntheticScriptedProvider (std::string class_name,
lldb::ValueObjectSP valobj);
virtual uint32_t
CalculateNumChildren (void *implementor);
virtual void*
GetChildAtIndex (void *implementor, uint32_t idx);
virtual int
GetIndexOfChildWithName (void *implementor, const char* child_name);
virtual lldb::SBValue*
CastPyObjectToSBValue (void* data);
bool
GenerateFunction(std::string& signature, StringList &input, StringList &output);
@ -103,7 +119,12 @@ public:
static void
InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback);
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,
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalu);
protected:

View file

@ -0,0 +1,78 @@
//===---------------------PythonPointer.h ------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef utility_PythonPointer_h_
#define utility_PythonPointer_h_
#include <algorithm>
#include <memory>
#if defined (__APPLE__)
#include <Python/Python.h>
#else
#include <Python.h>
#endif
namespace lldb_private {
template<class T>
class PythonPointer
{
public:
typedef PyObject* element_type;
private:
element_type* ptr_;
bool my_ref;
public:
PythonPointer(element_type p, bool steal_ref = false) :
ptr_(p),
my_ref(!steal_ref)
{
if (my_ref)
Py_INCREF(ptr_);
}
PythonPointer(const PythonPointer& r, bool steal_ref = false) :
ptr_(r.ptr_),
my_ref(!steal_ref)
{
if (my_ref)
Py_INCREF(ptr_);
}
~PythonPointer()
{
if (my_ref)
Py_XDECREF(ptr_);
}
PythonPointer
StealReference()
{
return PythonPointer(ptr_,true);
}
PythonPointer
DuplicateReference()
{
return PythonPointer(ptr_, false);
}
element_type get() const {return ptr_;}
bool IsNull() { return ptr_ == NULL; }
bool IsNone() { return ptr_ == Py_None; }
operator PyObject* () { return ptr_; }
};
} // namespace lldb
#endif // utility_PythonPointer_h_

View file

@ -67,7 +67,8 @@ namespace lldb {
typedef SharedPtr<lldb_private::SummaryFormat>::Type SummaryFormatSP;
typedef SharedPtr<lldb_private::SymbolFile>::Type SymbolFileSP;
typedef SharedPtr<lldb_private::SymbolContextSpecifier>::Type SymbolContextSpecifierSP;
typedef SharedPtr<lldb_private::SyntheticFilter>::Type SyntheticFilterSP;
typedef SharedPtr<lldb_private::SyntheticChildren>::Type SyntheticChildrenSP;
typedef SharedPtr<lldb_private::SyntheticChildrenFrontEnd>::Type SyntheticChildrenFrontEndSP;
typedef SharedPtr<lldb_private::Target>::Type TargetSP;
typedef SharedPtr<lldb_private::Thread>::Type ThreadSP;
typedef SharedPtr<lldb_private::ThreadPlan>::Type ThreadPlanSP;

View file

@ -144,7 +144,9 @@ class SymbolContextSpecifier;
class SymbolFile;
class SymbolVendor;
class Symtab;
class SyntheticFilter;
class SyntheticChildren;
class SyntheticChildrenFrontEnd;
class SyntheticScriptProvider;
class Target;
class TargetList;
class Thread;

View file

@ -1221,6 +1221,7 @@
94A9112D13D5DF210046D8A6 /* FormatClasses.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatClasses.cpp; path = source/Core/FormatClasses.cpp; sourceTree = "<group>"; };
94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ValueObjectSyntheticFilter.h; path = include/lldb/Core/ValueObjectSyntheticFilter.h; sourceTree = "<group>"; };
94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectSyntheticFilter.cpp; path = source/Core/ValueObjectSyntheticFilter.cpp; sourceTree = "<group>"; };
94EBAC8313D9EE26009BA64E /* PythonPointer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = PythonPointer.h; path = include/lldb/Utility/PythonPointer.h; sourceTree = "<group>"; };
961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FuncUnwinders.cpp; path = source/Symbol/FuncUnwinders.cpp; sourceTree = "<group>"; };
961FABB91235DE1600F93A47 /* UnwindPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindPlan.cpp; path = source/Symbol/UnwindPlan.cpp; sourceTree = "<group>"; };
961FABBA1235DE1600F93A47 /* UnwindTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindTable.cpp; path = source/Symbol/UnwindTable.cpp; sourceTree = "<group>"; };
@ -1864,6 +1865,7 @@
2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */,
2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */,
94031A9F13CF5B3D00DCFF3C /* PriorityPointerPair.h */,
94EBAC8313D9EE26009BA64E /* PythonPointer.h */,
);
name = Utility;
sourceTree = "<group>";

View file

@ -281,7 +281,6 @@ LLDBSwigPythonBreakpointCallbackFunction
// Find the current session's dictionary in the main module's dictionary.
if (PyDict_Check (main_dict))
{
session_dict = NULL;
while (PyDict_Next (main_dict, &pos, &key, &value))
@ -401,7 +400,6 @@ LLDBSwigPythonCallTypeScript
// Find the current session's dictionary in the main module's dictionary.
if (PyDict_Check (main_dict))
{
session_dict = NULL;
while (PyDict_Next (main_dict, &pos, &key, &value))
@ -493,5 +491,278 @@ LLDBSwigPythonCallTypeScript
return retval;
}
SWIGEXPORT void*
LLDBSwigPythonCreateSyntheticProvider
(
const std::string python_class_name,
const char *session_dictionary_name,
const lldb::ValueObjectSP& valobj_sp
)
{
PyObject* retval = NULL;
if (python_class_name.empty() || !session_dictionary_name)
Py_RETURN_NONE;
lldb::ValueObjectSP* valobj_sp_ptr = new lldb::ValueObjectSP(valobj_sp);
PyObject *ValObj_PyObj = SWIG_NewPointerObj((void *) valobj_sp_ptr, SWIGTYPE_p_lldb__SBValue, SWIG_POINTER_OWN);
if (ValObj_PyObj == NULL)
Py_RETURN_NONE;
const char* python_function_name = python_class_name.c_str();
PyObject *pmodule, *main_dict, *session_dict, *pfunc;
PyObject *pvalue;
pmodule = PyImport_AddModule ("__main__");
if (pmodule != NULL)
{
main_dict = PyModule_GetDict (pmodule);
if (main_dict != NULL)
{
PyObject *key, *value;
Py_ssize_t pos = 0;
// Find the current session's dictionary in the main module's dictionary.
if (PyDict_Check (main_dict))
{
session_dict = NULL;
while (PyDict_Next (main_dict, &pos, &key, &value))
{
// We have stolen references to the key and value objects in the dictionary; we need to increment
// them now so that Python's garbage collector doesn't collect them out from under us.
Py_INCREF (key);
Py_INCREF (value);
if (strcmp (PyString_AsString (key), session_dictionary_name) == 0)
{
session_dict = value;
break;
}
}
}
if (!session_dict || !PyDict_Check (session_dict))
return retval;
// Find the function we need to call in the current session's dictionary.
pos = 0;
pfunc = NULL;
while (PyDict_Next (session_dict, &pos, &key, &value))
{
if (PyString_Check (key))
{
// We have stolen references to the key and value objects in the dictionary; we need to increment
// them now so that Python's garbage collector doesn't collect them out from under us.
Py_INCREF (key);
Py_INCREF (value);
if (strcmp (PyString_AsString (key), python_function_name) == 0)
{
pfunc = value;
break;
}
}
}
// Set up the arguments and call the function.
if (pfunc && PyCallable_Check (pfunc))
{
PyObject *argList = Py_BuildValue("SS", ValObj_PyObj, session_dict);
if (PyErr_Occurred ())
{
PyErr_Print();
PyErr_Clear();
return retval;
}
if (argList == NULL)
{
return retval;
}
Py_INCREF(ValObj_PyObj);
pvalue = PyObject_CallObject(pfunc, argList);
Py_DECREF(argList);
if (pvalue != NULL)
{
if (pvalue != Py_None)
retval = pvalue;
else
{
retval = Py_None;
Py_INCREF(retval);
}
}
else if (PyErr_Occurred ())
{
PyErr_Print();
PyErr_Clear();
}
Py_INCREF (session_dict);
}
else if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
}
else if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
}
else if (PyErr_Occurred ())
{
PyErr_Print();
PyErr_Clear ();
}
if (retval)
return retval;
else
Py_RETURN_NONE;
}
/*
these four calls below are meant to support
Python-based synthetic children providers
they essentially mimic the four pure virtual
method calls provided by the frontend class
*/
SWIGEXPORT uint32_t
LLDBSwigPython_CalculateNumChildren
(
PyObject *implementor
)
{
static char callee_name[] = "num_children";
if (implementor == NULL || implementor == Py_None)
return 0;
PyObject* py_return = PyObject_CallMethod(implementor, callee_name, NULL);
if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
if (py_return == NULL || py_return == Py_None)
{
Py_XDECREF(py_return);
return UINT32_MAX;
}
long retval = PyInt_AsLong(py_return);
Py_DECREF(py_return);
if (retval >= 0)
return (uint32_t)retval;
if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
return 0;
}
SWIGEXPORT PyObject*
LLDBSwigPython_GetChildAtIndex
(
PyObject *implementor,
uint32_t idx
)
{
static char callee_name[] = "get_child_at_index";
static char param_format[] = "i";
if (implementor == NULL || implementor == Py_None)
return NULL;
PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, idx);
if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
if (py_return == NULL || py_return == Py_None)
{
Py_XDECREF(py_return);
return NULL;
}
lldb::SBValue* sbvalue_ptr = NULL;
if (SWIG_ConvertPtr(py_return, (void**)&sbvalue_ptr, SWIGTYPE_p_lldb__SBValue, 0) == -1)
{
Py_DECREF(py_return);
return NULL;
}
if (sbvalue_ptr == NULL)
return NULL;
return py_return;
}
SWIGEXPORT int
LLDBSwigPython_GetIndexOfChildWithName
(
PyObject *implementor,
const char* child_name
)
{
static char callee_name[] = "get_child_index";
static char param_format[] = "s";
if (implementor == NULL || implementor == Py_None)
return 0;
PyObject* py_return = PyObject_CallMethod(implementor, callee_name, param_format, child_name);
if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
if (py_return == NULL || py_return == Py_None)
{
Py_XDECREF(py_return);
return UINT32_MAX;
}
long retval = PyInt_AsLong(py_return);
Py_DECREF(py_return);
if (retval >= 0)
return (uint32_t)retval;
if (PyErr_Occurred())
{
PyErr_Print();
PyErr_Clear();
}
return 0;
}
SWIGEXPORT lldb::SBValue*
LLDBSWIGPython_CastPyObjectToSBValue
(
PyObject* data
)
{
lldb::SBValue* sb_ptr = NULL;
int valid_cast = SWIG_ConvertPtr(data, (void**)&sb_ptr, SWIGTYPE_p_lldb__SBValue, 0);
if (valid_cast == -1)
return NULL;
return sb_ptr;
}
%}

View file

@ -322,6 +322,19 @@ LLDBSwigPythonCallTypeScript
const lldb::ValueObjectSP& valobj_sp
);
extern "C" void*
LLDBSwigPythonCreateSyntheticProvider
(
const std::string python_class_name,
const char *session_dictionary_name,
const lldb::ValueObjectSP& valobj_sp
);
extern "C" uint32_t LLDBSwigPython_CalculateNumChildren (void *implementor);
extern "C" void* LLDBSwigPython_GetChildAtIndex (void *implementor, uint32_t idx);
extern "C" int LLDBSwigPython_GetIndexOfChildWithName (void *implementor, const char* child_name);
extern "C" lldb::SBValue* LLDBSWIGPython_CastPyObjectToSBValue (void* data);
extern "C" void init_lldb(void);
@ -334,6 +347,11 @@ SBCommandInterpreter::InitializeSWIG ()
g_initialized = true;
ScriptInterpreter::InitializeInterpreter (init_lldb,
LLDBSwigPythonBreakpointCallbackFunction,
LLDBSwigPythonCallTypeScript);
LLDBSwigPythonCallTypeScript,
LLDBSwigPythonCreateSyntheticProvider,
LLDBSwigPython_CalculateNumChildren,
LLDBSwigPython_GetChildAtIndex,
LLDBSwigPython_GetIndexOfChildWithName,
LLDBSWIGPython_CastPyObjectToSBValue);
}
}

View file

@ -10,6 +10,9 @@
#include "CommandObjectType.h"
// C Includes
#include <ctype.h>
// C++ Includes
#include "lldb/Core/ConstString.h"
@ -418,8 +421,8 @@ CommandObjectTypeFormatList_LoopCallback (
// CommandObjectTypeSummaryAdd
//-------------------------------------------------------------------------
static const char *g_reader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
"def function (valobj,dict):";
static const char *g_summary_addreader_instructions = "Enter your Python command(s). Type 'DONE' to end.\n"
"def function (valobj,dict):";
class TypeScriptAddInputReader : public InputReaderEZ
{
@ -441,7 +444,7 @@ public:
bool batch_mode = data.reader.GetDebugger().GetCommandInterpreter().GetBatchCommandMode();
if (!batch_mode)
{
out_stream->Printf ("%s\n", g_reader_instructions);
out_stream->Printf ("%s\n", g_summary_addreader_instructions);
if (data.reader.GetPrompt())
out_stream->Printf ("%s", data.reader.GetPrompt());
out_stream->Flush();
@ -1016,7 +1019,7 @@ CommandObject (interpreter,
" value = valobj.GetChildMemberWithName('value');\n"
" return 'My value is ' + value.GetValue();\n"
"DONE\n"
"(lldb)"
"(lldb) <-- type further LLDB commands here\n"
);
}
@ -2404,6 +2407,10 @@ private:
case 'c':
m_expr_paths.push_back(option_arg);
break;
case 'l':
m_class_name = std::string(option_arg);
is_class_based = true;
break;
case 'p':
m_skip_pointers = true;
break;
@ -2425,10 +2432,12 @@ private:
OptionParsingStarting ()
{
m_cascade = true;
m_expr_paths.clear();
m_class_name = "";
m_skip_pointers = false;
m_skip_references = false;
m_category = NULL;
m_expr_paths.clear();
is_class_based = false;
}
const OptionDefinition*
@ -2446,9 +2455,13 @@ private:
bool m_cascade;
bool m_skip_references;
bool m_skip_pointers;
std::string m_class_name;
bool m_input_python;
option_vector m_expr_paths;
const char* m_category;
bool is_class_based;
typedef option_vector::iterator ExpressionPathsIterator;
};
@ -2460,7 +2473,114 @@ private:
return &m_options;
}
bool
Execute_ChildrenList (Args& command, CommandReturnObject &result)
{
const size_t argc = command.GetArgumentCount();
if (argc < 1)
{
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
if (m_options.m_expr_paths.size() == 0)
{
result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
SyntheticChildrenSP entry;
SyntheticFilter* impl = new SyntheticFilter(m_options.m_cascade,
m_options.m_skip_pointers,
m_options.m_skip_references);
entry.reset(impl);
// go through the expression paths
CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end();
for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
impl->AddExpressionPath(*begin);
// now I have a valid provider, let's add it to every type
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
for (size_t i = 0; i < argc; i++) {
const char* typeA = command.GetArgumentAtIndex(i);
ConstString typeCS(typeA);
if (typeCS)
category->Filter()->Add(typeCS.GetCString(), entry);
else
{
result.AppendError("empty typenames not allowed");
result.SetStatus(eReturnStatusFailed);
return false;
}
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return result.Succeeded();
}
bool
Execute_PythonClass (Args& command, CommandReturnObject &result)
{
const size_t argc = command.GetArgumentCount();
if (argc < 1)
{
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
if (m_options.m_class_name.empty() && !m_options.m_input_python)
{
result.AppendErrorWithFormat ("%s needs either a Python class name or -P to directly input Python code.\n", m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
SyntheticChildrenSP entry;
SyntheticScriptProvider* impl = new SyntheticScriptProvider(m_options.m_cascade,
m_options.m_skip_pointers,
m_options.m_skip_references,
m_options.m_class_name);
entry.reset(impl);
// now I have a valid provider, let's add it to every type
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
for (size_t i = 0; i < argc; i++) {
const char* typeA = command.GetArgumentAtIndex(i);
ConstString typeCS(typeA);
if (typeCS)
category->Filter()->Add(typeCS.GetCString(), entry);
else
{
result.AppendError("empty typenames not allowed");
result.SetStatus(eReturnStatusFailed);
return false;
}
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return result.Succeeded();
}
public:
CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) :
CommandObject (interpreter,
"type synth add",
@ -2486,55 +2606,10 @@ public:
bool
Execute (Args& command, CommandReturnObject &result)
{
const size_t argc = command.GetArgumentCount();
if (argc < 1)
{
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
if (m_options.m_expr_paths.size() == 0)
{
result.AppendErrorWithFormat ("%s needs one or more children.\n", m_cmd_name.c_str());
result.SetStatus(eReturnStatusFailed);
return false;
}
SyntheticFilterSP entry;
entry.reset(new SyntheticFilter(m_options.m_cascade,
m_options.m_skip_pointers,
m_options.m_skip_references));
// go through the expression paths
CommandOptions::ExpressionPathsIterator begin, end = m_options.m_expr_paths.end();
for (begin = m_options.m_expr_paths.begin(); begin != end; begin++)
entry->AddExpressionPath(*begin);
// now I have a valid provider, let's add it to every type
lldb::FormatCategorySP category;
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
for (size_t i = 0; i < argc; i++) {
const char* typeA = command.GetArgumentAtIndex(i);
ConstString typeCS(typeA);
if (typeCS)
category->Filter()->Add(typeCS.GetCString(), entry);
else
{
result.AppendError("empty typenames not allowed");
result.SetStatus(eReturnStatusFailed);
return false;
}
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return result.Succeeded();
if (m_options.is_class_based)
return Execute_PythonClass(command, result);
else
return Execute_ChildrenList(command, result);
}
};
@ -2542,10 +2617,11 @@ OptionDefinition
CommandObjectTypeSynthAdd::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
{ LLDB_OPT_SET_ALL, false, "child", 'c', required_argument, NULL, 0, eArgTypeName, "Include this expression path in the synthetic view."},
{ LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for pointers-to-type objects."},
{ LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for references-to-type objects."},
{ LLDB_OPT_SET_ALL, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Add this to the given category instead of the default one."},
{ LLDB_OPT_SET_1, false, "child", 'c', required_argument, NULL, 0, eArgTypeName, "Include this expression path in the synthetic view."},
{ LLDB_OPT_SET_2, false, "python-class", 'l', required_argument, NULL, 0, eArgTypeName, "Use this Python class to produce synthetic children."},
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
};

View file

@ -1746,6 +1746,12 @@ GetFormatManager() {
return g_format_manager;
}
void
Debugger::Formatting::ForceUpdate()
{
GetFormatManager().Changed();
}
bool
Debugger::Formatting::ValueFormats::Get(ValueObject& vobj, ValueFormat::SharedPointer &entry)
{
@ -1796,7 +1802,7 @@ Debugger::Formatting::GetSummaryFormat(ValueObject& vobj,
}
bool
Debugger::Formatting::GetSyntheticFilter(ValueObject& vobj,
lldb::SyntheticFilterSP& entry)
lldb::SyntheticChildrenSP& entry)
{
return GetFormatManager().Get(vobj, entry);
}

View file

@ -21,8 +21,10 @@
#include "lldb/Core/Debugger.h"
#include "lldb/Core/FormatClasses.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
using namespace lldb;
using namespace lldb_private;
@ -156,3 +158,25 @@ SyntheticFilter::GetDescription()
sstr.Printf("}");
return sstr.GetString();
}
SyntheticScriptProvider::FrontEnd::FrontEnd(std::string pclass,
lldb::ValueObjectSP be) :
SyntheticChildrenFrontEnd(be),
m_python_class(pclass)
{
m_interpreter = be->GetUpdatePoint().GetTarget()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
m_wrapper = (PyObject*)m_interpreter->CreateSyntheticScriptedProvider(m_python_class, m_backend);
}
std::string
SyntheticScriptProvider::GetDescription()
{
StreamString sstr;
sstr.Printf("%s%s%s Python class: %s",
m_cascades ? "" : " (not cascading)",
m_skip_pointers ? " (skip pointers)" : "",
m_skip_references ? " (skip references)" : "",
m_python_class.c_str());
return sstr.GetString();
}

View file

@ -219,6 +219,8 @@ ValueObject::UpdateFormatsIfNeeded()
m_last_value_format.reset(/*(ValueFormat*)NULL*/);
if (m_last_synthetic_filter.get())
m_last_synthetic_filter.reset(/*(SyntheticFilter*)NULL*/);
m_synthetic_value = NULL;
Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format);
Debugger::Formatting::GetSummaryFormat(*this, m_last_summary_format);
@ -1493,7 +1495,8 @@ ValueObject::CalculateSyntheticValue (lldb::SyntheticValueType use_synthetic)
if (m_last_synthetic_filter.get() == NULL)
return;
m_synthetic_value = new ValueObjectSyntheticFilter(*this, m_last_synthetic_filter);
if (m_synthetic_value == NULL)
m_synthetic_value = new ValueObjectSynthetic(*this, m_last_synthetic_filter);
}

View file

@ -35,23 +35,25 @@
using namespace lldb_private;
ValueObjectSyntheticFilter::ValueObjectSyntheticFilter (ValueObject &parent, lldb::SyntheticFilterSP filter) :
ValueObjectSynthetic::ValueObjectSynthetic (ValueObject &parent, lldb::SyntheticChildrenSP filter) :
ValueObject(parent),
m_address (),
m_type_sp(),
m_use_synthetic (lldb::eUseSyntheticFilter),
m_synth_filter(filter)
m_use_synthetic (lldb::eUseSyntheticFilter),
m_synth_filter(filter->GetFrontEnd(parent.GetSP())),
m_children_byindex(),
m_name_toindex()
{
SetName (parent.GetName().AsCString());
}
ValueObjectSyntheticFilter::~ValueObjectSyntheticFilter()
ValueObjectSynthetic::~ValueObjectSynthetic()
{
m_owning_valobj_sp.reset();
}
lldb::clang_type_t
ValueObjectSyntheticFilter::GetClangType ()
ValueObjectSynthetic::GetClangType ()
{
if (m_type_sp)
return m_value.GetClangType();
@ -60,7 +62,7 @@ ValueObjectSyntheticFilter::GetClangType ()
}
ConstString
ValueObjectSyntheticFilter::GetTypeName()
ValueObjectSynthetic::GetTypeName()
{
const bool success = UpdateValueIfNeeded();
if (success && m_type_sp)
@ -70,22 +72,13 @@ ValueObjectSyntheticFilter::GetTypeName()
}
uint32_t
ValueObjectSyntheticFilter::CalculateNumChildren()
ValueObjectSynthetic::CalculateNumChildren()
{
const bool success = UpdateValueIfNeeded();
if (!success)
return 0;
if (m_synth_filter.get())
return m_synth_filter->GetCount();
return 0;
if (success && m_type_sp)
return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true);
else
return m_parent->GetNumChildren();
return m_synth_filter->CalculateNumChildren();
}
clang::ASTContext *
ValueObjectSyntheticFilter::GetClangAST ()
ValueObjectSynthetic::GetClangAST ()
{
const bool success = UpdateValueIfNeeded(false);
if (success && m_type_sp)
@ -95,7 +88,7 @@ ValueObjectSyntheticFilter::GetClangAST ()
}
size_t
ValueObjectSyntheticFilter::GetByteSize()
ValueObjectSynthetic::GetByteSize()
{
const bool success = UpdateValueIfNeeded();
if (success && m_type_sp)
@ -105,13 +98,13 @@ ValueObjectSyntheticFilter::GetByteSize()
}
lldb::ValueType
ValueObjectSyntheticFilter::GetValueType() const
ValueObjectSynthetic::GetValueType() const
{
return m_parent->GetValueType();
}
bool
ValueObjectSyntheticFilter::UpdateValue ()
ValueObjectSynthetic::UpdateValue ()
{
SetValueIsValid (false);
m_error.Clear();
@ -124,46 +117,61 @@ ValueObjectSyntheticFilter::UpdateValue ()
return false;
}
m_children_byindex.clear();
m_name_toindex.clear();
SetValueIsValid(true);
return true;
}
lldb::ValueObjectSP
ValueObjectSyntheticFilter::GetChildAtIndex (uint32_t idx, bool can_create)
ValueObjectSynthetic::GetChildAtIndex (uint32_t idx, bool can_create)
{
if (!m_synth_filter.get())
return lldb::ValueObjectSP();
if (idx >= m_synth_filter->GetCount())
return lldb::ValueObjectSP();
return m_parent->GetSyntheticExpressionPathChild(m_synth_filter->GetExpressionPathAtIndex(idx).c_str(), can_create);
ByIndexIterator iter = m_children_byindex.find(idx);
if (iter == m_children_byindex.end())
{
if (can_create)
{
lldb::ValueObjectSP synth_guy = m_synth_filter->GetChildAtIndex (idx, can_create);
m_children_byindex[idx]= synth_guy;
return synth_guy;
}
else
return lldb::ValueObjectSP();
}
else
return iter->second;
}
lldb::ValueObjectSP
ValueObjectSyntheticFilter::GetChildMemberWithName (const ConstString &name, bool can_create)
ValueObjectSynthetic::GetChildMemberWithName (const ConstString &name, bool can_create)
{
if (!m_synth_filter.get())
uint32_t index = GetIndexOfChildWithName(name);
if (index == UINT32_MAX)
return lldb::ValueObjectSP();
uint32_t idx = GetIndexOfChildWithName(name);
if (idx >= m_synth_filter->GetCount())
return lldb::ValueObjectSP();
return m_parent->GetSyntheticExpressionPathChild(name.GetCString(), can_create);
return GetChildAtIndex(index, can_create);
}
uint32_t
ValueObjectSyntheticFilter::GetIndexOfChildWithName (const ConstString &name)
ValueObjectSynthetic::GetIndexOfChildWithName (const ConstString &name)
{
const char* name_cstr = name.GetCString();
for (int i = 0; i < m_synth_filter->GetCount(); i++)
NameToIndexIterator iter = m_name_toindex.find(name.GetCString());
if (iter == m_name_toindex.end())
{
const char* expr_cstr = m_synth_filter->GetExpressionPathAtIndex(i).c_str();
if (::strcmp(name_cstr, expr_cstr))
return i;
uint32_t index = m_synth_filter->GetIndexOfChildWithName (name);
m_name_toindex[name.GetCString()] = index;
return index;
}
return UINT32_MAX;
return iter->second;
}
bool
ValueObjectSyntheticFilter::IsInScope ()
ValueObjectSynthetic::IsInScope ()
{
return m_parent->IsInScope();
}

View file

@ -13,6 +13,9 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
#include "lldb/Core/Debugger.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@ -54,6 +57,8 @@ CommandObjectScript::ExecuteRawCommandString
result.SetStatus (eReturnStatusFailed);
}
Debugger::Formatting::ForceUpdate(); // script might change Python code we use for formatting.. make sure we keep up to date with it
if (command == NULL || command[0] == '\0') {
script_interpreter->ExecuteInterpreterLoop ();
result.SetStatus (eReturnStatusSuccessFinishNoResult);

View file

@ -93,11 +93,21 @@ ScriptInterpreter::LanguageToString (lldb::ScriptLanguage language)
void
ScriptInterpreter::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback)
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,
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue)
{
ScriptInterpreterPython::InitializeInterpreter (python_swig_init_callback,
python_swig_breakpoint_callback,
python_swig_typescript_callback);
python_swig_typescript_callback,
python_swig_synthetic_script,
python_swig_calc_children,
python_swig_get_child_index,
python_swig_get_index_child,
python_swig_cast_to_sbvalue);
}
void

View file

@ -35,7 +35,11 @@ using namespace lldb_private;
static ScriptInterpreter::SWIGInitCallback g_swig_init_callback = NULL;
static ScriptInterpreter::SWIGBreakpointCallbackFunction g_swig_breakpoint_callback = NULL;
static ScriptInterpreter::SWIGPythonTypeScriptCallbackFunction g_swig_typescript_callback = NULL;
static ScriptInterpreter::SWIGPythonCreateSyntheticProvider g_swig_synthetic_script = NULL;
static ScriptInterpreter::SWIGPythonCalculateNumChildren g_swig_calc_children = NULL;
static ScriptInterpreter::SWIGPythonGetChildAtIndex g_swig_get_child_index = NULL;
static ScriptInterpreter::SWIGPythonGetIndexOfChildWithName g_swig_get_index_child = NULL;
static ScriptInterpreter::SWIGPythonCastPyObjectToSBValue g_swig_cast_to_sbvalue = NULL;
static int
_check_and_flush (FILE *stream)
@ -1245,6 +1249,55 @@ ScriptInterpreterPython::GenerateTypeScriptFunction (StringList &user_input, Str
return true;
}
void*
ScriptInterpreterPython::CreateSyntheticScriptedProvider (std::string class_name,
lldb::ValueObjectSP valobj)
{
if (class_name.empty())
return NULL;
if (!valobj.get())
return NULL;
Target *target = valobj->GetUpdatePoint().GetTarget();
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;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
if (CurrentThreadHasPythonLock())
{
python_interpreter->EnterSession ();
ret_val = g_swig_synthetic_script (class_name,
python_interpreter->m_dictionary_name.c_str(),
valobj);
python_interpreter->LeaveSession ();
}
else
{
while (!GetPythonLock (1))
fprintf (tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
python_interpreter->EnterSession ();
ret_val = g_swig_synthetic_script (class_name,
python_interpreter->m_dictionary_name.c_str(),
valobj);
python_interpreter->LeaveSession ();
ReleasePythonLock ();
}
return ret_val;
}
bool
ScriptInterpreterPython::GenerateTypeScriptFunction (const char* oneliner, StringList &output)
{
@ -1565,15 +1618,161 @@ ScriptInterpreterPython::RunEmbeddedPythonInterpreter (lldb::thread_arg_t baton)
return NULL;
}
uint32_t
ScriptInterpreterPython::CalculateNumChildren (void *implementor)
{
if (!implementor)
return 0;
if (!g_swig_calc_children)
return 0;
ScriptInterpreterPython *python_interpreter = this;
uint32_t ret_val = 0;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
if (CurrentThreadHasPythonLock())
{
python_interpreter->EnterSession ();
ret_val = g_swig_calc_children (implementor);
python_interpreter->LeaveSession ();
}
else
{
while (!GetPythonLock (1))
fprintf (tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
python_interpreter->EnterSession ();
ret_val = g_swig_calc_children (implementor);
python_interpreter->LeaveSession ();
ReleasePythonLock ();
}
return ret_val;
}
void*
ScriptInterpreterPython::GetChildAtIndex (void *implementor, uint32_t idx)
{
if (!implementor)
return 0;
if (!g_swig_get_child_index)
return 0;
ScriptInterpreterPython *python_interpreter = this;
void* ret_val = NULL;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
if (CurrentThreadHasPythonLock())
{
python_interpreter->EnterSession ();
ret_val = g_swig_get_child_index (implementor,idx);
python_interpreter->LeaveSession ();
}
else
{
while (!GetPythonLock (1))
fprintf (tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
python_interpreter->EnterSession ();
ret_val = g_swig_get_child_index (implementor,idx);
python_interpreter->LeaveSession ();
ReleasePythonLock ();
}
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;
ScriptInterpreterPython *python_interpreter = this;
int ret_val = UINT32_MAX;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
if (CurrentThreadHasPythonLock())
{
python_interpreter->EnterSession ();
ret_val = g_swig_get_index_child (implementor, child_name);
python_interpreter->LeaveSession ();
}
else
{
while (!GetPythonLock (1))
fprintf (tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
python_interpreter->EnterSession ();
ret_val = g_swig_get_index_child (implementor, child_name);
python_interpreter->LeaveSession ();
ReleasePythonLock ();
}
return ret_val;
}
lldb::SBValue*
ScriptInterpreterPython::CastPyObjectToSBValue (void* data)
{
if (!data)
return NULL;
if (!g_swig_cast_to_sbvalue)
return NULL;
ScriptInterpreterPython *python_interpreter = this;
lldb::SBValue* ret_val = NULL;
FILE *tmp_fh = (python_interpreter->m_dbg_stdout ? python_interpreter->m_dbg_stdout : stdout);
if (CurrentThreadHasPythonLock())
{
python_interpreter->EnterSession ();
ret_val = g_swig_cast_to_sbvalue (data);
python_interpreter->LeaveSession ();
}
else
{
while (!GetPythonLock (1))
fprintf (tmp_fh,
"Python interpreter locked on another thread; waiting to acquire lock...\n");
python_interpreter->EnterSession ();
ret_val = g_swig_cast_to_sbvalue (data);
python_interpreter->LeaveSession ();
ReleasePythonLock ();
}
return ret_val;
}
void
ScriptInterpreterPython::InitializeInterpreter (SWIGInitCallback python_swig_init_callback,
SWIGBreakpointCallbackFunction python_swig_breakpoint_callback,
SWIGPythonTypeScriptCallbackFunction python_swig_typescript_callback)
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,
SWIGPythonCastPyObjectToSBValue python_swig_cast_to_sbvalue)
{
g_swig_init_callback = python_swig_init_callback;
g_swig_breakpoint_callback = python_swig_breakpoint_callback;
g_swig_typescript_callback = python_swig_typescript_callback;
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;
}
void

View file

@ -0,0 +1,5 @@
LEVEL = ../../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View file

@ -0,0 +1,95 @@
"""
Test lldb data formatter subsystem.
"""
import os, time
import unittest2
import lldb
from lldbtest import *
class DataFormatterTestCase(TestBase):
mydir = os.path.join("functionalities", "data-formatter", "data-formatter-python-synth")
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
def test_with_dsym_and_run_command(self):
"""Test data formatter commands."""
self.buildDsym()
self.data_formatter_commands()
def test_with_dwarf_and_run_command(self):
"""Test data formatter commands."""
self.buildDwarf()
self.data_formatter_commands()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break at.
self.line = line_number('main.cpp', '// Set break point at this line.')
def data_formatter_commands(self):
"""Test that that file and class static variables display correctly."""
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
self.expect("breakpoint set -f main.cpp -l %d" % self.line,
BREAKPOINT_CREATED,
startstr = "Breakpoint created: 1: file ='main.cpp', line = %d, locations = 1" %
self.line)
self.runCmd("run", RUN_SUCCEEDED)
# The stop reason of the thread should be breakpoint.
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
substrs = ['stopped',
'stop reason = breakpoint'])
# This is the function to remove the custom formats in order to have a
# clean slate for the next test case.
def cleanup():
self.runCmd('type format clear', check=False)
self.runCmd('type summary clear', check=False)
self.runCmd('type synth clear', check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
# print the f00_1 variable without a synth
self.expect("frame variable f00_1",
substrs = ['a = 0',
'b = 1',
'r = 33']);
# now set up the synth
self.runCmd("script from fooSynthProvider import *")
self.runCmd("type synth add -l fooSynthProvider foo")
# check that we get only the two variables
self.expect("frame variable f00_1",
substrs = ['r = 33',
'a = 0']);
# check that we do not get the extra vars and that we cache results
self.expect("frame variable f00_1", matching=False,
substrs = ['looking for',
'b = 1']);
# check that the caching does not span beyond the stopoint
self.runCmd("n")
self.expect("frame variable f00_1",
substrs = ['r = 33',
'a = 1']);
# delete the synth and check that we get good output
self.runCmd("type synth delete foo")
self.expect("frame variable f00_1",
substrs = ['a = 1',
'b = 1',
'r = 33']);
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View file

@ -0,0 +1,16 @@
class fooSynthProvider:
def __init__(self, valobj, dict):
self.valobj = valobj;
def num_children(self):
return 2;
def get_child_at_index(self, index):
if index == 1:
child = self.valobj.GetChildMemberWithName('a');
else:
child = self.valobj.GetChildMemberWithName('r');
return child;
def get_child_index(self, name):
if name == 'a':
return 1;
else:
return 0;

View file

@ -0,0 +1,53 @@
struct foo
{
int a;
int b;
int c;
int d;
int e;
int f;
int g;
int h;
int i;
int j;
int k;
int l;
int m;
int n;
int o;
int p;
int q;
int r;
foo(int X) :
a(X),
b(X+1),
c(X+3),
d(X+5),
e(X+7),
f(X+9),
g(X+11),
h(X+13),
i(X+15),
j(X+17),
k(X+19),
l(X+21),
m(X+23),
n(X+25),
o(X+27),
p(X+29),
q(X+31),
r(X+33) {}
};
int main()
{
foo f00_1(0);
foo f00_2(6);
foo *f00_3 = new foo(12);
foo& f00_4 = *(new foo(18));
f00_1.a++; // Set break point at this line.
return 0;
}