forked from OSchip/llvm-project
when typing a summary string you can use the %S symbol to explicitly indicate that you want the summary to be used to print the target object
(e.g. ${var%S}). this might already be the default if your variable is of an aggregate type new feature: synthetic filters. you can restrict the number of children for your variables to only a meaningful subset - the restricted list of children obeys the typical rules (e.g. summaries prevail over children) - one-line summaries show only the filtered (synthetic) children, if you type an expanded summary string, or you use Python scripts, all the real children are accessible - to provide a synthetic children list use the "type synth add" command, as in: type synth add foo_type --child varA --child varB[0] --child varC->packet->flags[1-4] (you can use ., ->, single-item array operator [N] and bitfield operator [N-M]; array slice access is not supported, giving simplified names to expression paths is not supported) - a new -S option to frame variable and target variable lets you override synthetic children and instead show real ones llvm-svn: 135731
This commit is contained in:
parent
1872173841
commit
d55546b27a
|
@ -505,6 +505,9 @@ public:
|
|||
static bool
|
||||
GetSummaryFormat(ValueObject& vobj,
|
||||
lldb::SummaryFormatSP& entry);
|
||||
static bool
|
||||
GetSyntheticFilter(ValueObject& vobj,
|
||||
lldb::SyntheticFilterSP& entry);
|
||||
|
||||
class NamedSummaryFormats
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
|
||||
// C++ Includes
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// Other libraries and framework includes
|
||||
|
||||
|
@ -55,23 +56,23 @@ struct ValueFormat
|
|||
}
|
||||
|
||||
bool
|
||||
Cascades()
|
||||
Cascades() const
|
||||
{
|
||||
return m_cascades;
|
||||
}
|
||||
bool
|
||||
SkipsPointers()
|
||||
SkipsPointers() const
|
||||
{
|
||||
return m_skip_pointers;
|
||||
}
|
||||
bool
|
||||
SkipsReferences()
|
||||
SkipsReferences() const
|
||||
{
|
||||
return m_skip_references;
|
||||
}
|
||||
|
||||
lldb::Format
|
||||
GetFormat()
|
||||
GetFormat() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
@ -80,6 +81,57 @@ struct ValueFormat
|
|||
FormatObject(lldb::ValueObjectSP object);
|
||||
|
||||
};
|
||||
|
||||
struct SyntheticFilter
|
||||
{
|
||||
bool m_cascades;
|
||||
bool m_skip_pointers;
|
||||
bool m_skip_references;
|
||||
std::vector<std::string> m_expression_paths;
|
||||
|
||||
SyntheticFilter(bool casc = false,
|
||||
bool skipptr = false,
|
||||
bool skipref = false) :
|
||||
m_cascades(casc),
|
||||
m_skip_pointers(skipptr),
|
||||
m_skip_references(skipref),
|
||||
m_expression_paths()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
AddExpressionPath(std::string path)
|
||||
{
|
||||
bool need_add_dot = true;
|
||||
if (path[0] == '.' ||
|
||||
(path[0] == '-' && path[1] == '>') ||
|
||||
path[0] == '[')
|
||||
need_add_dot = false;
|
||||
// add a '.' symbol to help forgetful users
|
||||
if(!need_add_dot)
|
||||
m_expression_paths.push_back(path);
|
||||
else
|
||||
m_expression_paths.push_back(std::string(".") + path);
|
||||
}
|
||||
|
||||
int
|
||||
GetCount() const
|
||||
{
|
||||
return m_expression_paths.size();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
GetExpressionPathAtIndex(int i) const
|
||||
{
|
||||
return m_expression_paths[i];
|
||||
}
|
||||
|
||||
std::string
|
||||
GetDescription();
|
||||
|
||||
typedef lldb::SharedPtr<SyntheticFilter>::Type SharedPointer;
|
||||
typedef bool(*SyntheticFilterCallback)(void*, const char*, const SyntheticFilter::SharedPointer&);
|
||||
};
|
||||
|
||||
struct SummaryFormat
|
||||
{
|
||||
|
@ -106,17 +158,17 @@ struct SummaryFormat
|
|||
}
|
||||
|
||||
bool
|
||||
Cascades()
|
||||
Cascades() const
|
||||
{
|
||||
return m_cascades;
|
||||
}
|
||||
bool
|
||||
SkipsPointers()
|
||||
SkipsPointers() const
|
||||
{
|
||||
return m_skip_pointers;
|
||||
}
|
||||
bool
|
||||
SkipsReferences()
|
||||
SkipsReferences() const
|
||||
{
|
||||
return m_skip_references;
|
||||
}
|
||||
|
@ -174,7 +226,7 @@ struct StringSummaryFormat : public SummaryFormat
|
|||
}
|
||||
|
||||
std::string
|
||||
GetFormat()
|
||||
GetFormat() const
|
||||
{
|
||||
return m_format;
|
||||
}
|
||||
|
@ -213,13 +265,13 @@ struct ScriptSummaryFormat : public SummaryFormat
|
|||
}
|
||||
|
||||
std::string
|
||||
GetFunctionName()
|
||||
GetFunctionName() const
|
||||
{
|
||||
return m_function_name;
|
||||
}
|
||||
|
||||
std::string
|
||||
GetPythonScript()
|
||||
GetPythonScript() const
|
||||
{
|
||||
return m_python_script;
|
||||
}
|
||||
|
|
|
@ -415,12 +415,15 @@ class FormatCategory
|
|||
private:
|
||||
typedef FormatNavigator<const char*, SummaryFormat> SummaryNavigator;
|
||||
typedef FormatNavigator<lldb::RegularExpressionSP, SummaryFormat> RegexSummaryNavigator;
|
||||
typedef FormatNavigator<const char*, SyntheticFilter> FilterNavigator;
|
||||
|
||||
typedef SummaryNavigator::MapType SummaryMap;
|
||||
typedef RegexSummaryNavigator::MapType RegexSummaryMap;
|
||||
typedef FilterNavigator::MapType FilterMap;
|
||||
|
||||
SummaryNavigator::SharedPointer m_summary_nav;
|
||||
RegexSummaryNavigator::SharedPointer m_regex_summary_nav;
|
||||
FilterNavigator::SharedPointer m_filter_nav;
|
||||
|
||||
bool m_enabled;
|
||||
|
||||
|
@ -428,6 +431,8 @@ private:
|
|||
|
||||
Mutex m_mutex;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
void
|
||||
Enable(bool value = true)
|
||||
{
|
||||
|
@ -449,13 +454,17 @@ public:
|
|||
|
||||
typedef SummaryNavigator::SharedPointer SummaryNavigatorSP;
|
||||
typedef RegexSummaryNavigator::SharedPointer RegexSummaryNavigatorSP;
|
||||
typedef FilterNavigator::SharedPointer FilterNavigatorSP;
|
||||
|
||||
FormatCategory(IFormatChangeListener* clist) :
|
||||
FormatCategory(IFormatChangeListener* clist,
|
||||
std::string name) :
|
||||
m_summary_nav(new SummaryNavigator(clist)),
|
||||
m_regex_summary_nav(new RegexSummaryNavigator(clist)),
|
||||
m_filter_nav(new FilterNavigator(clist)),
|
||||
m_enabled(false),
|
||||
m_change_listener(clist),
|
||||
m_mutex(Mutex::eMutexTypeRecursive)
|
||||
m_mutex(Mutex::eMutexTypeRecursive),
|
||||
m_name(name)
|
||||
{}
|
||||
|
||||
SummaryNavigatorSP
|
||||
|
@ -470,6 +479,12 @@ public:
|
|||
return RegexSummaryNavigatorSP(m_regex_summary_nav);
|
||||
}
|
||||
|
||||
FilterNavigatorSP
|
||||
Filter()
|
||||
{
|
||||
return FilterNavigatorSP(m_filter_nav);
|
||||
}
|
||||
|
||||
bool
|
||||
IsEnabled() const
|
||||
{
|
||||
|
@ -491,15 +506,27 @@ public:
|
|||
return regex;
|
||||
}
|
||||
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SyntheticFilterSP& entry,
|
||||
uint32_t* reason = NULL)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return false;
|
||||
return (Filter()->Get(vobj, entry, reason));
|
||||
}
|
||||
|
||||
// just a shortcut for Summary()->Clear; RegexSummary()->Clear()
|
||||
void
|
||||
Clear()
|
||||
ClearSummaries()
|
||||
{
|
||||
m_summary_nav->Clear();
|
||||
m_regex_summary_nav->Clear();
|
||||
}
|
||||
|
||||
// just a shortcut for (Summary()->Delete(name) || RegexSummary()->Delete(name))
|
||||
bool
|
||||
Delete(const char* name)
|
||||
DeleteSummaries(const char* name)
|
||||
{
|
||||
bool del_sum = m_summary_nav->Delete(name);
|
||||
bool del_rex = m_regex_summary_nav->Delete(name);
|
||||
|
@ -513,6 +540,12 @@ public:
|
|||
return Summary()->GetCount() + RegexSummary()->GetCount();
|
||||
}
|
||||
|
||||
std::string
|
||||
GetName()
|
||||
{
|
||||
return m_name;
|
||||
}
|
||||
|
||||
typedef lldb::SharedPtr<FormatCategory>::Type SharedPointer;
|
||||
};
|
||||
|
||||
|
@ -648,23 +681,6 @@ public:
|
|||
return true;
|
||||
}
|
||||
|
||||
class match_category_to_name
|
||||
{
|
||||
private:
|
||||
FormatCategory* addr;
|
||||
public:
|
||||
|
||||
match_category_to_name(FormatCategory* ptr) : addr(ptr)
|
||||
{}
|
||||
|
||||
bool operator()(std::pair<const char*,FormatCategory::SharedPointer> map_entry)
|
||||
{
|
||||
if (addr == map_entry.second.get())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
LoopThrough(CallbackType callback, void* param)
|
||||
{
|
||||
|
@ -678,13 +694,7 @@ public:
|
|||
for (begin = m_active_categories.begin(); begin != end; begin++)
|
||||
{
|
||||
FormatCategory::SharedPointer category = *begin;
|
||||
const char* type;
|
||||
MapIterator type_position =
|
||||
std::find_if(m_map.begin(),m_map.end(),match_category_to_name(category.get()));
|
||||
if (type_position != m_map.end())
|
||||
type = type_position->first;
|
||||
else
|
||||
continue;
|
||||
const char* type = category->GetName().c_str();
|
||||
if (!callback(param, type, category))
|
||||
break;
|
||||
}
|
||||
|
@ -741,6 +751,38 @@ public:
|
|||
}
|
||||
return !first;
|
||||
}
|
||||
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SyntheticFilterSP& entry)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
|
||||
uint32_t reason_why;
|
||||
bool first = true;
|
||||
|
||||
ActiveCategoriesIterator begin, end = m_active_categories.end();
|
||||
|
||||
for (begin = m_active_categories.begin(); begin != end; begin++)
|
||||
{
|
||||
FormatCategory::SharedPointer category = *begin;
|
||||
lldb::SyntheticFilterSP current_format;
|
||||
if (!category->Get(vobj, current_format, &reason_why))
|
||||
continue;
|
||||
if (reason_why == lldb::eFormatterDirectChoice)
|
||||
{
|
||||
entry = current_format;
|
||||
return true;
|
||||
}
|
||||
else if (first)
|
||||
{
|
||||
entry = current_format;
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
return !first;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -856,7 +898,7 @@ public:
|
|||
lldb::FormatCategorySP category;
|
||||
if (m_categories_map.Get(category_name, category))
|
||||
return category;
|
||||
Categories().Add(category_name,lldb::FormatCategorySP(new FormatCategory(this)));
|
||||
Categories().Add(category_name,lldb::FormatCategorySP(new FormatCategory(this, category_name)));
|
||||
return Category(category_name);
|
||||
}
|
||||
|
||||
|
@ -866,6 +908,12 @@ public:
|
|||
{
|
||||
return m_categories_map.Get(vobj, entry);
|
||||
}
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SyntheticFilterSP& entry)
|
||||
{
|
||||
return m_categories_map.Get(vobj, entry);
|
||||
}
|
||||
|
||||
static bool
|
||||
GetFormatFromCString (const char *format_cstr,
|
||||
|
|
|
@ -466,7 +466,7 @@ public:
|
|||
const ConstString &
|
||||
GetName() const;
|
||||
|
||||
lldb::ValueObjectSP
|
||||
virtual lldb::ValueObjectSP
|
||||
GetChildAtIndex (uint32_t idx, bool can_create);
|
||||
|
||||
virtual lldb::ValueObjectSP
|
||||
|
@ -545,9 +545,15 @@ public:
|
|||
lldb::ValueObjectSP
|
||||
GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetSyntheticExpressionPathChild(const char* expression, bool can_create);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetDynamicValue (lldb::DynamicValueType valueType);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetSyntheticValue (lldb::SyntheticValueType use_synthetic);
|
||||
|
||||
virtual lldb::ValueObjectSP
|
||||
CreateConstantValue (const ConstString &name);
|
||||
|
||||
|
@ -592,6 +598,7 @@ public:
|
|||
bool show_location,
|
||||
bool use_objc,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
bool use_synthetic,
|
||||
bool scope_already_checked,
|
||||
bool flat_output,
|
||||
uint32_t omit_summary_depth);
|
||||
|
@ -727,6 +734,7 @@ protected:
|
|||
std::vector<ValueObject *> m_children;
|
||||
std::map<ConstString, ValueObject *> m_synthetic_children;
|
||||
ValueObject *m_dynamic_value;
|
||||
ValueObject *m_synthetic_value;
|
||||
lldb::ValueObjectSP m_addr_of_valobj_sp; // We have to hold onto a shared pointer to this one because it is created
|
||||
// as an independent ValueObjectConstResult, which isn't managed by us.
|
||||
ValueObject *m_deref_valobj;
|
||||
|
@ -736,6 +744,7 @@ protected:
|
|||
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;
|
||||
bool m_value_is_valid:1,
|
||||
m_value_did_change:1,
|
||||
|
@ -744,7 +753,8 @@ protected:
|
|||
m_pointers_point_to_load_addrs:1,
|
||||
m_is_deref_of_parent:1,
|
||||
m_is_array_item_for_pointer:1,
|
||||
m_is_bitfield_for_scalar:1;
|
||||
m_is_bitfield_for_scalar:1,
|
||||
m_is_expression_path_child:1;
|
||||
|
||||
// used to prevent endless looping into GetpPrintableRepresentation()
|
||||
uint32_t m_dump_printable_counter;
|
||||
|
@ -782,6 +792,9 @@ protected:
|
|||
virtual void
|
||||
CalculateDynamicValue (lldb::DynamicValueType use_dynamic);
|
||||
|
||||
virtual void
|
||||
CalculateSyntheticValue (lldb::SyntheticValueType use_synthetic);
|
||||
|
||||
// Should only be called by ValueObject::GetChildAtIndex()
|
||||
// Returns a ValueObject managed by this ValueObject's manager.
|
||||
virtual ValueObject *
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
//===-- ValueObjectSyntheticFilter.h -------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef liblldb_ValueObjectSyntheticFilter_h_
|
||||
#define liblldb_ValueObjectSyntheticFilter_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// A ValueObject that represents memory at a given address, viewed as some
|
||||
// set lldb type.
|
||||
//----------------------------------------------------------------------
|
||||
class ValueObjectSyntheticFilter : public ValueObject
|
||||
{
|
||||
public:
|
||||
virtual
|
||||
~ValueObjectSyntheticFilter();
|
||||
|
||||
virtual size_t
|
||||
GetByteSize();
|
||||
|
||||
virtual clang::ASTContext *
|
||||
GetClangAST ();
|
||||
|
||||
virtual lldb::clang_type_t
|
||||
GetClangType ();
|
||||
|
||||
virtual ConstString
|
||||
GetTypeName();
|
||||
|
||||
virtual uint32_t
|
||||
CalculateNumChildren();
|
||||
|
||||
virtual lldb::ValueType
|
||||
GetValueType() const;
|
||||
|
||||
virtual lldb::ValueObjectSP
|
||||
GetChildAtIndex (uint32_t idx, bool can_create);
|
||||
|
||||
virtual lldb::ValueObjectSP
|
||||
GetChildMemberWithName (const ConstString &name, bool can_create);
|
||||
|
||||
virtual uint32_t
|
||||
GetIndexOfChildWithName (const ConstString &name);
|
||||
|
||||
virtual bool
|
||||
IsInScope ();
|
||||
|
||||
virtual bool
|
||||
IsDynamic ()
|
||||
{
|
||||
if (m_parent)
|
||||
return m_parent->IsDynamic();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ValueObject *
|
||||
GetParent()
|
||||
{
|
||||
if (m_parent)
|
||||
return m_parent->GetParent();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
virtual const ValueObject *
|
||||
GetParent() const
|
||||
{
|
||||
if (m_parent)
|
||||
return m_parent->GetParent();
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
SetOwningSP (lldb::ValueObjectSP &owning_sp)
|
||||
{
|
||||
if (m_owning_valobj_sp == owning_sp)
|
||||
return;
|
||||
|
||||
assert (m_owning_valobj_sp.get() == NULL);
|
||||
m_owning_valobj_sp = owning_sp;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool
|
||||
UpdateValue ();
|
||||
|
||||
Address m_address; ///< The variable that this value object is based upon
|
||||
lldb::TypeSP m_type_sp;
|
||||
lldb::ValueObjectSP m_owning_valobj_sp;
|
||||
lldb::SyntheticValueType m_use_synthetic;
|
||||
lldb::SyntheticFilterSP m_synth_filter;
|
||||
|
||||
private:
|
||||
friend class ValueObject;
|
||||
ValueObjectSyntheticFilter (ValueObject &parent, lldb::SyntheticFilterSP filter);
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// For ValueObject only
|
||||
//------------------------------------------------------------------
|
||||
DISALLOW_COPY_AND_ASSIGN (ValueObjectSyntheticFilter);
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // liblldb_ValueObjectSyntheticFilter_h_
|
|
@ -54,6 +54,7 @@ public:
|
|||
uint32_t max_depth;
|
||||
uint32_t ptr_depth;
|
||||
lldb::DynamicValueType use_dynamic;
|
||||
bool use_synth;
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -324,6 +324,12 @@ namespace lldb {
|
|||
eDynamicDontRunTarget = 2
|
||||
} DynamicValueType;
|
||||
|
||||
typedef enum SyntheticValueType
|
||||
{
|
||||
eNoSyntheticFilter = 0,
|
||||
eUseSyntheticFilter = 1
|
||||
} SyntheticValueType;
|
||||
|
||||
typedef enum AccessType
|
||||
{
|
||||
eAccessNone,
|
||||
|
|
|
@ -67,6 +67,7 @@ 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::Target>::Type TargetSP;
|
||||
typedef SharedPtr<lldb_private::Thread>::Type ThreadSP;
|
||||
typedef SharedPtr<lldb_private::ThreadPlan>::Type ThreadPlanSP;
|
||||
|
|
|
@ -144,6 +144,7 @@ class SymbolContextSpecifier;
|
|||
class SymbolFile;
|
||||
class SymbolVendor;
|
||||
class Symtab;
|
||||
class SyntheticFilter;
|
||||
class Target;
|
||||
class TargetList;
|
||||
class Thread;
|
||||
|
|
|
@ -419,6 +419,7 @@
|
|||
94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.cpp */; };
|
||||
9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */; };
|
||||
9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */; };
|
||||
94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */; };
|
||||
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
|
||||
9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A22A15D135E30370024DDC3 /* EmulateInstructionARM.cpp */; };
|
||||
|
@ -1218,6 +1219,8 @@
|
|||
9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = "<group>"; };
|
||||
94A9112B13D5DEF80046D8A6 /* FormatClasses.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatClasses.h; path = include/lldb/Core/FormatClasses.h; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
|
@ -2079,6 +2082,8 @@
|
|||
4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */,
|
||||
2643343A1110F63C00CDB6C6 /* ValueObjectRegister.h */,
|
||||
264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */,
|
||||
94B6E76013D8833C005F417F /* ValueObjectSyntheticFilter.h */,
|
||||
94B6E76113D88362005F417F /* ValueObjectSyntheticFilter.cpp */,
|
||||
26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */,
|
||||
26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */,
|
||||
26BC7D8610F1B77400F91463 /* VMRange.h */,
|
||||
|
@ -3361,6 +3366,7 @@
|
|||
2676045A13D49D2300AB1B6A /* ProcessControl-mig.defs in Sources */,
|
||||
26D7E45D13D5E30A007FD12B /* SocketAddress.cpp in Sources */,
|
||||
B271B11413D6139300C3FEDB /* FormatClasses.cpp in Sources */,
|
||||
94B6E76213D88365005F417F /* ValueObjectSyntheticFilter.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -648,6 +648,8 @@ SBValue::GetDescription (SBStream &description)
|
|||
lldb::DynamicValueType use_dynamic = eNoDynamicValues;
|
||||
bool scope_already_checked = false;
|
||||
bool flat_output = false;
|
||||
bool use_synthetic = true;
|
||||
uint32_t no_summary_depth = 0;
|
||||
ValueObject::DumpValueObject (description.ref(),
|
||||
m_opaque_sp.get(),
|
||||
m_opaque_sp->GetName().GetCString(),
|
||||
|
@ -656,10 +658,11 @@ SBValue::GetDescription (SBStream &description)
|
|||
max_depth,
|
||||
show_types, show_location,
|
||||
use_objc,
|
||||
use_dynamic,
|
||||
use_dynamic,
|
||||
use_synthetic,
|
||||
scope_already_checked,
|
||||
flat_output,
|
||||
0);
|
||||
no_summary_depth);
|
||||
}
|
||||
else
|
||||
description.Printf ("No value");
|
||||
|
|
|
@ -334,6 +334,7 @@ CommandObjectExpression::EvaluateExpression
|
|||
false, // Show locations of variables, no since this is a host address which we don't care to see
|
||||
m_options.print_object, // Print the objective C object?
|
||||
use_dynamic,
|
||||
true, // Use synthetic children if available
|
||||
true, // Scope is already checked. Const results are always in scope.
|
||||
false, // Don't flatten output
|
||||
0); // Always use summaries (you might want an option --no-summary like there is for frame variable)
|
||||
|
|
|
@ -499,7 +499,8 @@ public:
|
|||
m_varobj_options.show_types,
|
||||
m_varobj_options.show_location,
|
||||
m_varobj_options.use_objc,
|
||||
m_varobj_options.use_dynamic,
|
||||
m_varobj_options.use_dynamic,
|
||||
m_varobj_options.use_synth,
|
||||
false,
|
||||
m_varobj_options.flat_output,
|
||||
m_varobj_options.no_summary_depth);
|
||||
|
@ -552,6 +553,7 @@ public:
|
|||
m_varobj_options.show_location,
|
||||
m_varobj_options.use_objc,
|
||||
m_varobj_options.use_dynamic,
|
||||
m_varobj_options.use_synth,
|
||||
false,
|
||||
m_varobj_options.flat_output,
|
||||
m_varobj_options.no_summary_depth);
|
||||
|
@ -643,6 +645,7 @@ public:
|
|||
m_varobj_options.show_location,
|
||||
m_varobj_options.use_objc,
|
||||
m_varobj_options.use_dynamic,
|
||||
m_varobj_options.use_synth,
|
||||
false,
|
||||
m_varobj_options.flat_output,
|
||||
m_varobj_options.no_summary_depth);
|
||||
|
|
|
@ -657,6 +657,7 @@ public:
|
|||
m_varobj_options.show_location,
|
||||
m_varobj_options.use_objc,
|
||||
m_varobj_options.use_dynamic,
|
||||
m_varobj_options.use_synth,
|
||||
scope_already_checked,
|
||||
m_varobj_options.flat_output,
|
||||
0);
|
||||
|
|
|
@ -488,6 +488,7 @@ public:
|
|||
m_varobj_options.show_location,
|
||||
m_varobj_options.use_objc,
|
||||
m_varobj_options.use_dynamic,
|
||||
m_varobj_options.use_synth,
|
||||
false,
|
||||
m_varobj_options.flat_output,
|
||||
m_varobj_options.no_summary_depth);
|
||||
|
|
|
@ -1226,7 +1226,7 @@ public:
|
|||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
bool delete_category = category->Delete(typeCS.GetCString());
|
||||
bool delete_category = category->DeleteSummaries(typeCS.GetCString());
|
||||
bool delete_named = Debugger::Formatting::NamedSummaryFormats::Delete(typeCS);
|
||||
|
||||
if (delete_category || delete_named)
|
||||
|
@ -1359,7 +1359,7 @@ public:
|
|||
}
|
||||
else
|
||||
Debugger::Formatting::Categories::Get(ConstString(NULL), category);
|
||||
category->Clear();
|
||||
category->ClearSummaries();
|
||||
}
|
||||
|
||||
Debugger::Formatting::NamedSummaryFormats::Clear();
|
||||
|
@ -1885,6 +1885,670 @@ public:
|
|||
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectTypeSynthList
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, const char* type, const SyntheticFilter::SharedPointer& entry);
|
||||
|
||||
class CommandObjectTypeSynthList;
|
||||
|
||||
struct CommandObjectTypeSynthList_LoopCallbackParam {
|
||||
CommandObjectTypeSynthList* self;
|
||||
CommandReturnObject* result;
|
||||
RegularExpression* regex;
|
||||
RegularExpression* cate_regex;
|
||||
CommandObjectTypeSynthList_LoopCallbackParam(CommandObjectTypeSynthList* S, CommandReturnObject* R,
|
||||
RegularExpression* X = NULL,
|
||||
RegularExpression* CX = NULL) : self(S), result(R), regex(X), cate_regex(CX) {}
|
||||
};
|
||||
|
||||
class CommandObjectTypeSynthList : public CommandObject
|
||||
{
|
||||
|
||||
class CommandOptions : public Options
|
||||
{
|
||||
public:
|
||||
|
||||
CommandOptions (CommandInterpreter &interpreter) :
|
||||
Options (interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandOptions (){}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (uint32_t option_idx, const char *option_arg)
|
||||
{
|
||||
Error error;
|
||||
char short_option = (char) m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'w':
|
||||
m_category_regex = std::string(option_arg);
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParsingStarting ()
|
||||
{
|
||||
m_category_regex = "";
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_option_table;
|
||||
}
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
std::string m_category_regex;
|
||||
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
||||
virtual Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_options;
|
||||
}
|
||||
|
||||
public:
|
||||
CommandObjectTypeSynthList (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
"type synth list",
|
||||
"Show a list of current synthetic providers.",
|
||||
NULL), m_options(interpreter)
|
||||
{
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatOptional;
|
||||
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
}
|
||||
|
||||
~CommandObjectTypeSynthList ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Execute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
CommandObjectTypeSynthList_LoopCallbackParam *param;
|
||||
RegularExpression* cate_regex =
|
||||
m_options.m_category_regex.empty() ? NULL :
|
||||
new RegularExpression(m_options.m_category_regex.c_str());
|
||||
|
||||
if (argc == 1) {
|
||||
RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
|
||||
regex->Compile(command.GetArgumentAtIndex(0));
|
||||
param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,regex,cate_regex);
|
||||
}
|
||||
else
|
||||
param = new CommandObjectTypeSynthList_LoopCallbackParam(this,&result,NULL,cate_regex);
|
||||
|
||||
Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback,param);
|
||||
|
||||
if (cate_regex)
|
||||
delete cate_regex;
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
static bool
|
||||
PerCategoryCallback(void* param_vp,
|
||||
const char* cate_name,
|
||||
const FormatCategory::SharedPointer& cate)
|
||||
{
|
||||
|
||||
CommandObjectTypeSynthList_LoopCallbackParam* param =
|
||||
(CommandObjectTypeSynthList_LoopCallbackParam*)param_vp;
|
||||
CommandReturnObject* result = param->result;
|
||||
|
||||
// if the category is disabled or empty and there is no regex, just skip it
|
||||
if ((cate->IsEnabled() == false || cate->Filter()->GetCount() == 0) && param->cate_regex == NULL)
|
||||
return true;
|
||||
|
||||
// if we have a regex and this category does not match it, just skip it
|
||||
if(param->cate_regex != NULL && param->cate_regex->Execute(cate_name) == false)
|
||||
return true;
|
||||
|
||||
result->GetOutputStream().Printf("-----------------------\nCategory: %s (%s)\n-----------------------\n",
|
||||
cate_name,
|
||||
(cate->IsEnabled() ? "enabled" : "disabled"));
|
||||
|
||||
cate->Filter()->LoopThrough(CommandObjectTypeSynthList_LoopCallback, param_vp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
LoopCallback (const char* type,
|
||||
const SyntheticFilter::SharedPointer& entry,
|
||||
RegularExpression* regex,
|
||||
CommandReturnObject *result)
|
||||
{
|
||||
if (regex == NULL || regex->Execute(type))
|
||||
result->GetOutputStream().Printf ("%s: %s\n", type, entry->GetDescription().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool CommandObjectTypeSynthList_LoopCallback(void* pt2self, const char* type, const SyntheticFilter::SharedPointer& entry);
|
||||
};
|
||||
|
||||
bool
|
||||
CommandObjectTypeSynthList_LoopCallback (void* pt2self,
|
||||
const char* type,
|
||||
const SyntheticFilter::SharedPointer& entry)
|
||||
{
|
||||
CommandObjectTypeSynthList_LoopCallbackParam* param = (CommandObjectTypeSynthList_LoopCallbackParam*)pt2self;
|
||||
return param->self->LoopCallback(type, entry, param->regex, param->result);
|
||||
}
|
||||
|
||||
|
||||
OptionDefinition
|
||||
CommandObjectTypeSynthList::CommandOptions::g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_ALL, false, "category-regex", 'w', required_argument, NULL, 0, eArgTypeName, "Only show categories matching this filter."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectTypeSynthDelete
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class CommandObjectTypeSynthDelete : public CommandObject
|
||||
{
|
||||
private:
|
||||
class CommandOptions : public Options
|
||||
{
|
||||
public:
|
||||
|
||||
CommandOptions (CommandInterpreter &interpreter) :
|
||||
Options (interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandOptions (){}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (uint32_t option_idx, const char *option_arg)
|
||||
{
|
||||
Error error;
|
||||
char short_option = (char) m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'a':
|
||||
m_delete_all = true;
|
||||
break;
|
||||
case 'w':
|
||||
m_category = ConstString(option_arg).GetCString();
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParsingStarting ()
|
||||
{
|
||||
m_delete_all = false;
|
||||
m_category = NULL;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_option_table;
|
||||
}
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
bool m_delete_all;
|
||||
const char* m_category;
|
||||
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
||||
virtual Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_options;
|
||||
}
|
||||
|
||||
static bool
|
||||
PerCategoryCallback(void* param,
|
||||
const char* cate_name,
|
||||
const FormatCategory::SharedPointer& cate)
|
||||
{
|
||||
const char* name = (const char*)param;
|
||||
cate->Filter()->Delete(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
public:
|
||||
CommandObjectTypeSynthDelete (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
"type synth delete",
|
||||
"Delete an existing synthetic provider for a type.",
|
||||
NULL), m_options(interpreter)
|
||||
{
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatPlain;
|
||||
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
}
|
||||
|
||||
~CommandObjectTypeSynthDelete ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Execute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
if (argc != 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes 1 arg.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* typeA = command.GetArgumentAtIndex(0);
|
||||
ConstString typeCS(typeA);
|
||||
|
||||
if (!typeCS)
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_options.m_delete_all)
|
||||
{
|
||||
Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, (void*)typeCS.GetCString());
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
lldb::FormatCategorySP category;
|
||||
Debugger::Formatting::Categories::Get(ConstString(m_options.m_category), category);
|
||||
|
||||
bool delete_category = category->Filter()->Delete(typeCS.GetCString());
|
||||
|
||||
if (delete_category)
|
||||
{
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
result.AppendErrorWithFormat ("no custom synthetic provider for %s.\n", typeA);
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
OptionDefinition
|
||||
CommandObjectTypeSynthDelete::CommandOptions::g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_1, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Delete from every category."},
|
||||
{ LLDB_OPT_SET_2, false, "category", 'w', required_argument, NULL, 0, eArgTypeName, "Delete from given category."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectTypeSynthClear
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class CommandObjectTypeSynthClear : public CommandObject
|
||||
{
|
||||
private:
|
||||
|
||||
class CommandOptions : public Options
|
||||
{
|
||||
public:
|
||||
|
||||
CommandOptions (CommandInterpreter &interpreter) :
|
||||
Options (interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandOptions (){}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (uint32_t option_idx, const char *option_arg)
|
||||
{
|
||||
Error error;
|
||||
char short_option = (char) m_getopt_table[option_idx].val;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'a':
|
||||
m_delete_all = true;
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParsingStarting ()
|
||||
{
|
||||
m_delete_all = false;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_option_table;
|
||||
}
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
bool m_delete_all;
|
||||
bool m_delete_named;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
||||
virtual Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_options;
|
||||
}
|
||||
|
||||
static bool
|
||||
PerCategoryCallback(void* param,
|
||||
const char* cate_name,
|
||||
const FormatCategory::SharedPointer& cate)
|
||||
{
|
||||
cate->Filter()->Clear();
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
public:
|
||||
CommandObjectTypeSynthClear (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
"type synth clear",
|
||||
"Delete all existing synthetic providers.",
|
||||
NULL), m_options(interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
~CommandObjectTypeSynthClear ()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Execute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
|
||||
if (m_options.m_delete_all)
|
||||
Debugger::Formatting::Categories::LoopThrough(PerCategoryCallback, NULL);
|
||||
|
||||
else
|
||||
{
|
||||
lldb::FormatCategorySP category;
|
||||
if (command.GetArgumentCount() > 0)
|
||||
{
|
||||
const char* cat_name = command.GetArgumentAtIndex(0);
|
||||
ConstString cat_nameCS(cat_name);
|
||||
Debugger::Formatting::Categories::Get(cat_nameCS, category);
|
||||
}
|
||||
else
|
||||
Debugger::Formatting::Categories::Get(ConstString(NULL), category);
|
||||
category->Filter()->Clear();
|
||||
}
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
OptionDefinition
|
||||
CommandObjectTypeSynthClear::CommandOptions::g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_ALL, false, "all", 'a', no_argument, NULL, 0, eArgTypeBoolean, "Clear every category."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// CommandObjectTypeSynthAdd
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
class CommandObjectTypeSynthAdd : public CommandObject
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
class CommandOptions : public Options
|
||||
{
|
||||
typedef std::vector<std::string> option_vector;
|
||||
public:
|
||||
|
||||
CommandOptions (CommandInterpreter &interpreter) :
|
||||
Options (interpreter)
|
||||
{
|
||||
}
|
||||
|
||||
virtual
|
||||
~CommandOptions (){}
|
||||
|
||||
virtual Error
|
||||
SetOptionValue (uint32_t option_idx, const char *option_arg)
|
||||
{
|
||||
Error error;
|
||||
char short_option = (char) m_getopt_table[option_idx].val;
|
||||
bool success;
|
||||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'C':
|
||||
m_cascade = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
|
||||
break;
|
||||
case 'c':
|
||||
m_expr_paths.push_back(option_arg);
|
||||
break;
|
||||
case 'p':
|
||||
m_skip_pointers = true;
|
||||
break;
|
||||
case 'r':
|
||||
m_skip_references = true;
|
||||
break;
|
||||
case 'w':
|
||||
m_category = ConstString(option_arg).GetCString();
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void
|
||||
OptionParsingStarting ()
|
||||
{
|
||||
m_cascade = true;
|
||||
m_expr_paths.clear();
|
||||
m_skip_pointers = false;
|
||||
m_skip_references = false;
|
||||
m_category = NULL;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
GetDefinitions ()
|
||||
{
|
||||
return g_option_table;
|
||||
}
|
||||
|
||||
// Options table: Required for subclasses of Options.
|
||||
|
||||
static OptionDefinition g_option_table[];
|
||||
|
||||
// Instance variables to hold the values for command options.
|
||||
|
||||
bool m_cascade;
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
option_vector m_expr_paths;
|
||||
const char* m_category;
|
||||
|
||||
typedef option_vector::iterator ExpressionPathsIterator;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
||||
virtual Options *
|
||||
GetOptions ()
|
||||
{
|
||||
return &m_options;
|
||||
}
|
||||
|
||||
public:
|
||||
CommandObjectTypeSynthAdd (CommandInterpreter &interpreter) :
|
||||
CommandObject (interpreter,
|
||||
"type synth add",
|
||||
"Add a new synthetic provider for a type.",
|
||||
NULL), m_options (interpreter)
|
||||
{
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatPlus;
|
||||
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
|
||||
}
|
||||
|
||||
~CommandObjectTypeSynthAdd ()
|
||||
{
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
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."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
class CommandObjectTypeFormat : public CommandObjectMultiword
|
||||
{
|
||||
public:
|
||||
|
@ -1906,6 +2570,27 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class CommandObjectTypeSynth : public CommandObjectMultiword
|
||||
{
|
||||
public:
|
||||
CommandObjectTypeSynth (CommandInterpreter &interpreter) :
|
||||
CommandObjectMultiword (interpreter,
|
||||
"type synth",
|
||||
"A set of commands for operating on synthetic type representations",
|
||||
"type synth [<sub-command-options>] ")
|
||||
{
|
||||
LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSynthAdd (interpreter)));
|
||||
LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSynthClear (interpreter)));
|
||||
LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSynthDelete (interpreter)));
|
||||
LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSynthList (interpreter)));
|
||||
}
|
||||
|
||||
|
||||
~CommandObjectTypeSynth ()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
class CommandObjectTypeCategory : public CommandObjectMultiword
|
||||
{
|
||||
public:
|
||||
|
@ -1961,6 +2646,7 @@ CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) :
|
|||
LoadSubCommand ("category", CommandObjectSP (new CommandObjectTypeCategory (interpreter)));
|
||||
LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter)));
|
||||
LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter)));
|
||||
LoadSubCommand ("synth", CommandObjectSP (new CommandObjectTypeSynth (interpreter)));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -733,8 +733,12 @@ ScanFormatDescriptor(const char* var_name_begin,
|
|||
// if this is a V, print the value using the default format
|
||||
if (*format_name == 'V')
|
||||
*val_obj_display = ValueObject::eDisplayValue;
|
||||
// if this is an L, print the location of the value
|
||||
if (*format_name == 'L')
|
||||
*val_obj_display = ValueObject::eDisplayLocation;
|
||||
// if this is an S, print the summary after all
|
||||
if (*format_name == 'S')
|
||||
*val_obj_display = ValueObject::eDisplaySummary;
|
||||
}
|
||||
// a good custom format tells us to print the value using it
|
||||
else
|
||||
|
@ -1761,6 +1765,12 @@ Debugger::Formatting::GetSummaryFormat(ValueObject& vobj,
|
|||
{
|
||||
return GetFormatManager().Get(vobj, entry);
|
||||
}
|
||||
bool
|
||||
Debugger::Formatting::GetSyntheticFilter(ValueObject& vobj,
|
||||
lldb::SyntheticFilterSP& entry)
|
||||
{
|
||||
return GetFormatManager().Get(vobj, entry);
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::Formatting::Categories::Get(const ConstString &category, lldb::FormatCategorySP &entry)
|
||||
|
@ -1791,7 +1801,7 @@ Debugger::Formatting::Categories::Clear()
|
|||
void
|
||||
Debugger::Formatting::Categories::Clear(ConstString &category)
|
||||
{
|
||||
GetFormatManager().Category(category.GetCString())->Clear();
|
||||
GetFormatManager().Category(category.GetCString())->ClearSummaries();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -66,14 +66,15 @@ StringSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
|||
|
||||
if (m_show_members_oneliner)
|
||||
{
|
||||
const uint32_t num_children = object->GetNumChildren();
|
||||
ValueObjectSP synth_vobj = object->GetSyntheticValue(lldb::eUseSyntheticFilter);
|
||||
const uint32_t num_children = synth_vobj->GetNumChildren();
|
||||
if (num_children)
|
||||
{
|
||||
s.PutChar('(');
|
||||
|
||||
for (uint32_t idx=0; idx<num_children; ++idx)
|
||||
{
|
||||
lldb::ValueObjectSP child_sp(object->GetChildAtIndex(idx, true));
|
||||
lldb::ValueObjectSP child_sp(synth_vobj->GetChildAtIndex(idx, true));
|
||||
if (child_sp.get())
|
||||
{
|
||||
if (idx)
|
||||
|
@ -137,4 +138,21 @@ ScriptSummaryFormat::GetDescription()
|
|||
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
SyntheticFilter::GetDescription()
|
||||
{
|
||||
StreamString sstr;
|
||||
sstr.Printf("%s%s%s {\n",
|
||||
m_cascades ? "" : " (not cascading)",
|
||||
m_skip_pointers ? " (skip pointers)" : "",
|
||||
m_skip_references ? " (skip references)" : "");
|
||||
|
||||
for (int i = 0; i < GetCount(); i++)
|
||||
{
|
||||
sstr.Printf(" %s\n",
|
||||
GetExpressionPathAtIndex(i).c_str());
|
||||
}
|
||||
|
||||
sstr.Printf("}");
|
||||
return sstr.GetString();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "lldb/Core/ValueObjectDynamicValue.h"
|
||||
#include "lldb/Core/ValueObjectList.h"
|
||||
#include "lldb/Core/ValueObjectMemory.h"
|
||||
#include "lldb/Core/ValueObjectSyntheticFilter.h"
|
||||
|
||||
#include "lldb/Host/Endian.h"
|
||||
|
||||
|
@ -70,12 +71,14 @@ ValueObject::ValueObject (ValueObject &parent) :
|
|||
m_children (),
|
||||
m_synthetic_children (),
|
||||
m_dynamic_value (NULL),
|
||||
m_synthetic_value(NULL),
|
||||
m_deref_valobj(NULL),
|
||||
m_format (eFormatDefault),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_summary_format(),
|
||||
m_forced_summary_format(),
|
||||
m_last_value_format(),
|
||||
m_last_synthetic_filter(),
|
||||
m_user_id_of_forced_summary(0),
|
||||
m_value_is_valid (false),
|
||||
m_value_did_change (false),
|
||||
|
@ -85,6 +88,7 @@ ValueObject::ValueObject (ValueObject &parent) :
|
|||
m_is_deref_of_parent (false),
|
||||
m_is_array_item_for_pointer(false),
|
||||
m_is_bitfield_for_scalar(false),
|
||||
m_is_expression_path_child(false),
|
||||
m_dump_printable_counter(0)
|
||||
{
|
||||
m_manager->ManageObject(this);
|
||||
|
@ -110,12 +114,14 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
|
|||
m_children (),
|
||||
m_synthetic_children (),
|
||||
m_dynamic_value (NULL),
|
||||
m_synthetic_value(NULL),
|
||||
m_deref_valobj(NULL),
|
||||
m_format (eFormatDefault),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_summary_format(),
|
||||
m_forced_summary_format(),
|
||||
m_last_value_format(),
|
||||
m_last_synthetic_filter(),
|
||||
m_user_id_of_forced_summary(0),
|
||||
m_value_is_valid (false),
|
||||
m_value_did_change (false),
|
||||
|
@ -125,6 +131,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
|
|||
m_is_deref_of_parent (false),
|
||||
m_is_array_item_for_pointer(false),
|
||||
m_is_bitfield_for_scalar(false),
|
||||
m_is_expression_path_child(false),
|
||||
m_dump_printable_counter(0)
|
||||
{
|
||||
m_manager = new ValueObjectManager();
|
||||
|
@ -209,14 +216,13 @@ ValueObject::UpdateFormatsIfNeeded()
|
|||
if (m_last_summary_format.get())
|
||||
m_last_summary_format.reset((StringSummaryFormat*)NULL);
|
||||
if (m_last_value_format.get())
|
||||
m_last_value_format.reset((ValueFormat*)NULL);
|
||||
Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format);
|
||||
// to find a summary we look for a direct summary, then if there is none
|
||||
// we look for a regex summary. if there is none we look for a system
|
||||
// summary (direct), and if also that fails, we look for a system
|
||||
// regex summary
|
||||
m_last_value_format.reset(/*(ValueFormat*)NULL*/);
|
||||
if (m_last_synthetic_filter.get())
|
||||
m_last_synthetic_filter.reset(/*(SyntheticFilter*)NULL*/);
|
||||
|
||||
Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format);
|
||||
Debugger::Formatting::GetSummaryFormat(*this, m_last_summary_format);
|
||||
Debugger::Formatting::GetSyntheticFilter(*this, m_last_synthetic_filter);
|
||||
|
||||
m_last_format_mgr_revision = Debugger::Formatting::ValueFormats::GetCurrentRevision();
|
||||
|
||||
|
@ -1423,6 +1429,63 @@ ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_cre
|
|||
return synthetic_child_sp;
|
||||
}
|
||||
|
||||
// your expression path needs to have a leading . or ->
|
||||
// (unless it somehow "looks like" an array, in which case it has
|
||||
// a leading [ symbol). while the [ is meaningful and should be shown
|
||||
// to the user, . and -> are just parser design, but by no means
|
||||
// added information for the user.. strip them off
|
||||
static const char*
|
||||
SkipLeadingExpressionPathSeparators(const char* expression)
|
||||
{
|
||||
if (!expression || !expression[0])
|
||||
return expression;
|
||||
if (expression[0] == '.')
|
||||
return expression+1;
|
||||
if (expression[0] == '-' && expression[1] == '>')
|
||||
return expression+2;
|
||||
return expression;
|
||||
}
|
||||
|
||||
lldb::ValueObjectSP
|
||||
ValueObject::GetSyntheticExpressionPathChild(const char* expression, bool can_create)
|
||||
{
|
||||
ValueObjectSP synthetic_child_sp;
|
||||
ConstString name_const_string(expression);
|
||||
// Check if we have already created a synthetic array member in this
|
||||
// valid object. If we have we will re-use it.
|
||||
synthetic_child_sp = GetSyntheticChild (name_const_string);
|
||||
if (!synthetic_child_sp)
|
||||
{
|
||||
// We haven't made a synthetic array member for expression yet, so
|
||||
// lets make one and cache it for any future reference.
|
||||
synthetic_child_sp = GetValueForExpressionPath(expression);
|
||||
|
||||
// Cache the value if we got one back...
|
||||
if (synthetic_child_sp.get())
|
||||
{
|
||||
AddSyntheticChild(name_const_string, synthetic_child_sp.get());
|
||||
synthetic_child_sp->SetName(SkipLeadingExpressionPathSeparators(expression));
|
||||
synthetic_child_sp->m_is_expression_path_child = true;
|
||||
}
|
||||
}
|
||||
return synthetic_child_sp;
|
||||
}
|
||||
|
||||
void
|
||||
ValueObject::CalculateSyntheticValue (lldb::SyntheticValueType use_synthetic)
|
||||
{
|
||||
if (use_synthetic == lldb::eNoSyntheticFilter)
|
||||
return;
|
||||
|
||||
UpdateFormatsIfNeeded();
|
||||
|
||||
if (m_last_synthetic_filter.get() == NULL)
|
||||
return;
|
||||
|
||||
m_synthetic_value = new ValueObjectSyntheticFilter(*this, m_last_synthetic_filter);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ValueObject::CalculateDynamicValue (lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
|
@ -1483,6 +1546,29 @@ ValueObject::GetDynamicValue (DynamicValueType use_dynamic)
|
|||
return ValueObjectSP();
|
||||
}
|
||||
|
||||
// GetDynamicValue() returns a NULL SharedPointer if the object is not dynamic
|
||||
// or we do not really want a dynamic VO. this method instead returns this object
|
||||
// itself when making it synthetic has no meaning. this makes it much simpler
|
||||
// to replace the SyntheticValue for the ValueObject
|
||||
ValueObjectSP
|
||||
ValueObject::GetSyntheticValue (SyntheticValueType use_synthetic)
|
||||
{
|
||||
if (use_synthetic == lldb::eNoSyntheticFilter)
|
||||
return GetSP();
|
||||
|
||||
UpdateFormatsIfNeeded();
|
||||
|
||||
if (m_last_synthetic_filter.get() == NULL)
|
||||
return GetSP();
|
||||
|
||||
CalculateSyntheticValue(use_synthetic);
|
||||
|
||||
if (m_synthetic_value)
|
||||
return m_synthetic_value->GetSP();
|
||||
else
|
||||
return GetSP();
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObject::GetBaseClassPath (Stream &s)
|
||||
{
|
||||
|
@ -2398,6 +2484,7 @@ ValueObject::DumpValueObject
|
|||
bool show_location,
|
||||
bool use_objc,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
bool use_synth,
|
||||
bool scope_already_checked,
|
||||
bool flat_output,
|
||||
uint32_t omit_summary_depth
|
||||
|
@ -2545,7 +2632,10 @@ ValueObject::DumpValueObject
|
|||
|
||||
if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
|
||||
{
|
||||
const uint32_t num_children = valobj->GetNumChildren();
|
||||
ValueObjectSP synth_vobj = valobj->GetSyntheticValue(use_synth ?
|
||||
lldb::eUseSyntheticFilter :
|
||||
lldb::eNoSyntheticFilter);
|
||||
const uint32_t num_children = synth_vobj->GetNumChildren();
|
||||
if (num_children)
|
||||
{
|
||||
if (flat_output)
|
||||
|
@ -2562,7 +2652,7 @@ ValueObject::DumpValueObject
|
|||
|
||||
for (uint32_t idx=0; idx<num_children; ++idx)
|
||||
{
|
||||
ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
|
||||
ValueObjectSP child_sp(synth_vobj->GetChildAtIndex(idx, true));
|
||||
if (child_sp.get())
|
||||
{
|
||||
DumpValueObject (s,
|
||||
|
@ -2575,6 +2665,7 @@ ValueObject::DumpValueObject
|
|||
show_location,
|
||||
false,
|
||||
use_dynamic,
|
||||
use_synth,
|
||||
true,
|
||||
flat_output,
|
||||
omit_summary_depth > 1 ? omit_summary_depth - 1 : 0);
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
//===-- ValueObjectSyntheticFilter.cpp -----------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "lldb/Core/ValueObjectSyntheticFilter.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/FormatClasses.h"
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/ValueObjectList.h"
|
||||
#include "lldb/Core/Value.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Symbol/SymbolContext.h"
|
||||
#include "lldb/Symbol/Type.h"
|
||||
#include "lldb/Symbol/Variable.h"
|
||||
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/LanguageRuntime.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
ValueObjectSyntheticFilter::ValueObjectSyntheticFilter (ValueObject &parent, lldb::SyntheticFilterSP filter) :
|
||||
ValueObject(parent),
|
||||
m_address (),
|
||||
m_type_sp(),
|
||||
m_use_synthetic (lldb::eUseSyntheticFilter),
|
||||
m_synth_filter(filter)
|
||||
{
|
||||
SetName (parent.GetName().AsCString());
|
||||
}
|
||||
|
||||
ValueObjectSyntheticFilter::~ValueObjectSyntheticFilter()
|
||||
{
|
||||
m_owning_valobj_sp.reset();
|
||||
}
|
||||
|
||||
lldb::clang_type_t
|
||||
ValueObjectSyntheticFilter::GetClangType ()
|
||||
{
|
||||
if (m_type_sp)
|
||||
return m_value.GetClangType();
|
||||
else
|
||||
return m_parent->GetClangType();
|
||||
}
|
||||
|
||||
ConstString
|
||||
ValueObjectSyntheticFilter::GetTypeName()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded();
|
||||
if (success && m_type_sp)
|
||||
return ClangASTType::GetConstTypeName (GetClangType());
|
||||
else
|
||||
return m_parent->GetTypeName();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ValueObjectSyntheticFilter::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();
|
||||
}
|
||||
|
||||
clang::ASTContext *
|
||||
ValueObjectSyntheticFilter::GetClangAST ()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded(false);
|
||||
if (success && m_type_sp)
|
||||
return m_type_sp->GetClangAST();
|
||||
else
|
||||
return m_parent->GetClangAST ();
|
||||
}
|
||||
|
||||
size_t
|
||||
ValueObjectSyntheticFilter::GetByteSize()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded();
|
||||
if (success && m_type_sp)
|
||||
return m_value.GetValueByteSize(GetClangAST(), NULL);
|
||||
else
|
||||
return m_parent->GetByteSize();
|
||||
}
|
||||
|
||||
lldb::ValueType
|
||||
ValueObjectSyntheticFilter::GetValueType() const
|
||||
{
|
||||
return m_parent->GetValueType();
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObjectSyntheticFilter::UpdateValue ()
|
||||
{
|
||||
SetValueIsValid (false);
|
||||
m_error.Clear();
|
||||
|
||||
if (!m_parent->UpdateValueIfNeeded())
|
||||
{
|
||||
// our parent could not update.. as we are meaningless without a parent, just stop
|
||||
if (m_error.Success() && m_parent->GetError().Fail())
|
||||
m_error = m_parent->GetError();
|
||||
return false;
|
||||
}
|
||||
|
||||
SetValueIsValid(true);
|
||||
return true;
|
||||
}
|
||||
|
||||
lldb::ValueObjectSP
|
||||
ValueObjectSyntheticFilter::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);
|
||||
}
|
||||
|
||||
lldb::ValueObjectSP
|
||||
ValueObjectSyntheticFilter::GetChildMemberWithName (const ConstString &name, bool can_create)
|
||||
{
|
||||
if (!m_synth_filter.get())
|
||||
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);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ValueObjectSyntheticFilter::GetIndexOfChildWithName (const ConstString &name)
|
||||
{
|
||||
const char* name_cstr = name.GetCString();
|
||||
for (int i = 0; i < m_synth_filter->GetCount(); i++)
|
||||
{
|
||||
const char* expr_cstr = m_synth_filter->GetExpressionPathAtIndex(i).c_str();
|
||||
if (::strcmp(name_cstr, expr_cstr))
|
||||
return i;
|
||||
}
|
||||
return UINT32_MAX;
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObjectSyntheticFilter::IsInScope ()
|
||||
{
|
||||
return m_parent->IsInScope();
|
||||
}
|
||||
|
|
@ -31,7 +31,8 @@ static OptionDefinition
|
|||
g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, TargetInstanceSettings::g_dynamic_value_types,
|
||||
0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
|
||||
0, eArgTypeNone, "Show the object as its full dynamic type, not its static type, if available."},
|
||||
{ LLDB_OPT_SET_1, false, "synthetic-type", 'S', required_argument, NULL, 0, eArgTypeBoolean, "Show the object obeying its synthetic provider, if available."},
|
||||
{ LLDB_OPT_SET_1, false, "depth", 'D', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
|
||||
{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
|
||||
{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
|
||||
|
@ -105,7 +106,12 @@ OptionGroupValueObjectDisplay::SetOptionValue (CommandInterpreter &interpreter,
|
|||
else
|
||||
no_summary_depth = 1;
|
||||
break;
|
||||
|
||||
|
||||
case 'S':
|
||||
use_synth = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid synthetic-type '%s'.\n", option_arg);
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
|
@ -124,6 +130,7 @@ OptionGroupValueObjectDisplay::OptionParsingStarting (CommandInterpreter &interp
|
|||
use_objc = false;
|
||||
max_depth = UINT32_MAX;
|
||||
ptr_depth = 0;
|
||||
use_synth = true;
|
||||
|
||||
Target *target = interpreter.GetExecutionContext().target;
|
||||
if (target != NULL)
|
||||
|
|
|
@ -319,8 +319,23 @@ class DataFormatterTestCase(TestBase):
|
|||
'AShape',
|
||||
'ARectangleStar'])
|
||||
|
||||
# check that synthetic children work into categories
|
||||
self.runCmd("type synth add Rectangle --child w --category RectangleCategory")
|
||||
self.runCmd("type category enable RectangleCategory")
|
||||
self.runCmd("type summary add Rectangle -f \" \" -e --category RectangleCategory")
|
||||
self.expect('frame variable r2',
|
||||
substrs = ['w = 9'])
|
||||
self.runCmd("type summary add Rectangle -f \" \" -e")
|
||||
self.expect('frame variable r2', matching=False,
|
||||
substrs = ['h = 16'])
|
||||
|
||||
# Now delete all categories
|
||||
self.runCmd("type category delete CircleCategory RectangleStarCategory BaseCategory")
|
||||
self.runCmd("type category delete CircleCategory RectangleStarCategory BaseCategory RectangleCategory")
|
||||
|
||||
# last of all, check that a deleted category with synth does not blow us up
|
||||
self.expect('frame variable r2',
|
||||
substrs = ['w = 9',
|
||||
'h = 16'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -182,7 +182,25 @@ class DataFormatterTestCase(TestBase):
|
|||
self.expect("frame variable cool_pointer",
|
||||
substrs = ['3,0,0'])
|
||||
|
||||
# test special symbols for formatting variables into summaries
|
||||
self.runCmd("type summary add -f \"cool object @ ${var%L}\" i_am_cool")
|
||||
self.runCmd("type summary delete \"i_am_cool [5]\"")
|
||||
|
||||
# this test might fail if the compiler tries to store
|
||||
# these values into registers.. hopefully this is not
|
||||
# going to be the case
|
||||
self.expect("frame variable cool_array",
|
||||
substrs = ['[0] = cool object @ 0x',
|
||||
'[1] = cool object @ 0x',
|
||||
'[2] = cool object @ 0x',
|
||||
'[3] = cool object @ 0x',
|
||||
'[4] = cool object @ 0x'])
|
||||
|
||||
self.runCmd("type summary add -f \"goofy\" i_am_cool")
|
||||
self.runCmd("type summary add -f \"${var.second_cool%S}\" i_am_cooler")
|
||||
|
||||
self.expect("frame variable the_coolest_guy",
|
||||
substrs = ['(i_am_cooler) the_coolest_guy = goofy'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -110,6 +110,8 @@ int main (int argc, const char * argv[])
|
|||
|
||||
char strarr[32] = "Hello world!";
|
||||
char* strptr = "Hello world!";
|
||||
|
||||
i_am_cooler the_coolest_guy(1,2,3.14,6.28,'E','G');
|
||||
|
||||
return 0; // Set break point at this line.
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,203 @@
|
|||
"""
|
||||
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-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)
|
||||
|
||||
# Pick some values and check that the basics work
|
||||
self.runCmd("type synth add BagOfInts --child x --child z")
|
||||
self.expect("frame variable int_bag",
|
||||
substrs = ['x = 6',
|
||||
'z = 8'])
|
||||
|
||||
# Check we can still access the missing child by summary
|
||||
self.runCmd("type summary add BagOfInts -f \"y=${var.y}\"")
|
||||
self.expect('frame variable int_bag',
|
||||
substrs = ['y=7'])
|
||||
|
||||
# Even if we have synth children, the summary prevails
|
||||
self.expect("frame variable int_bag", matching=False,
|
||||
substrs = ['x = 6',
|
||||
'z = 8'])
|
||||
|
||||
# Summary+Synth must work together
|
||||
self.runCmd("type summary add BagOfInts -f \"y=${var.y}\" -e")
|
||||
self.expect('frame variable int_bag',
|
||||
substrs = ['y=7',
|
||||
'x = 6',
|
||||
'z = 8'])
|
||||
|
||||
# Same output, but using Python
|
||||
self.runCmd("type summary add BagOfInts -s \"return 'y='+valobj.GetChildMemberWithName('y').GetValue()\" -e")
|
||||
self.expect('frame variable int_bag',
|
||||
substrs = ['y=7',
|
||||
'x = 6',
|
||||
'z = 8'])
|
||||
|
||||
# If I skip summaries, still give me the artificial children
|
||||
self.expect("frame variable int_bag -Y1",
|
||||
substrs = ['x = 6',
|
||||
'z = 8'])
|
||||
|
||||
# Delete synth and check that the view reflects it immediately
|
||||
self.runCmd("type synth delete BagOfInts")
|
||||
self.expect("frame variable int_bag",
|
||||
substrs = ['x = 6',
|
||||
'y = 7',
|
||||
'z = 8'])
|
||||
|
||||
# Add the synth again and check that it's honored deeper in the hierarchy
|
||||
self.runCmd("type synth add BagOfInts --child x --child z")
|
||||
self.expect('frame variable bag_bag',
|
||||
substrs = ['x = y=70 {',
|
||||
'x = 69',
|
||||
'z = 71',
|
||||
'y = y=67 {',
|
||||
'x = 66',
|
||||
'z = 68'])
|
||||
self.expect('frame variable bag_bag', matching=False,
|
||||
substrs = ['y = 70',
|
||||
'y = 67'])
|
||||
|
||||
# Check that a synth can expand nested stuff
|
||||
self.runCmd("type synth add BagOfBags --child x.y --child y.z")
|
||||
self.expect('frame variable bag_bag',
|
||||
substrs = ['x.y = 70',
|
||||
'y.z = 68'])
|
||||
|
||||
# ...even if we get -> and . wrong
|
||||
self.runCmd("type synth add BagOfBags --child x.y --child \"y->z\"")
|
||||
self.expect('frame variable bag_bag',
|
||||
substrs = ['x.y = 70',
|
||||
'y->z = 68'])
|
||||
|
||||
# ...even bitfields
|
||||
self.runCmd("type synth add BagOfBags --child x.y --child \"y->z[1-2]\"")
|
||||
self.expect('frame variable bag_bag -T',
|
||||
substrs = ['x.y = 70',
|
||||
'(int:2) y->z[1-2] = 2'])
|
||||
|
||||
# ...even if we format the bitfields
|
||||
self.runCmd("type synth add BagOfBags --child x.y --child \"y->y[0-0]\"")
|
||||
self.runCmd("type format add \"int:1\" -f bool")
|
||||
self.expect('frame variable bag_bag -T',
|
||||
substrs = ['x.y = 70',
|
||||
'(int:1) y->y[0-0] = true'])
|
||||
|
||||
# ...even if we use one-liner summaries
|
||||
self.runCmd("type summary add -c BagOfBags")
|
||||
self.expect('frame variable bag_bag',
|
||||
substrs = ['(BagOfBags) bag_bag = (x.y=70, y->y[0-0]=true)'])
|
||||
|
||||
self.runCmd("type summary delete BagOfBags")
|
||||
|
||||
# now check we are dynamic (and arrays work)
|
||||
self.runCmd("type synth add Plenty --child bitfield --child array[0] --child array[2]")
|
||||
self.expect('frame variable plenty_of_stuff',
|
||||
substrs = ['bitfield = 1',
|
||||
'array[0] = 5',
|
||||
'array[2] = 3'])
|
||||
|
||||
self.runCmd("n")
|
||||
self.expect('frame variable plenty_of_stuff',
|
||||
substrs = ['bitfield = 17',
|
||||
'array[0] = 5',
|
||||
'array[2] = 3'])
|
||||
|
||||
# skip synthetic children
|
||||
self.expect('frame variable plenty_of_stuff -S no',
|
||||
substrs = ['some_values = 0x0',
|
||||
'array = 0x',
|
||||
'array_size = 5'])
|
||||
|
||||
|
||||
# check flat printing with synthetic children
|
||||
self.expect('frame variable plenty_of_stuff --flat',
|
||||
substrs = ['plenty_of_stuff.bitfield = 17',
|
||||
'*(plenty_of_stuff.array) = 5',
|
||||
'*(plenty_of_stuff.array) = 3'])
|
||||
|
||||
# check that we do not lose location information for our children
|
||||
self.expect('frame variable plenty_of_stuff -L',
|
||||
substrs = ['0x',
|
||||
': bitfield = 17'])
|
||||
|
||||
# check we work across pointer boundaries
|
||||
self.expect('frame variable plenty_of_stuff.some_values -P1',
|
||||
substrs = ['(BagOfInts *) plenty_of_stuff.some_values',
|
||||
'x = 5',
|
||||
'z = 7'])
|
||||
|
||||
# but not if we don't want to
|
||||
self.runCmd("type synth add BagOfInts --child x --child z -p")
|
||||
self.expect('frame variable plenty_of_stuff.some_values -P1',
|
||||
substrs = ['(BagOfInts *) plenty_of_stuff.some_values',
|
||||
'x = 5',
|
||||
'y = 6',
|
||||
'z = 7'])
|
||||
|
||||
# check we're dynamic even if nested
|
||||
self.runCmd("type synth add BagOfBags --child x.z")
|
||||
self.expect('frame variable bag_bag',
|
||||
substrs = ['x.z = 71'])
|
||||
|
||||
self.runCmd("n")
|
||||
self.expect('frame variable bag_bag',
|
||||
substrs = ['x.z = 12'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
lldb.SBDebugger.Initialize()
|
||||
atexit.register(lambda: lldb.SBDebugger.Terminate())
|
||||
unittest2.main()
|
|
@ -0,0 +1,83 @@
|
|||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct BagOfInts
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int z;
|
||||
BagOfInts(int X) :
|
||||
x(X),
|
||||
y(X+1),
|
||||
z(X+2) {}
|
||||
};
|
||||
|
||||
struct BagOfFloats
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
BagOfFloats(float X) :
|
||||
x(X+0.334),
|
||||
y(X+0.500),
|
||||
z(X+0.667) {}
|
||||
};
|
||||
|
||||
struct BagOfBags
|
||||
{
|
||||
BagOfInts x;
|
||||
BagOfInts y;
|
||||
BagOfFloats z;
|
||||
BagOfFloats q;
|
||||
BagOfBags() :
|
||||
x('E'),
|
||||
y('B'),
|
||||
z(1.1),
|
||||
q(20.11) {}
|
||||
};
|
||||
|
||||
struct Plenty
|
||||
{
|
||||
BagOfInts *some_values;
|
||||
int* array;
|
||||
int array_size;
|
||||
int bitfield;
|
||||
|
||||
Plenty(int N, bool flagA, bool flagB) :
|
||||
some_values(new BagOfInts(N)),
|
||||
array(new int[N]),
|
||||
array_size(N),
|
||||
bitfield( (flagA ? 0x01 : 0x00) | (flagB ? 0x10 : 0x00) )
|
||||
{
|
||||
for (int j = 0; j < N; j++)
|
||||
array[j] = N-j;
|
||||
}
|
||||
};
|
||||
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
BagOfInts int_bag(6);
|
||||
BagOfFloats float_bag(2.71);
|
||||
|
||||
BagOfBags bag_bag;
|
||||
|
||||
Plenty plenty_of_stuff(5,true,false);
|
||||
|
||||
plenty_of_stuff.bitfield = 0x11; // Set break point at this line.
|
||||
|
||||
bag_bag.x.z = 12;
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
|
@ -495,20 +495,38 @@
|
|||
in fact it has a similar effect. If you add a % sign
|
||||
followed by any one format name or abbreviation from the
|
||||
above table after an expression path, the resulting
|
||||
object will be displyed using the chosen format (this is
|
||||
applicable to non-aggregate types only, with a few
|
||||
special exceptions discussed below). </p>
|
||||
<p>There are two more special format symbols that you can
|
||||
use only as part of a summary string: <code>%V</code>
|
||||
and <code>%@</code>. The first one tells LLDB to ignore
|
||||
summary strings for the type of the object referred by
|
||||
the expression path and instead print the object's
|
||||
value. The second is only applicable to Objective-C
|
||||
classes, and tells LLDB to get the object's description
|
||||
from the Objective-C runtime. By default, if no format
|
||||
is provided, LLDB will try to get the object's summary,
|
||||
and if empty the object's value. If neither can be
|
||||
obtained, nothing will be displayed.</p>
|
||||
object will be displyed using the chosen format.</p>
|
||||
|
||||
<p>You can also use some other special format markers, not available
|
||||
for type formatters, but which carry a special meaning when used in this
|
||||
context:</p>
|
||||
|
||||
<table border="1">
|
||||
<tbody>
|
||||
<tr valign="top">
|
||||
<td width="23%"><b>Symbol</b></td>
|
||||
<td><b>Description</b></td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><b>%S</b></td>
|
||||
<td>Use this object's summary (the default for aggregate types)</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><b>%V</b></td>
|
||||
<td>Use this object's value (the default for non-aggregate types)</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><b>%@</b></td>
|
||||
<td>Use a language-runtime specific description (for C++ this does nothing,
|
||||
for Objective-C it calls the NSPrintForDebugger API)</td>
|
||||
</tr>
|
||||
<tr valign="top">
|
||||
<td><b>%L</b></td>
|
||||
<td>Use this object's location (memory address, register name, ...)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p>As previously said, pointers and values are treated the
|
||||
same way when getting to their members in an expression
|
||||
path. However, if your expression path leads to a
|
||||
|
|
Loading…
Reference in New Issue