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:
parent
fb66d5cc9c
commit
a37a065c33
26 changed files with 1319 additions and 136 deletions
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
78
lldb/include/lldb/Utility/PythonPointer.h
Normal file
78
lldb/include/lldb/Utility/PythonPointer.h
Normal 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_
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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>";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
%}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
||||
|
|
@ -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()
|
||||
|
|
@ -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;
|
||||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Reference in a new issue