summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/Core/Debugger.h55
-rw-r--r--lldb/include/lldb/Core/FormatManager.h303
-rw-r--r--lldb/include/lldb/Core/ValueObject.h17
-rw-r--r--lldb/include/lldb/Symbol/ClangASTType.h7
-rw-r--r--lldb/include/lldb/lldb-forward-rtti.h2
-rw-r--r--lldb/include/lldb/lldb-forward.h3
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj2
-rw-r--r--lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme4
-rw-r--r--lldb/source/Commands/CommandObjectType.cpp552
-rw-r--r--lldb/source/Core/Debugger.cpp358
-rw-r--r--lldb/source/Core/FormatManager.cpp58
-rw-r--r--lldb/source/Core/ValueObject.cpp159
-rw-r--r--lldb/source/Symbol/ClangASTType.cpp36
-rw-r--r--lldb/test/functionalities/data-formatter/TestDataFormatter.py34
-rw-r--r--lldb/test/functionalities/data-formatter/main.cpp8
15 files changed, 1377 insertions, 221 deletions
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index ae69d3e5588..021a18f766c 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -415,7 +415,8 @@ public:
const ExecutionContext *exe_ctx,
const Address *addr,
Stream &s,
- const char **end);
+ const char **end,
+ ValueObject* vobj = NULL);
void
@@ -473,18 +474,50 @@ private:
public:
- static bool
- GetFormatForType (const ConstString &type, lldb::Format& format, bool& cascade);
-
- static void
- AddFormatForType (const ConstString &type, lldb::Format format, bool cascade);
+ class ValueFormats
+ {
+ public:
+ static bool
+ Get(ValueObject& vobj, ValueFormat::SharedPointer &entry);
+
+ static void
+ Add(const ConstString &type, const ValueFormat::SharedPointer &entry);
+
+ static bool
+ Delete(const ConstString &type);
+
+ static void
+ Clear();
+
+ static void
+ LoopThrough(FormatManager::ValueCallback callback, void* callback_baton);
+
+ static uint32_t GetCurrentRevision();
+ };
- static bool
- DeleteFormatForType (const ConstString &type);
+ class SummaryFormats
+ {
+ public:
+
+ static bool
+ Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry);
+
+ static void
+ Add(const ConstString &type, const SummaryFormat::SharedPointer &entry);
+
+ static bool
+ Delete(const ConstString &type);
+
+ static void
+ Clear();
+
+ static void
+ LoopThrough(FormatManager::SummaryCallback callback, void* callback_baton);
+
+ static uint32_t
+ GetCurrentRevision();
+ };
- static void
- LoopThroughFormatList (FormatManager::Callback callback,
- void* callback_baton);
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h
index d99887bf8cd..01914537d85 100644
--- a/lldb/include/lldb/Core/FormatManager.h
+++ b/lldb/include/lldb/Core/FormatManager.h
@@ -40,42 +40,288 @@ namespace std
#include "lldb/Core/Communication.h"
#include "lldb/Core/InputReaderStack.h"
#include "lldb/Core/Listener.h"
-#include "lldb/Core/Stream.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/SourceManager.h"
#include "lldb/Core/UserID.h"
#include "lldb/Core/UserSettingsController.h"
+#include "lldb/Core/ValueObject.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Platform.h"
#include "lldb/Target/TargetList.h"
-namespace lldb_private {
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+namespace lldb_private {
-class FormatManager
+class IFormatChangeListener
{
public:
+ virtual void
+ Changed() = 0;
+
+ virtual
+ ~IFormatChangeListener() {}
+
+};
- typedef bool(*Callback)(void*, const char*, lldb::Format, bool);
+struct SummaryFormat
+{
+ std::string m_format;
+ bool m_dont_show_children;
+ bool m_dont_show_value;
+ bool m_show_members_oneliner;
+ bool m_cascades;
+ SummaryFormat(std::string f = "", bool c = false, bool nochildren = true, bool novalue = true, bool oneliner = false) :
+ m_format(f),
+ m_dont_show_children(nochildren),
+ m_dont_show_value(novalue),
+ m_show_members_oneliner(oneliner),
+ m_cascades(c)
+ {
+ }
+
+ bool
+ DoesPrintChildren() const
+ {
+ return !m_dont_show_children;
+ }
+
+ bool
+ DoesPrintValue() const
+ {
+ return !m_dont_show_value;
+ }
+
+ bool
+ IsOneliner() const
+ {
+ return m_show_members_oneliner;
+ }
+
+ typedef lldb::SharedPtr<SummaryFormat>::Type SharedPointer;
+
+};
- FormatManager() :
- m_format_map(FormatMap()),
- m_format_map_mutex(Mutex::eMutexTypeRecursive)
+struct ValueFormat
+{
+ lldb::Format m_format;
+ bool m_cascades;
+ ValueFormat (lldb::Format f = lldb::eFormatInvalid, bool c = false) :
+ m_format (f),
+ m_cascades (c)
+ {
+ }
+
+ typedef lldb::SharedPtr<ValueFormat>::Type SharedPointer;
+
+ ~ValueFormat()
{
}
+
+};
+
+template<typename MapType, typename CallbackType>
+class FormatNavigator
+{
+public:
+ typedef typename MapType::iterator MapIterator;
+ typedef typename MapType::key_type MapKeyType;
+ typedef typename MapType::mapped_type MapValueType;
+
+ FormatNavigator(IFormatChangeListener* lst = NULL) :
+ m_map_mutex(Mutex::eMutexTypeRecursive),
+ m_map(MapType()),
+ listener(lst)
+ {
+ }
+
bool
- GetFormatForType (const ConstString &type, lldb::Format& format, bool& cascade);
-
+ Get(ValueObject& vobj, MapValueType& entry)
+ {
+ Mutex::Locker(m_map_mutex);
+ clang::QualType type = clang::QualType::getFromOpaquePtr(vobj.GetClangType());
+ bool ret = Get(vobj, type, entry);
+ if(ret)
+ entry = MapValueType(entry);
+ else
+ entry = MapValueType();
+ return ret;
+ }
+
void
- AddFormatForType (const ConstString &type, lldb::Format format, bool cascade);
-
+ Add(const MapKeyType &type, const MapValueType& entry)
+ {
+ Mutex::Locker(m_map_mutex);
+ m_map[type] = MapValueType(entry);
+ if(listener)
+ listener->Changed();
+ }
+
bool
- DeleteFormatForType (const ConstString &type);
-
+ Delete(const MapKeyType& type)
+ {
+ Mutex::Locker(m_map_mutex);
+ MapIterator iter = m_map.find(type);
+ if (iter == m_map.end())
+ return false;
+ m_map.erase(type);
+ if(listener)
+ listener->Changed();
+ return true;
+ }
+
+ void
+ Clear()
+ {
+ Mutex::Locker(m_map_mutex);
+ m_map.clear();
+ if(listener)
+ listener->Changed();
+ }
+
void
- LoopThroughFormatList (Callback cback, void* param);
+ LoopThrough(CallbackType callback, void* param)
+ {
+ if (callback)
+ {
+ Mutex::Locker(m_map_mutex);
+ MapIterator pos, end = m_map.end();
+ for (pos = m_map.begin(); pos != end; pos++)
+ {
+ MapKeyType type = pos->first;
+ if(!callback(param, type, MapValueType(pos->second)))
+ break;
+ }
+ }
+ }
+
+ ~FormatNavigator()
+ {
+ }
+
+private:
+
+ Mutex m_map_mutex;
+ MapType m_map;
+ IFormatChangeListener* listener;
+
+ DISALLOW_COPY_AND_ASSIGN(FormatNavigator);
+
+ bool
+ Get(const MapKeyType &type, MapValueType& entry)
+ {
+ Mutex::Locker(m_map_mutex);
+ MapIterator iter = m_map.find(type);
+ if (iter == m_map.end())
+ return false;
+ entry = iter->second;
+ return true;
+ }
+
+ bool Get(ValueObject& vobj,
+ const clang::QualType& q_type,
+ MapValueType& entry)
+ {
+ if (q_type.isNull())
+ return false;
+ clang::QualType type = q_type.getUnqualifiedType();
+ type.removeLocalConst(); type.removeLocalVolatile(); type.removeLocalRestrict();
+ ConstString name(type.getAsString().c_str());
+ //printf("trying to get format for VO name %s of type %s\n",vobj.GetName().AsCString(),name.AsCString());
+ if (Get(name.GetCString(), entry))
+ return true;
+ // look for a "base type", whatever that means
+ const clang::Type* typePtr = type.getTypePtrOrNull();
+ if (!typePtr)
+ return false;
+ if (typePtr->isReferenceType())
+ return Get(vobj,type.getNonReferenceType(),entry);
+ // for C++ classes, navigate up the hierarchy
+ if (typePtr->isRecordType())
+ {
+ clang::CXXRecordDecl* record = typePtr->getAsCXXRecordDecl();
+ if (record)
+ {
+ if (!record->hasDefinition())
+ // dummy call to do the complete
+ ClangASTContext::GetNumChildren(vobj.GetClangAST(), vobj.GetClangType(), false);
+ clang::IdentifierInfo *info = record->getIdentifier();
+ if (info) {
+ // this is the class name, plain and simple
+ ConstString id_info(info->getName().str().c_str());
+ if (Get(id_info.GetCString(), entry))
+ return true;
+ }
+ if (record->hasDefinition())
+ {
+ clang::CXXRecordDecl::base_class_iterator pos,end;
+ if( record->getNumBases() > 0)
+ {
+ end = record->bases_end();
+ for (pos = record->bases_begin(); pos != end; pos++)
+ {
+ if((Get(vobj, pos->getType(), entry)) && entry->m_cascades)
+ return true; // if it does not cascade, just move on to other base classes which might
+ }
+ }
+ if (record->getNumVBases() > 0)
+ {
+ end = record->vbases_end();
+ for (pos = record->vbases_begin(); pos != end; pos++)
+ {
+ if((Get(vobj, pos->getType(), entry)) && entry->m_cascades)
+ return true;
+ }
+ }
+ }
+ }
+ }
+ // try to strip typedef chains
+ const clang::TypedefType* type_tdef = type->getAs<clang::TypedefType>();
+ if (type_tdef)
+ if ((Get(vobj, type_tdef->getDecl()->getUnderlyingType(), entry)) && entry->m_cascades)
+ return true;
+ return false;
+ }
+
+};
+
+class FormatManager : public IFormatChangeListener
+{
+
+public:
+
+ typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
+ typedef bool(*SummaryCallback)(void*, const char*, const SummaryFormat::SharedPointer&);
+
+private:
+
+ typedef std::map<const char*, ValueFormat::SharedPointer> ValueMap;
+ typedef std::map<const char*, SummaryFormat::SharedPointer> SummaryMap;
+
+ typedef FormatNavigator<ValueMap, ValueCallback> ValueNavigator;
+ typedef FormatNavigator<SummaryMap, SummaryCallback> SummaryNavigator;
+
+ ValueNavigator m_value_nav;
+ SummaryNavigator m_summary_nav;
+
+ uint32_t m_last_revision;
+
+public:
+
+ FormatManager() :
+ m_value_nav(this),
+ m_summary_nav(this),
+ m_last_revision(0)
+ {
+ }
+
+ ValueNavigator& Value() { return m_value_nav; }
+ SummaryNavigator& Summary() { return m_summary_nav; }
+
static bool
GetFormatFromCString (const char *format_cstr,
bool partial_match_ok,
@@ -86,24 +332,23 @@ public:
static const char *
GetFormatAsCString (lldb::Format format);
-
-private:
- struct Entry
+
+ void
+ Changed()
{
- lldb::Format format;
- bool cascades;
- Entry (lldb::Format f = lldb::eFormatInvalid, bool c = false) :
- format (f),
- cascades (c)
- {
- }
- };
+ __sync_add_and_fetch(&m_last_revision, +1);
+ }
+
+ uint32_t
+ GetCurrentRevision() const
+ {
+ return m_last_revision;
+ }
- typedef std::map<const char*, Entry> FormatMap;
- typedef FormatMap::iterator FormatIterator;
+ ~FormatManager()
+ {
+ }
- FormatMap m_format_map;
- Mutex m_format_map_mutex;
};
} // namespace lldb_private
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index 82ed45cf675..5242c1fb258 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -64,6 +64,12 @@ namespace lldb_private {
class ValueObject : public UserID
{
public:
+
+ enum GetExpressionPathFormat
+ {
+ eDereferencePointers = 1,
+ eHonorPointers,
+ };
class EvaluationPoint
{
@@ -262,8 +268,8 @@ public:
GetBaseClassPath (Stream &s);
virtual void
- GetExpressionPath (Stream &s, bool qualify_cxx_base_classes);
-
+ GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat = eDereferencePointers);
+
virtual bool
IsInScope ()
{
@@ -347,6 +353,9 @@ public:
bool
UpdateValueIfNeeded ();
+
+ void
+ UpdateFormatsIfNeeded();
DataExtractor &
GetDataExtractor ();
@@ -508,7 +517,9 @@ protected:
ValueObject *m_deref_valobj;
lldb::Format m_format;
- lldb::Format m_last_format;
+ uint32_t m_last_format_mgr_revision;
+ lldb::SummaryFormatSP m_last_summary_format;
+ lldb::ValueFormatSP m_last_value_format;
bool m_value_is_valid:1,
m_value_did_change:1,
m_children_count_valid:1,
diff --git a/lldb/include/lldb/Symbol/ClangASTType.h b/lldb/include/lldb/Symbol/ClangASTType.h
index e68a9dca873..cc75f6106cb 100644
--- a/lldb/include/lldb/Symbol/ClangASTType.h
+++ b/lldb/include/lldb/Symbol/ClangASTType.h
@@ -182,6 +182,13 @@ public:
static lldb::Format
GetFormat (lldb::clang_type_t opaque_clang_qual_type);
+
+ uint32_t
+ GetTypeByteSize();
+
+ static uint32_t
+ GetTypeByteSize(clang::ASTContext *ast_context,
+ lldb::clang_type_t opaque_clang_qual_type);
bool
GetValueAsScalar (const DataExtractor &data,
diff --git a/lldb/include/lldb/lldb-forward-rtti.h b/lldb/include/lldb/lldb-forward-rtti.h
index abfe843e1f8..766407753b7 100644
--- a/lldb/include/lldb/lldb-forward-rtti.h
+++ b/lldb/include/lldb/lldb-forward-rtti.h
@@ -60,6 +60,7 @@ namespace lldb {
typedef SharedPtr<lldb_private::StopInfo>::Type StopInfoSP;
typedef SharedPtr<lldb_private::StoppointLocation>::Type StoppointLocationSP;
typedef SharedPtr<lldb_private::Stream>::Type StreamSP;
+ 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::Target>::Type TargetSP;
@@ -72,6 +73,7 @@ namespace lldb {
typedef SharedPtr<lldb_private::UnwindPlan>::Type UnwindPlanSP;
typedef SharedPtr<lldb_private::ValueObject>::Type ValueObjectSP;
typedef SharedPtr<lldb_private::Value>::Type ValueSP;
+ typedef SharedPtr<lldb_private::ValueFormat>::Type ValueFormatSP;
typedef SharedPtr<lldb_private::ValueList>::Type ValueListSP;
typedef SharedPtr<lldb_private::Variable>::Type VariableSP;
typedef SharedPtr<lldb_private::VariableList>::Type VariableListSP;
diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h
index d05359126b5..4b3a97fc4d1 100644
--- a/lldb/include/lldb/lldb-forward.h
+++ b/lldb/include/lldb/lldb-forward.h
@@ -76,6 +76,7 @@ class ExecutionContextScope;
class FileSpec;
class FileSpecList;
class Flags;
+class FormatManager;
class FuncUnwinders;
class Function;
class FunctionInfo;
@@ -130,6 +131,7 @@ class Stream;
class StreamFile;
class StreamString;
class StringList;
+class SummaryFormat;
class Symbol;
class SymbolContext;
class SymbolContextList;
@@ -164,6 +166,7 @@ class UnwindTable;
class UserSettingsController;
class VMRange;
class Value;
+class ValueFormat;
class ValueList;
class ValueObject;
class ValueObjectList;
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index 7abe7956546..e7fb8352217 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -924,7 +924,7 @@
26BC7E9610F1B85900F91463 /* Timer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Timer.cpp; path = source/Core/Timer.cpp; sourceTree = "<group>"; };
26BC7E9810F1B85900F91463 /* UserID.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UserID.cpp; path = source/Core/UserID.cpp; sourceTree = "<group>"; };
26BC7E9910F1B85900F91463 /* Value.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Value.cpp; path = source/Core/Value.cpp; sourceTree = "<group>"; };
- 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
+ 26BC7E9A10F1B85900F91463 /* ValueObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; name = ValueObject.cpp; path = source/Core/ValueObject.cpp; sourceTree = "<group>"; };
26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectChild.cpp; path = source/Core/ValueObjectChild.cpp; sourceTree = "<group>"; };
26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectList.cpp; path = source/Core/ValueObjectList.cpp; sourceTree = "<group>"; };
26BC7E9D10F1B85900F91463 /* ValueObjectVariable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectVariable.cpp; path = source/Core/ValueObjectVariable.cpp; sourceTree = "<group>"; };
diff --git a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme
index c5d00df5d84..afb96900b7d 100644
--- a/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme
+++ b/lldb/lldb.xcodeproj/xcshareddata/xcschemes/lldb-tool.xcscheme
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
- version = "1.3">
+ version = "1.8">
<BuildAction
parallelizeBuildables = "NO"
buildImplicitDependencies = "YES">
@@ -77,7 +77,7 @@
launchStyle = "0"
useCustomWorkingDirectory = "NO"
customWorkingDirectory = "/Volumes/work/gclayton/Documents/devb/attach"
- buildConfiguration = "Release"
+ buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "YES"
enablesOpenGLESFrameCapture = "YES">
<BuildableProductRunnable>
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index 32172f21025..7d3b83b8cba 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -25,10 +25,10 @@ using namespace lldb;
using namespace lldb_private;
//-------------------------------------------------------------------------
-// CommandObjectTypeAdd
+// CommandObjectTypeFormatAdd
//-------------------------------------------------------------------------
-class CommandObjectTypeAdd : public CommandObject
+class CommandObjectTypeFormatAdd : public CommandObject
{
private:
@@ -97,7 +97,7 @@ private:
}
public:
- CommandObjectTypeAdd (CommandInterpreter &interpreter) :
+ CommandObjectTypeFormatAdd (CommandInterpreter &interpreter) :
CommandObject (interpreter,
"type format add",
"Add a new formatting style for a type.",
@@ -121,7 +121,7 @@ public:
m_arguments.push_back (type_arg);
}
- ~CommandObjectTypeAdd ()
+ ~CommandObjectTypeFormatAdd ()
{
}
@@ -138,9 +138,22 @@ public:
}
const char* format_cstr = command.GetArgumentAtIndex(0);
+
+ if (!format_cstr || !format_cstr[0])
+ {
+ result.AppendError("empty format strings not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
lldb::Format format;
- Error error = Args::StringToFormat(format_cstr, format, NULL);
+ Error error;
+ error = Args::StringToFormat(format_cstr, format, NULL);
+ ValueFormat::SharedPointer entry;
+
+ entry.reset(new ValueFormat(format,m_options.m_cascade));
+
if (error.Fail())
{
result.AppendError(error.AsCString());
@@ -153,7 +166,14 @@ public:
for(int i = 1; i < argc; i++) {
const char* typeA = command.GetArgumentAtIndex(i);
ConstString typeCS(typeA);
- Debugger::AddFormatForType(typeCS, format, m_options.m_cascade);
+ if (typeCS)
+ Debugger::ValueFormats::Add(typeCS, entry);
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
}
result.SetStatus(eReturnStatusSuccessFinishNoResult);
@@ -163,7 +183,7 @@ public:
};
OptionDefinition
-CommandObjectTypeAdd::CommandOptions::g_option_table[] =
+CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_ALL, false, "cascade", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
@@ -171,13 +191,13 @@ CommandObjectTypeAdd::CommandOptions::g_option_table[] =
//-------------------------------------------------------------------------
-// CommandObjectTypeDelete
+// CommandObjectTypeFormatDelete
//-------------------------------------------------------------------------
-class CommandObjectTypeDelete : public CommandObject
+class CommandObjectTypeFormatDelete : public CommandObject
{
public:
- CommandObjectTypeDelete (CommandInterpreter &interpreter) :
+ CommandObjectTypeFormatDelete (CommandInterpreter &interpreter) :
CommandObject (interpreter,
"type format delete",
"Delete an existing formatting style for a type.",
@@ -185,17 +205,17 @@ public:
{
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);
-
+
}
- ~CommandObjectTypeDelete ()
+ ~CommandObjectTypeFormatDelete ()
{
}
@@ -214,7 +234,15 @@ public:
const char* typeA = command.GetArgumentAtIndex(0);
ConstString typeCS(typeA);
- if (Debugger::DeleteFormatForType(typeCS))
+ if(!typeCS)
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+
+ if (Debugger::ValueFormats::Delete(typeCS))
{
result.SetStatus(eReturnStatusSuccessFinishNoResult);
return result.Succeeded();
@@ -225,31 +253,60 @@ public:
result.SetStatus(eReturnStatusFailed);
return false;
}
+
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeFormatClear
+//-------------------------------------------------------------------------
+class CommandObjectTypeFormatClear : public CommandObject
+{
+public:
+ CommandObjectTypeFormatClear (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type format clear",
+ "Delete all existing format styles.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectTypeFormatClear ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+ Debugger::ValueFormats::Clear();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
}
};
//-------------------------------------------------------------------------
-// CommandObjectTypeList
+// CommandObjectTypeFormatList
//-------------------------------------------------------------------------
-bool CommandObjectTypeList_LoopCallback(void* pt2self, const char* type, lldb::Format format, bool cascade);
+bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, const char* type, const ValueFormat::SharedPointer& entry);
-class CommandObjectTypeList;
+class CommandObjectTypeFormatList;
-struct CommandObjectTypeList_LoopCallbackParam {
- CommandObjectTypeList* self;
+struct CommandObjectTypeFormatList_LoopCallbackParam {
+ CommandObjectTypeFormatList* self;
CommandReturnObject* result;
RegularExpression* regex;
- CommandObjectTypeList_LoopCallbackParam(CommandObjectTypeList* S, CommandReturnObject* R,
+ CommandObjectTypeFormatList_LoopCallbackParam(CommandObjectTypeFormatList* S, CommandReturnObject* R,
RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
};
-class CommandObjectTypeList : public CommandObject
+class CommandObjectTypeFormatList : public CommandObject
{
public:
- CommandObjectTypeList (CommandInterpreter &interpreter) :
+ CommandObjectTypeFormatList (CommandInterpreter &interpreter) :
CommandObject (interpreter,
"type format list",
"Show a list of current formatting styles.",
@@ -266,7 +323,7 @@ public:
m_arguments.push_back (type_arg);
}
- ~CommandObjectTypeList ()
+ ~CommandObjectTypeFormatList ()
{
}
@@ -275,16 +332,16 @@ public:
{
const size_t argc = command.GetArgumentCount();
- CommandObjectTypeList_LoopCallbackParam *param;
+ CommandObjectTypeFormatList_LoopCallbackParam *param;
if (argc == 1) {
RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
regex->Compile(command.GetArgumentAtIndex(0));
- param = new CommandObjectTypeList_LoopCallbackParam(this,&result,regex);
+ param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result,regex);
}
else
- param = new CommandObjectTypeList_LoopCallbackParam(this,&result);
- Debugger::LoopThroughFormatList(CommandObjectTypeList_LoopCallback, param);
+ param = new CommandObjectTypeFormatList_LoopCallbackParam(this,&result);
+ Debugger::ValueFormats::LoopThrough(CommandObjectTypeFormatList_LoopCallback, param);
delete param;
result.SetStatus(eReturnStatusSuccessFinishResult);
return result.Succeeded();
@@ -294,45 +351,438 @@ private:
bool
LoopCallback (const char* type,
- lldb::Format format,
- bool cascade,
+ const ValueFormat::SharedPointer& entry,
RegularExpression* regex,
CommandReturnObject *result)
{
if (regex == NULL || regex->Execute(type))
{
- result->GetOutputStream().Printf ("%s: %s\n", type, FormatManager::GetFormatAsCString (format));
+ result->GetOutputStream().Printf ("%s: %s%s\n", type,
+ FormatManager::GetFormatAsCString (entry->m_format),
+ entry->m_cascades ? "" : " (not cascading)");
}
return true;
}
- friend bool CommandObjectTypeList_LoopCallback(void* pt2self, const char* type, lldb::Format format, bool cascade);
+ friend bool CommandObjectTypeFormatList_LoopCallback(void* pt2self, const char* type, const ValueFormat::SharedPointer& entry);
};
bool
-CommandObjectTypeList_LoopCallback (
+CommandObjectTypeFormatList_LoopCallback (
void* pt2self,
const char* type,
- lldb::Format format,
- bool cascade)
+ const ValueFormat::SharedPointer& entry)
{
- CommandObjectTypeList_LoopCallbackParam* param = (CommandObjectTypeList_LoopCallbackParam*)pt2self;
- return param->self->LoopCallback(type, format, cascade, param->regex, param->result);
+ CommandObjectTypeFormatList_LoopCallbackParam* param = (CommandObjectTypeFormatList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type, entry, param->regex, param->result);
}
+
+
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryAdd
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSummaryAdd : 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;
+ 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 'h':
+ m_no_children = !Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid value for nochildren: %s.\n", option_arg);
+ break;
+ case 'v':
+ m_no_value = !Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid value for novalue: %s.\n", option_arg);
+ break;
+ case 'o':
+ m_one_liner = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid value for oneliner: %s.\n", option_arg);
+ break;
+ default:
+ error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
+ break;
+ }
+
+ return error;
+ }
+
+ void
+ OptionParsingStarting ()
+ {
+ m_cascade = true;
+ m_no_children = true;
+ m_no_value = false;
+ m_one_liner = 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_cascade;
+ bool m_no_children;
+ bool m_no_value;
+ bool m_one_liner;
+ };
+
+ CommandOptions m_options;
+
+ virtual Options *
+ GetOptions ()
+ {
+ return &m_options;
+ }
+
+public:
+ CommandObjectTypeSummaryAdd (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type summary add",
+ "Add a new summary style for a type.",
+ NULL), m_options (interpreter)
+ {
+ CommandArgumentEntry format_arg;
+ CommandArgumentData format_style_arg;
+ CommandArgumentEntry type_arg;
+ CommandArgumentData type_style_arg;
+
+ format_style_arg.arg_type = eArgTypeFormat;
+ format_style_arg.arg_repetition = eArgRepeatPlain;
+
+ type_style_arg.arg_type = eArgTypeName;
+ type_style_arg.arg_repetition = eArgRepeatPlus;
+
+ format_arg.push_back (format_style_arg);
+ type_arg.push_back (type_style_arg);
+
+ m_arguments.push_back (format_arg);
+ m_arguments.push_back (type_arg);
+ }
+
+ ~CommandObjectTypeSummaryAdd ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ // we support just one custom syntax: type summary add -o yes typeName
+ // anything else, must take the usual route
+ // e.g. type summary add -o yes "" type1 type2 ... typeN
+
+ bool isValidShortcut = m_options.m_one_liner && (argc == 1);
+ bool isValid = (argc >= 2);
+
+ if (!isValidShortcut && !isValid)
+ {
+ result.AppendErrorWithFormat ("%s takes two or more args.\n", m_cmd_name.c_str());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ const char* format_cstr = (isValidShortcut ? "" : command.GetArgumentAtIndex(0));
+
+ if ( (!format_cstr || !format_cstr[0]) && !m_options.m_one_liner )
+ {
+ result.AppendError("empty summary strings not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ Error error;
+
+ SummaryFormat::SharedPointer entry(new SummaryFormat(format_cstr,m_options.m_cascade,
+ m_options.m_no_children,m_options.m_no_value,
+ m_options.m_one_liner));
+
+ if (error.Fail())
+ {
+ result.AppendError(error.AsCString());
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ // now I have a valid format, let's add it to every type
+
+ for(int i = (isValidShortcut ? 0 : 1); i < argc; i++) {
+ const char* typeA = command.GetArgumentAtIndex(i);
+ ConstString typeCS(typeA);
+ if (typeCS)
+ Debugger::SummaryFormats::Add(typeCS, entry);
+ else
+ {
+ result.AppendError("empty typenames not allowed");
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+ }
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+
+};
+
+OptionDefinition
+CommandObjectTypeSummaryAdd::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, "show-children", 'h', required_argument, NULL, 0, eArgTypeBoolean, "If true, print children."},
+ { LLDB_OPT_SET_ALL, false, "show-value", 'v', required_argument, NULL, 0, eArgTypeBoolean, "If true, print value."},
+ { LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeBoolean, "If true, just print a one-line preformatted summary."},
+ { 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+};
+
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryDelete
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSummaryDelete : public CommandObject
+{
+public:
+ CommandObjectTypeSummaryDelete (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type summary delete",
+ "Delete an existing summary style for a type.",
+ NULL)
+ {
+ 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);
+
+ }
+
+ ~CommandObjectTypeSummaryDelete ()
+ {
+ }
+
+ 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 (Debugger::SummaryFormats::Delete(typeCS))
+ {
+ result.SetStatus(eReturnStatusSuccessFinishNoResult);
+ return result.Succeeded();
+ }
+ else
+ {
+ result.AppendErrorWithFormat ("no custom summary for %s.\n", typeA);
+ result.SetStatus(eReturnStatusFailed);
+ return false;
+ }
+
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryClear
+//-------------------------------------------------------------------------
+
+class CommandObjectTypeSummaryClear : public CommandObject
+{
+public:
+ CommandObjectTypeSummaryClear (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type summary clear",
+ "Delete all existing summary styles.",
+ NULL)
+ {
+ }
+
+ ~CommandObjectTypeSummaryClear ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+ Debugger::SummaryFormats::Clear();
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+};
+
+//-------------------------------------------------------------------------
+// CommandObjectTypeSummaryList
+//-------------------------------------------------------------------------
+
+bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
+
+class CommandObjectTypeSummaryList;
+
+struct CommandObjectTypeSummaryList_LoopCallbackParam {
+ CommandObjectTypeSummaryList* self;
+ CommandReturnObject* result;
+ RegularExpression* regex;
+ CommandObjectTypeSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R,
+ RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
+};
+
+class CommandObjectTypeSummaryList : public CommandObject
+{
+public:
+ CommandObjectTypeSummaryList (CommandInterpreter &interpreter) :
+ CommandObject (interpreter,
+ "type summary list",
+ "Show a list of current summary styles.",
+ NULL)
+ {
+ 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);
+ }
+
+ ~CommandObjectTypeSummaryList ()
+ {
+ }
+
+ bool
+ Execute (Args& command, CommandReturnObject &result)
+ {
+ const size_t argc = command.GetArgumentCount();
+
+ CommandObjectTypeSummaryList_LoopCallbackParam *param;
+
+ if (argc == 1) {
+ RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
+ regex->Compile(command.GetArgumentAtIndex(0));
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result,regex);
+ }
+ else
+ param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result);
+ Debugger::SummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param);
+ delete param;
+ result.SetStatus(eReturnStatusSuccessFinishResult);
+ return result.Succeeded();
+ }
+
+private:
+
+ bool
+ LoopCallback (const char* type,
+ const SummaryFormat::SharedPointer& entry,
+ RegularExpression* regex,
+ CommandReturnObject *result)
+ {
+ if (regex == NULL || regex->Execute(type))
+ {
+ result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s\n", type,
+ entry->m_format.c_str(),
+ entry->m_cascades ? "" : " (not cascading)",
+ entry->m_dont_show_children ? "" : " (show children)",
+ entry->m_dont_show_value ? "" : " (show value)",
+ entry->m_show_members_oneliner ? " (one-line printout)" : "");
+ }
+ return true;
+ }
+
+ friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
+
+};
+
+bool
+CommandObjectTypeSummaryList_LoopCallback (
+ void* pt2self,
+ const char* type,
+ const SummaryFormat::SharedPointer& entry)
+{
+ CommandObjectTypeSummaryList_LoopCallbackParam* param = (CommandObjectTypeSummaryList_LoopCallbackParam*)pt2self;
+ return param->self->LoopCallback(type, entry, param->regex, param->result);
+}
+
+
+
+
+
class CommandObjectTypeFormat : public CommandObjectMultiword
{
public:
CommandObjectTypeFormat (CommandInterpreter &interpreter) :
CommandObjectMultiword (interpreter,
"type format",
- "A set of commands for editing variable display options",
+ "A set of commands for editing variable value display options",
"type format [<sub-command-options>] ")
{
- LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeAdd (interpreter)));
- LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeDelete (interpreter)));
- LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeList (interpreter)));
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeFormatAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeFormatClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeFormatDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeFormatList (interpreter)));
}
@@ -341,6 +791,27 @@ public:
}
};
+class CommandObjectTypeSummary : public CommandObjectMultiword
+{
+public:
+ CommandObjectTypeSummary (CommandInterpreter &interpreter) :
+ CommandObjectMultiword (interpreter,
+ "type format",
+ "A set of commands for editing variable summary display options",
+ "type summary [<sub-command-options>] ")
+ {
+ LoadSubCommand ("add", CommandObjectSP (new CommandObjectTypeSummaryAdd (interpreter)));
+ LoadSubCommand ("clear", CommandObjectSP (new CommandObjectTypeSummaryClear (interpreter)));
+ LoadSubCommand ("delete", CommandObjectSP (new CommandObjectTypeSummaryDelete (interpreter)));
+ LoadSubCommand ("list", CommandObjectSP (new CommandObjectTypeSummaryList (interpreter)));
+ }
+
+
+ ~CommandObjectTypeSummary ()
+ {
+ }
+};
+
//-------------------------------------------------------------------------
// CommandObjectType
//-------------------------------------------------------------------------
@@ -352,6 +823,7 @@ CommandObjectType::CommandObjectType (CommandInterpreter &interpreter) :
"type [<sub-command-options>]")
{
LoadSubCommand ("format", CommandObjectSP (new CommandObjectTypeFormat (interpreter)));
+ LoadSubCommand ("summary", CommandObjectSP (new CommandObjectTypeSummary (interpreter)));
}
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 7ab7a7728d7..fadeafdf813 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -11,6 +11,9 @@
#include <map>
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/Type.h"
+
#include "lldb/lldb-private.h"
#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/FormatManager.h"
@@ -20,6 +23,7 @@
#include "lldb/Core/StreamAsynchronousIO.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/Timer.h"
+#include "lldb/Core/ValueObject.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Target/TargetList.h"
@@ -698,13 +702,20 @@ Debugger::FormatPrompt
const ExecutionContext *exe_ctx,
const Address *addr,
Stream &s,
- const char **end
+ const char **end,
+ ValueObject* vobj
)
{
+ ValueObject* realvobj = NULL; // makes it super-easy to parse pointers
bool success = true;
const char *p;
for (p = format; *p != '\0'; ++p)
{
+ if(realvobj)
+ {
+ vobj = realvobj;
+ realvobj = NULL;
+ }
size_t non_special_chars = ::strcspn (p, "${}\\");
if (non_special_chars > 0)
{
@@ -732,7 +743,7 @@ Debugger::FormatPrompt
++p; // Skip the '{'
- if (FormatPrompt (p, sc, exe_ctx, addr, sub_strm, &p))
+ if (FormatPrompt (p, sc, exe_ctx, addr, sub_strm, &p, vobj))
{
// The stream had all it needed
s.Write(sub_strm.GetData(), sub_strm.GetSize());
@@ -777,6 +788,284 @@ Debugger::FormatPrompt
bool var_success = false;
switch (var_name_begin[0])
{
+ case '*':
+ {
+ if (!vobj) break;
+ var_name_begin++;
+ lldb::clang_type_t pointer_clang_type = vobj->GetClangType();
+ clang_type_t elem_or_pointee_clang_type;
+ const Flags type_flags (ClangASTContext::GetTypeInfo (pointer_clang_type,
+ vobj->GetClangAST(),
+ &elem_or_pointee_clang_type));
+ if (type_flags.Test (ClangASTContext::eTypeIsPointer))
+ {
+ if (ClangASTContext::IsCharType (elem_or_pointee_clang_type))
+ {
+ StreamString sstr;
+ ExecutionContextScope *exe_scope = vobj->GetExecutionContextScope();
+ Process *process = exe_scope->CalculateProcess();
+ if(!process) break;
+ lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS;
+ AddressType cstr_address_type = eAddressTypeInvalid;
+ DataExtractor data;
+ size_t bytes_read = 0;
+ std::vector<char> data_buffer;
+ Error error;
+ cstr_address = vobj->GetPointerValue (cstr_address_type, true);
+ {
+ const size_t k_max_buf_size = 256;
+ data_buffer.resize (k_max_buf_size + 1);
+ // NULL terminate in case we don't get the entire C string
+ data_buffer.back() = '\0';
+
+ sstr << '"';
+
+ data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder());
+ while ((bytes_read = process->ReadMemory (cstr_address, &data_buffer.front(), k_max_buf_size, error)) > 0)
+ {
+ size_t len = strlen(&data_buffer.front());
+ if (len == 0)
+ break;
+ if (len > bytes_read)
+ len = bytes_read;
+
+ data.Dump (&sstr,
+ 0, // Start offset in "data"
+ eFormatCharArray, // Print as characters
+ 1, // Size of item (1 byte for a char!)
+ len, // How many bytes to print?
+ UINT32_MAX, // num per line
+ LLDB_INVALID_ADDRESS,// base address
+ 0, // bitfield bit size
+ 0); // bitfield bit offset
+
+ if (len < k_max_buf_size)
+ break;
+ cstr_address += k_max_buf_size;
+ }
+ sstr << '"';
+ s.PutCString(sstr.GetData());
+ var_success = true;
+ break;
+ }
+ }
+ else /*if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type)) or this is some other pointer type*/
+ {
+ Error error;
+ realvobj = vobj;
+ vobj = vobj->Dereference(error).get();
+ if(!vobj || error.Fail())
+ break;
+ }
+ }
+ else
+ break;
+ }
+ case 'v':
+ {
+ const char* targetvalue;
+ bool use_summary = false;
+ ValueObject* target;
+ lldb::Format custom_format = eFormatInvalid;
+ int bitfield_lower = -1;
+ int bitfield_higher = -1;
+ if (!vobj) break;
+ // simplest case ${var}, just print vobj's value
+ if (::strncmp (var_name_begin, "var}", strlen("var}")) == 0)
+ target = vobj;
+ else if (::strncmp(var_name_begin,"var%",strlen("var%")) == 0)
+ {
+ // this is a variable with some custom format applied to it
+ const char* var_name_final;
+ target = vobj;
+ {
+ const char* percent_position = ::strchr(var_name_begin,'%'); // TODO: make this a constant
+ //if(!percent_position || percent_position > var_name_end)
+ // var_name_final = var_name_end;
+ //else
+ //{
+ var_name_final = percent_position;
+ char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
+ memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
+ FormatManager::GetFormatFromCString(format_name,
+ true,
+ custom_format); // if this fails, custom_format is reset to invalid
+ delete format_name;
+ //}
+ }
+ }
+ else if (::strncmp(var_name_begin,"var[",strlen("var[")) == 0)
+ {
+ // this is a bitfield variable
+ const char *var_name_final;
+ target = vobj;
+
+ {
+ const char* percent_position = ::strchr(var_name_begin,'%');
+ if(!percent_position || percent_position > var_name_end)
+ var_name_final = var_name_end;
+ else
+ {
+ var_name_final = percent_position;
+ char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
+ memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
+ FormatManager::GetFormatFromCString(format_name,
+ true,
+ custom_format); // if this fails, custom_format is reset to invalid
+ delete format_name;
+ }
+ }
+
+ {
+ // code here might be simpler than in the case below
+ const char* open_bracket_position = ::strchr(var_name_begin,'[');
+ if(open_bracket_position && open_bracket_position < var_name_final)
+ {
+ char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
+ char* close_bracket_position = ::strchr(open_bracket_position,']');
+ // as usual, we assume that [] will come before %
+ //printf("trying to expand a []\n");
+ var_name_final = open_bracket_position;
+ if (separator_position == NULL || separator_position > var_name_end)
+ {
+ char *end = NULL;
+ bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0);
+ bitfield_higher = bitfield_lower;
+ //printf("got to read low=%d high same\n",bitfield_lower);
+ }
+ else if(close_bracket_position && close_bracket_position < var_name_end)
+ {
+ char *end = NULL;
+ bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0);
+ bitfield_higher = ::strtoul (separator_position+1, &end, 0);
+ //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher);
+ }
+ else
+ break;
+ if(bitfield_lower > bitfield_higher)
+ break;
+ }
+ }
+ }
+ // this is ${var.something} or multiple .something nested
+ else if (::strncmp (var_name_begin, "var", strlen("var")) == 0)
+ {
+ // check for custom format string
+
+ // we need this because we might have ${var.something%format}. in this case var_name_end
+ // still points to the closing }, but we must extract the variable name only up to
+ // before the %. var_name_final will point to that % sign position
+ const char* var_name_final;
+
+ {
+ const char* percent_position = ::strchr(var_name_begin,'%');
+ if(!percent_position || percent_position > var_name_end)
+ var_name_final = var_name_end;
+ else
+ {
+ var_name_final = percent_position;
+ char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
+ memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
+ FormatManager::GetFormatFromCString(format_name,
+ true,
+ custom_format); // if this fails, custom_format is reset to invalid
+ delete format_name;
+ }
+ }
+
+ {
+ const char* open_bracket_position = ::strchr(var_name_begin,'[');
+ if(open_bracket_position && open_bracket_position < var_name_final)
+ {
+ char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
+ char* close_bracket_position = ::strchr(open_bracket_position,']');
+ // as usual, we assume that [] will come before %
+ //printf("trying to expand a []\n");
+ var_name_final = open_bracket_position;
+ if (separator_position == NULL || separator_position > var_name_end)
+ {
+ char *end = NULL;
+ bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0);
+ bitfield_higher = bitfield_lower;
+ //printf("got to read low=%d high same\n",bitfield_lower);
+ }
+ else if(close_bracket_position && close_bracket_position < var_name_end)
+ {
+ char *end = NULL;
+ bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0);
+ bitfield_higher = ::strtoul (separator_position+1, &end, 0);
+ //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher);
+ }
+ else
+ break;
+ if(bitfield_lower > bitfield_higher)
+ break;
+ //*((char*)open_bracket_position) = '\0';
+ //printf("variable name is %s\n",var_name_begin);
+ //*((char*)open_bracket_position) = '[';
+ }
+ }
+
+ Error error;
+ lldb::VariableSP var_sp;
+ StreamString sstring;
+ vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers);
+ //printf("name to expand in phase 0: %s\n",sstring.GetData());
+ sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3);
+ //printf("name to expand in phase 1: %s\n",sstring.GetData());
+ std::string name = std::string(sstring.GetData());
+ target = exe_ctx->frame->GetValueForVariableExpressionPath (name.c_str(),
+ eNoDynamicValues,
+ 0,
+ var_sp,
+ error).get();
+ if (error.Fail())
+ {
+ //printf("ERROR: %s\n",error.AsCString("unknown"));
+ break;
+ }
+ }
+ else
+ break;
+ if(*(var_name_end+1)=='s')
+ {
+ use_summary = true;
+ var_name_end++;
+ }
+ if (bitfield_lower >= 0)
+ {
+ //printf("trying to print a []\n");
+ // format this as a bitfield
+ DataExtractor extractor = target->GetDataExtractor();
+ uint32_t item_byte_size = ClangASTType::GetTypeByteSize(target->GetClangAST(), target->GetClangType());
+ if(custom_format == eFormatInvalid)
+ custom_format = eFormatHex;
+ var_success =
+ extractor.Dump(&s, 0, custom_format, item_byte_size, 1, 1, LLDB_INVALID_ADDRESS, bitfield_higher-bitfield_lower+1, bitfield_lower) > 0;
+ //printf("var_success = %s\n",var_success ? "true" : "false");
+ }
+ else
+ {
+ //printf("here I come 1\n");
+ // format this as usual
+ if(custom_format != eFormatInvalid)
+ target->SetFormat(custom_format);
+ //printf("here I come 2\n");
+ if(!use_summary)
+ targetvalue = target->GetValueAsCString();
+ else
+ targetvalue = target->GetSummaryAsCString();
+ //printf("here I come 3\n");
+ if(targetvalue)
+ s.PutCString(targetvalue);
+ var_success = targetvalue;
+ //printf("here I come 4 : %s\n",var_success ? "good" : "bad");
+ if(custom_format != eFormatInvalid)
+ target->SetFormat(eFormatDefault);
+ //printf("here I come 5\n");
+ }
+ break;
+ }
case 'a':
if (::strncmp (var_name_begin, "addr}", strlen("addr}")) == 0)
{
@@ -1321,27 +1610,76 @@ GetFormatManager() {
}
bool
-Debugger::GetFormatForType (const ConstString &type, lldb::Format& format, bool& cascade)
+Debugger::ValueFormats::Get(ValueObject& vobj, ValueFormat::SharedPointer &entry)
+{
+ return GetFormatManager().Value().Get(vobj,entry);
+}
+
+void
+Debugger::ValueFormats::Add(const ConstString &type, const ValueFormat::SharedPointer &entry)
+{
+ GetFormatManager().Value().Add(type.AsCString(),entry);
+}
+
+bool
+Debugger::ValueFormats::Delete(const ConstString &type)
+{
+ return GetFormatManager().Value().Delete(type.AsCString());
+}
+
+void
+Debugger::ValueFormats::Clear()
+{
+ GetFormatManager().Value().Clear();
+}
+
+void
+Debugger::ValueFormats::LoopThrough(FormatManager::ValueCallback callback, void* callback_baton)
+{
+ GetFormatManager().Value().LoopThrough(callback, callback_baton);
+}
+
+uint32_t
+Debugger::ValueFormats::GetCurrentRevision()
+{
+ return GetFormatManager().GetCurrentRevision();
+}
+
+
+bool
+Debugger::SummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry)
{
- return GetFormatManager().GetFormatForType(type, format, cascade);
+ return GetFormatManager().Summary().Get(vobj,entry);
}
void
-Debugger::AddFormatForType (const ConstString &type, lldb::Format format, bool cascade)
+Debugger::SummaryFormats::Add(const ConstString &type, const SummaryFormat::SharedPointer &entry)
{
- GetFormatManager().AddFormatForType(type,format, cascade);
+ GetFormatManager().Summary().Add(type.AsCString(),entry);
}
bool
-Debugger::DeleteFormatForType (const ConstString &type)
+Debugger::SummaryFormats::Delete(const ConstString &type)
+{
+ return GetFormatManager().Summary().Delete(type.AsCString());
+}
+
+void
+Debugger::SummaryFormats::Clear()
{
- return GetFormatManager().DeleteFormatForType(type);
+ GetFormatManager().Summary().Clear();
}
void
-Debugger::LoopThroughFormatList (FormatManager::Callback callback, void* callback_baton)
+Debugger::SummaryFormats::LoopThrough(FormatManager::SummaryCallback callback, void* callback_baton)
+{
+ GetFormatManager().Summary().LoopThrough(callback, callback_baton);
+}
+
+uint32_t
+Debugger::SummaryFormats::GetCurrentRevision()
{
- return GetFormatManager().LoopThroughFormatList(callback, callback_baton);
+ return GetFormatManager().GetCurrentRevision();
}
#pragma mark Debugger::SettingsController
diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp
index 72503842387..8f8a60d3b49 100644
--- a/lldb/source/Core/FormatManager.cpp
+++ b/lldb/source/Core/FormatManager.cpp
@@ -151,61 +151,3 @@ FormatManager::GetFormatAsCString (Format format)
return g_format_infos[format].format_name;
return NULL;
}
-
-bool
-FormatManager::GetFormatForType (const ConstString &type_name, lldb::Format& format, bool& cascade)
-{
- Mutex::Locker locker (m_format_map_mutex);
- FormatMap& fmtmap = m_format_map;
- FormatMap::iterator iter = fmtmap.find(type_name.GetCString());
- if(iter == fmtmap.end())
- return false;
- else {
- format = iter->second.format;
- cascade = iter->second.cascades;
- return true;
- }
-}
-
-void
-FormatManager::AddFormatForType (const ConstString &type_name, lldb::Format format, bool cascade)
-{
- Entry entry(format, cascade);
- Mutex::Locker locker (m_format_map_mutex);
- FormatMap& fmtmap = m_format_map;
- fmtmap[type_name.GetCString()] = entry;
-}
-
-bool
-FormatManager::DeleteFormatForType (const ConstString &type_name)
-{
- Mutex::Locker locker (m_format_map_mutex);
- FormatMap& fmtmap = m_format_map;
- const char* typeCS = type_name.GetCString();
- FormatMap::iterator iter = fmtmap.find(typeCS);
- if (iter != fmtmap.end())
- {
- fmtmap.erase(typeCS);
- return true;
- }
- return false;
-}
-
-void
-FormatManager::LoopThroughFormatList (Callback callback, void* param)
-{
- if (callback)
- {
- Mutex::Locker locker (m_format_map_mutex);
- FormatIterator pos, end = m_format_map.end();
- for (pos = m_format_map.begin(); pos != end; ++pos)
- {
- const char* type = pos->first;
- lldb::Format format = pos->second.format;
- bool cascade = pos->second.cascades;
- if (!callback(param, type, format, cascade))
- break;
- }
- }
-}
-
diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index c4bfc3c126c..5177600b0fe 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/source/Core/ValueObject.cpp
@@ -19,6 +19,7 @@
// Project includes
#include "lldb/Core/DataBufferHeap.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectChild.h"
#include "lldb/Core/ValueObjectConstResult.h"
@@ -71,7 +72,10 @@ ValueObject::ValueObject (ValueObject &parent) :
m_children_count_valid (false),
m_old_value_valid (false),
m_pointers_point_to_load_addrs (false),
- m_is_deref_of_parent (false)
+ m_is_deref_of_parent (false),
+ m_last_format_mgr_revision(0),
+ m_last_summary_format(),
+ m_last_value_format()
{
m_manager->ManageObject(this);
}
@@ -103,7 +107,10 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
m_children_count_valid (false),
m_old_value_valid (false),
m_pointers_point_to_load_addrs (false),
- m_is_deref_of_parent (false)
+ m_is_deref_of_parent (false),
+ m_last_format_mgr_revision(0),
+ m_last_summary_format(),
+ m_last_value_format()
{
m_manager = new ValueObjectManager();
m_manager->ManageObject (this);
@@ -119,6 +126,9 @@ ValueObject::~ValueObject ()
bool
ValueObject::UpdateValueIfNeeded ()
{
+
+ UpdateFormatsIfNeeded();
+
// If this is a constant value, then our success is predicated on whether
// we have an error or not
if (GetIsConstant())
@@ -168,6 +178,26 @@ ValueObject::UpdateValueIfNeeded ()
return m_error.Success();
}
+void
+ValueObject::UpdateFormatsIfNeeded()
+{
+ /*printf("CHECKING FOR UPDATES. I am at revision %d, while the format manager is at revision %d\n",
+ m_last_format_mgr_revision,
+ Debugger::ValueFormats::GetCurrentRevision());*/
+ if (m_last_format_mgr_revision != Debugger::ValueFormats::GetCurrentRevision())
+ {
+ if (m_last_summary_format.get())
+ m_last_summary_format.reset((SummaryFormat*)NULL);
+ if (m_last_value_format.get())
+ m_last_value_format.reset((ValueFormat*)NULL);
+ Debugger::ValueFormats::Get(*this, m_last_value_format);
+ Debugger::SummaryFormats::Get(*this, m_last_summary_format);
+ m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision();
+ m_value_str.clear();
+ m_summary_str.clear();
+ }
+}
+
DataExtractor &
ValueObject::GetDataExtractor ()
{
@@ -454,9 +484,23 @@ const char *
ValueObject::GetSummaryAsCString ()
{
if (UpdateValueIfNeeded ())
- {
+ {
if (m_summary_str.empty())
{
+ if (m_last_summary_format.get())
+ {
+ StreamString s;
+ ExecutionContext exe_ctx;
+ this->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
+ SymbolContext sc = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything);
+ if (Debugger::FormatPrompt(m_last_summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
+ {
+ m_summary_str.swap(s.GetString());
+ return m_summary_str.c_str();
+ }
+ return NULL;
+ }
+
clang_type_t clang_type = GetClangType();
// See if this is a pointer to a C string?
@@ -664,28 +708,6 @@ ValueObject::GetValueAsCString ()
{
if (UpdateValueIfNeeded())
{
- /*
- this is a quick fix for the case in which we display a variable, then change its format with
- type format add and the old display string keeps showing until one steps through the code
- */
- {
- const Value::ContextType context_type = m_value.GetContextType();
- switch (context_type)
- {
- case Value::eContextTypeClangType:
- case Value::eContextTypeLLDBType:
- case Value::eContextTypeVariable:
- {
- Format format = GetFormat();
- if (format != m_last_format)
- m_value_str.clear();
- }
- break;
-
- default:
- break;
- }
- }
if (m_value_str.empty())
{
const Value::ContextType context_type = m_value.GetContextType();
@@ -701,13 +723,18 @@ ValueObject::GetValueAsCString ()
{
StreamString sstr;
Format format = GetFormat();
- if (format == eFormatDefault)
- format = ClangASTType::GetFormat(clang_type);
+ if (format == eFormatDefault)
+ {
+ if (m_last_value_format)
+ format = m_last_value_format->m_format;
+ else
+ format = ClangASTType::GetFormat(clang_type);
+ }
if (ClangASTType::DumpTypeValue (GetClangAST(), // The clang AST
clang_type, // The clang type to display
&sstr,
- m_last_format = format, // Format to display this type with
+ format, // Format to display this type with
m_data, // Data to extract from
0, // Byte offset into "m_data"
GetByteSize(), // Byte size of item in "m_data"
@@ -1123,16 +1150,22 @@ ValueObject::GetNonBaseClassParent()
}
void
-ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes)
+ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat epformat)
{
const bool is_deref_of_parent = IsDereferenceOfParent ();
-
- if (is_deref_of_parent)
- s.PutCString("*(");
- if (GetParent())
- GetParent()->GetExpressionPath (s, qualify_cxx_base_classes);
+ if(is_deref_of_parent && epformat == eDereferencePointers) {
+ // this is the original format of GetExpressionPath() producing code like *(a_ptr).memberName, which is entirely
+ // fine, until you put this into StackFrame::GetValueForVariableExpressionPath() which prefers to see a_ptr->memberName.
+ // the eHonorPointers mode is meant to produce strings in this latter format
+ s.PutCString("*(");
+ }
+
+ ValueObject* parent = GetParent();
+ if (parent)
+ parent->GetExpressionPath (s, qualify_cxx_base_classes, epformat);
+
if (!IsBaseClass())
{
if (!is_deref_of_parent)
@@ -1145,14 +1178,21 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes)
{
const uint32_t non_base_class_parent_type_info = ClangASTContext::GetTypeInfo (non_base_class_parent_clang_type, NULL, NULL);
- if (non_base_class_parent_type_info & ClangASTContext::eTypeIsPointer)
+ if(parent && parent->IsDereferenceOfParent() && epformat == eHonorPointers)
{
s.PutCString("->");
}
- else if ((non_base_class_parent_type_info & ClangASTContext::eTypeHasChildren) &&
- !(non_base_class_parent_type_info & ClangASTContext::eTypeIsArray))
- {
- s.PutChar('.');
+ else
+ {
+ if (non_base_class_parent_type_info & ClangASTContext::eTypeIsPointer)
+ {
+ s.PutCString("->");
+ }
+ else if ((non_base_class_parent_type_info & ClangASTContext::eTypeHasChildren) &&
+ !(non_base_class_parent_type_info & ClangASTContext::eTypeIsArray))
+ {
+ s.PutChar('.');
+ }
}
}
}
@@ -1170,8 +1210,9 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes)
}
}
- if (is_deref_of_parent)
+ if (is_deref_of_parent && epformat == eDereferencePointers) {
s.PutChar(')');
+ }
}
void
@@ -1245,6 +1286,8 @@ ValueObject::DumpValueObject
}
const char *val_cstr = NULL;
+ const char *sum_cstr = NULL;
+ SummaryFormat* entry = valobj->m_last_summary_format.get();
if (err_cstr == NULL)
{
@@ -1261,10 +1304,13 @@ ValueObject::DumpValueObject
const bool is_ref = type_flags.Test (ClangASTContext::eTypeIsReference);
if (print_valobj)
{
- const char *sum_cstr = valobj->GetSummaryAsCString();
+
+ sum_cstr = valobj->GetSummaryAsCString();
- if (val_cstr)
- s.Printf(" %s", val_cstr);
+ // We must calculate this value in realtime because entry might alter this variable's value
+ // (e.g. by saying ${var%fmt}) and render precached values useless
+ if (val_cstr && (!entry || entry->DoesPrintValue() || !sum_cstr))
+ s.Printf(" %s", valobj->GetValueAsCString());
if (sum_cstr)
s.Printf(" %s", sum_cstr);
@@ -1314,7 +1360,32 @@ ValueObject::DumpValueObject
print_children = false;
}
- if (print_children)
+ if (entry && entry->IsOneliner())
+ {
+ const uint32_t num_children = valobj->GetNumChildren();
+ if (num_children)
+ {
+
+ s.PutChar('(');
+
+ for (uint32_t idx=0; idx<num_children; ++idx)
+ {
+ ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
+ if (child_sp.get())
+ {
+ if (idx)
+ s.PutCString(", ");
+ s.PutCString(child_sp.get()->GetName().AsCString());
+ s.PutChar('=');
+ s.PutCString(child_sp.get()->GetValueAsCString());
+ }
+ }
+
+ s.PutChar(')');
+ s.EOL();
+ }
+ }
+ else if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
{
const uint32_t num_children = valobj->GetNumChildren();
if (num_children)
diff --git a/lldb/source/Symbol/ClangASTType.cpp b/lldb/source/Symbol/ClangASTType.cpp
index 9b862d191c4..53011f00fb4 100644
--- a/lldb/source/Symbol/ClangASTType.cpp
+++ b/lldb/source/Symbol/ClangASTType.cpp
@@ -247,25 +247,8 @@ ClangASTType::GetFormat ()
lldb::Format
ClangASTType::GetFormat (clang_type_t clang_type)
{
- // first of all, check for a valid format for this type itself
clang::QualType qual_type(clang::QualType::getFromOpaquePtr(clang_type));
- lldb::Format format;
- bool cascade;
- if(Debugger::GetFormatForType(GetClangTypeName(qual_type), format, cascade))
- return format; // return it if found
-
- // here, I know this type does not have a direct format. two things can happen:
- // 1) this is a typedef - I expand this to its parent type and look there
- // 2) this is not a typedef - I use the default formatting options
- const clang::TypedefType *typedef_type = qual_type->getAs<clang::TypedefType>();
- while (typedef_type) {
- qual_type = typedef_type->getDecl()->getUnderlyingType();
- std::string name = qual_type.getAsString();
- if(Debugger::GetFormatForType(GetClangTypeName(qual_type), format, cascade) && cascade) // if I have a cascading format...
- return format; // ...use it
- typedef_type = qual_type->getAs<clang::TypedefType>(); // try to expand another level
- }
-
+
switch (qual_type->getTypeClass())
{
case clang::Type::FunctionNoProto:
@@ -1347,6 +1330,23 @@ ClangASTType::ReadFromMemory
data);
}
+uint32_t
+ClangASTType::GetTypeByteSize()
+{
+ return GetTypeByteSize(m_ast,
+ m_type);
+}
+
+uint32_t
+ClangASTType::GetTypeByteSize(
+ clang::ASTContext *ast_context,
+ lldb::clang_type_t opaque_clang_qual_type)
+{
+ clang::QualType qual_type(clang::QualType::getFromOpaquePtr(opaque_clang_qual_type));
+
+ return (ast_context->getTypeSize (qual_type) + 7) / 8;
+}
+
bool
ClangASTType::ReadFromMemory
diff --git a/lldb/test/functionalities/data-formatter/TestDataFormatter.py b/lldb/test/functionalities/data-formatter/TestDataFormatter.py
index b88c6fc8af2..48947f427d4 100644
--- a/lldb/test/functionalities/data-formatter/TestDataFormatter.py
+++ b/lldb/test/functionalities/data-formatter/TestDataFormatter.py
@@ -51,11 +51,8 @@ class DataFormatterTestCase(TestBase):
# 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 delete Speed', check=False)
- self.runCmd('type format delete Bitfield', check=False)
- self.runCmd('type format delete RealNumber', check=False)
- self.runCmd('type format delete Type2', check=False)
- self.runCmd('type format delete Type1', check=False)
+ self.runCmd('type format clear', check=False)
+ self.runCmd('type summary clear', check=False)
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
@@ -87,6 +84,33 @@ class DataFormatterTestCase(TestBase):
# Delete type format for 'Speed', we should expect an error message.
self.expect("type format delete Speed", error=True,
substrs = ['no custom format for Speed'])
+
+ # For some reason the type system is calling this "struct"
+ self.runCmd("type summary add -o yes \"\" Point")
+
+ self.expect("frame variable iAmSomewhere",
+ substrs = ['x=4',
+ 'y=6'])
+
+ self.expect("type summary list",
+ substrs = ['Point',
+ 'one-line'])
+
+ self.runCmd("type summary add \"y=${var.y%x}\" Point")
+
+ self.expect("frame variable iAmSomewhere",
+ substrs = ['y=0x'])
+
+ self.runCmd("type summary add \"hello\" Point -h yes")
+
+ self.expect("type summary list",
+ substrs = ['Point',
+ 'show children'])
+
+ self.expect("frame variable iAmSomewhere",
+ substrs = ['hello',
+ 'x = 4',
+ '}'])
if __name__ == '__main__':
diff --git a/lldb/test/functionalities/data-formatter/main.cpp b/lldb/test/functionalities/data-formatter/main.cpp
index 5413bbd291e..94e2993ed90 100644
--- a/lldb/test/functionalities/data-formatter/main.cpp
+++ b/lldb/test/functionalities/data-formatter/main.cpp
@@ -31,6 +31,12 @@ typedef Type3 Type4; // should show as char
typedef int ChildType; // should show as int
typedef int AnotherChildType; // should show as int
+struct Point {
+ int x;
+ int y;
+ Point(int X = 3, int Y = 2) : x(X), y(Y) {}
+};
+
int main (int argc, const char * argv[])
{
@@ -57,6 +63,8 @@ int main (int argc, const char * argv[])
Speed* SPPtrILookHex = new Speed(16);
+ Point iAmSomewhere(4,6);
+
return 0; // Set break point at this line.
}
OpenPOWER on IntegriCloud