Provide synthetic children for some vector types

Unlike GDB, we tackle the problem of representing vector types in different styles by having a synthetic child provider that recognizes the format you're trying to apply to the variable, and coming up with the right type and number of child values to match that format

This makes for a more compact representation and less visual noise

Fixes rdar://5429347

llvm-svn: 231449
This commit is contained in:
Enrico Granata 2015-03-06 03:32:20 +00:00
parent d07b2b4228
commit 0ddbf3633c
10 changed files with 384 additions and 1 deletions

View File

@ -864,7 +864,7 @@ public:
lldb::Format
GetFormat () const;
void
virtual void
SetFormat (lldb::Format format)
{
if (format != m_format)

View File

@ -143,6 +143,14 @@ public:
virtual bool
SetValueFromCString (const char *value_str, Error& error);
virtual void
SetFormat (lldb::Format format)
{
if (m_parent)
m_parent->SetFormat(format);
this->ValueObject::SetFormat(format);
}
protected:
virtual bool
UpdateValue ();

View File

@ -398,6 +398,7 @@ namespace lldb_private {
SyntheticChildrenFrontEnd* LibcxxInitializerListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
SyntheticChildrenFrontEnd* VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
} // namespace formatters
} // namespace lldb_private

View File

@ -758,6 +758,7 @@
940B04E11A89860E0045D5F7 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 940B04E01A89860E0045D5F7 /* libedit.dylib */; };
940B04E41A8987680045D5F7 /* argdumper in CopyFiles */ = {isa = PBXBuildFile; fileRef = 942829C01A89835300521B30 /* argdumper */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
94145431175E63B500284436 /* lldb-versioning.h in Headers */ = {isa = PBXBuildFile; fileRef = 94145430175D7FDE00284436 /* lldb-versioning.h */; settings = {ATTRIBUTES = (Public, ); }; };
9418EBCD1AA910910058B02E /* VectorType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9418EBCC1AA910910058B02E /* VectorType.cpp */; };
941BCC7F14E48C4000BB969C /* SBTypeFilter.h in Headers */ = {isa = PBXBuildFile; fileRef = 9461568614E355F2003A195C /* SBTypeFilter.h */; settings = {ATTRIBUTES = (Public, ); }; };
941BCC8014E48C4000BB969C /* SBTypeFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = 9461568714E355F2003A195C /* SBTypeFormat.h */; settings = {ATTRIBUTES = (Public, ); }; };
941BCC8114E48C4000BB969C /* SBTypeSummary.h in Headers */ = {isa = PBXBuildFile; fileRef = 9461568814E355F2003A195C /* SBTypeSummary.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -2387,6 +2388,8 @@
940B04DE1A8986070045D5F7 /* libncurses.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libncurses.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libncurses.dylib; sourceTree = DEVELOPER_DIR; };
940B04E01A89860E0045D5F7 /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libedit.dylib; sourceTree = DEVELOPER_DIR; };
94145430175D7FDE00284436 /* lldb-versioning.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "lldb-versioning.h"; path = "include/lldb/lldb-versioning.h"; sourceTree = "<group>"; };
9418EBCB1AA9108B0058B02E /* VectorType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = VectorType.h; path = include/lldb/DataFormatters/VectorType.h; sourceTree = "<group>"; };
9418EBCC1AA910910058B02E /* VectorType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VectorType.cpp; path = source/DataFormatters/VectorType.cpp; sourceTree = "<group>"; };
94235B9A1A8D5FD800EB2EED /* SBVariablesOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = SBVariablesOptions.h; path = include/lldb/API/SBVariablesOptions.h; sourceTree = "<group>"; };
94235B9B1A8D5FF300EB2EED /* SBVariablesOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBVariablesOptions.cpp; path = source/API/SBVariablesOptions.cpp; sourceTree = "<group>"; };
94235B9D1A8D601A00EB2EED /* SBVariablesOptions.i */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBVariablesOptions.i; sourceTree = "<group>"; };
@ -5037,6 +5040,8 @@
94CD131919BA33B400DB7BED /* TypeValidator.cpp */,
945215DD17F639E600521C0B /* ValueObjectPrinter.h */,
945215DE17F639EE00521C0B /* ValueObjectPrinter.cpp */,
9418EBCB1AA9108B0058B02E /* VectorType.h */,
9418EBCC1AA910910058B02E /* VectorType.cpp */,
);
name = DataFormatters;
sourceTree = "<group>";
@ -5977,6 +5982,7 @@
94BA8B70176F97CE005A91B5 /* CommandHistory.cpp in Sources */,
2689007713353E1A00698AC0 /* CFCData.cpp in Sources */,
2689007813353E1A00698AC0 /* CFCMutableArray.cpp in Sources */,
9418EBCD1AA910910058B02E /* VectorType.cpp in Sources */,
2689007913353E1A00698AC0 /* CFCMutableDictionary.cpp in Sources */,
2689007A13353E1A00698AC0 /* CFCMutableSet.cpp in Sources */,
2689007B13353E1A00698AC0 /* CFCString.cpp in Sources */,

View File

@ -1216,6 +1216,15 @@ FormatManager::LoadSystemFormatters()
AddFormat(sys_category_sp, lldb::eFormatOSType, ConstString("FourCharCode"), fourchar_flags);
SyntheticChildren::Flags synth_flags;
synth_flags.SetCascades(true).SetSkipPointers(true).SetSkipReferences(true);
AddCXXSynthetic(sys_category_sp,
lldb_private::formatters::VectorTypeSyntheticFrontEndCreator,
"vector_type synthetic children",
ConstString("unsigned char __attribute__\\(\\(ext_vector_type\\([0-9]+\\)\\)\\)"),
synth_flags,
true);
#endif
}

View File

@ -0,0 +1,259 @@
//===-- VectorType.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/DataFormatters/CXXFormatterFunctions.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Utility/LLDBAssert.h"
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::formatters;
static ClangASTType
GetClangTypeForFormat (lldb::Format format,
ClangASTContext *ast_ctx)
{
lldbassert(ast_ctx && "ast_ctx needs to be not NULL");
switch (format)
{
case lldb::eFormatAddressInfo:
case lldb::eFormatPointer:
return ast_ctx->GetPointerSizedIntType(false);
case lldb::eFormatBoolean:
return ast_ctx->GetBasicType(lldb::eBasicTypeBool);
case lldb::eFormatBytes:
case lldb::eFormatBytesWithASCII:
case lldb::eFormatChar:
case lldb::eFormatCharArray:
case lldb::eFormatCharPrintable:
return ast_ctx->GetBasicType(lldb::eBasicTypeChar);
case lldb::eFormatComplex /* lldb::eFormatComplexFloat */:
return ast_ctx->GetBasicType(lldb::eBasicTypeFloatComplex);
case lldb::eFormatCString:
return ast_ctx->GetBasicType(lldb::eBasicTypeChar).GetPointerType();
case lldb::eFormatFloat:
return ast_ctx->GetBasicType(lldb::eBasicTypeFloat);
case lldb::eFormatHex:
case lldb::eFormatHexUppercase:
case lldb::eFormatOctal:
return ast_ctx->GetBasicType(lldb::eBasicTypeInt);
case lldb::eFormatHexFloat:
return ast_ctx->GetBasicType(lldb::eBasicTypeFloat);
case lldb::eFormatUnicode16:
case lldb::eFormatUnicode32:
case lldb::eFormatUnsigned:
return ast_ctx->GetBasicType(lldb::eBasicTypeUnsignedInt);
case lldb::eFormatVectorOfChar:
return ast_ctx->GetBasicType(lldb::eBasicTypeChar);
case lldb::eFormatVectorOfFloat32:
return ast_ctx->GetFloatTypeFromBitSize(32);
case lldb::eFormatVectorOfFloat64:
return ast_ctx->GetFloatTypeFromBitSize(64);
case lldb::eFormatVectorOfSInt16:
return ast_ctx->GetIntTypeFromBitSize(16, true);
case lldb::eFormatVectorOfSInt32:
return ast_ctx->GetIntTypeFromBitSize(32, true);
case lldb::eFormatVectorOfSInt64:
return ast_ctx->GetIntTypeFromBitSize(64, true);
case lldb::eFormatVectorOfSInt8:
return ast_ctx->GetIntTypeFromBitSize(8, true);
case lldb::eFormatVectorOfUInt128:
return ast_ctx->GetIntTypeFromBitSize(128, false);
case lldb::eFormatVectorOfUInt16:
return ast_ctx->GetIntTypeFromBitSize(16, false);
case lldb::eFormatVectorOfUInt32:
return ast_ctx->GetIntTypeFromBitSize(32, false);
case lldb::eFormatVectorOfUInt64:
return ast_ctx->GetIntTypeFromBitSize(64, false);
case lldb::eFormatVectorOfUInt8:
return ast_ctx->GetIntTypeFromBitSize(8, false);
case lldb::eFormatBinary:
case lldb::eFormatComplexInteger:
case lldb::eFormatDecimal:
case lldb::eFormatDefault:
case lldb::eFormatEnum:
case lldb::eFormatInstruction:
case lldb::eFormatOSType:
case lldb::eFormatVoid:
default:
return ast_ctx->GetIntTypeFromBitSize(8, false);
}
}
static lldb::Format
GetItemFormatForFormat (lldb::Format format)
{
switch (format)
{
case lldb::eFormatVectorOfChar:
return lldb::eFormatChar;
case lldb::eFormatVectorOfFloat32:
case lldb::eFormatVectorOfFloat64:
return lldb::eFormatFloat;
case lldb::eFormatVectorOfSInt16:
case lldb::eFormatVectorOfSInt32:
case lldb::eFormatVectorOfSInt64:
case lldb::eFormatVectorOfSInt8:
return lldb::eFormatDecimal;
case lldb::eFormatVectorOfUInt128:
case lldb::eFormatVectorOfUInt16:
case lldb::eFormatVectorOfUInt32:
case lldb::eFormatVectorOfUInt64:
case lldb::eFormatVectorOfUInt8:
return lldb::eFormatUnsigned;
case lldb::eFormatBinary:
case lldb::eFormatComplexInteger:
case lldb::eFormatDecimal:
case lldb::eFormatDefault:
case lldb::eFormatEnum:
case lldb::eFormatInstruction:
case lldb::eFormatOSType:
case lldb::eFormatVoid:
return eFormatHex;
default:
return format;
}
}
static size_t
CalculateNumChildren (ClangASTType container_type,
ClangASTType element_type,
lldb_private::ExecutionContextScope *exe_scope = nullptr // does not matter here because all we trade in are basic types
)
{
auto container_size = container_type.GetByteSize(exe_scope);
auto element_size = element_type.GetByteSize(exe_scope);
if (element_size)
{
if (container_size % element_size)
return 0;
return container_size / element_size;
}
return 0;
}
namespace lldb_private {
namespace formatters {
class VectorTypeSyntheticFrontEnd : public SyntheticChildrenFrontEnd
{
public:
VectorTypeSyntheticFrontEnd (lldb::ValueObjectSP valobj_sp) :
SyntheticChildrenFrontEnd(*valobj_sp),
m_parent_format (eFormatInvalid),
m_item_format(eFormatInvalid),
m_child_type(),
m_num_children(0)
{}
virtual size_t
CalculateNumChildren ()
{
return m_num_children;
}
virtual lldb::ValueObjectSP
GetChildAtIndex (size_t idx)
{
if (idx >= CalculateNumChildren())
return lldb::ValueObjectSP();
auto offset = idx * m_child_type.GetByteSize(nullptr);
ValueObjectSP child_sp(m_backend.GetSyntheticChildAtOffset(offset, m_child_type, true));
if (!child_sp)
return child_sp;
StreamString idx_name;
idx_name.Printf("[%" PRIu64 "]", (uint64_t)idx);
child_sp->SetName( ConstString( idx_name.GetData() ) );
child_sp->SetFormat(m_item_format);
return child_sp;
}
virtual bool
Update()
{
m_parent_format = m_backend.GetFormat();
ClangASTType parent_type(m_backend.GetClangType());
m_child_type = ::GetClangTypeForFormat(m_parent_format, ClangASTContext::GetASTContext(parent_type.GetASTContext()));
m_num_children = ::CalculateNumChildren(parent_type,
m_child_type);
m_item_format = GetItemFormatForFormat(m_parent_format);
return false;
}
virtual bool
MightHaveChildren ()
{
return true;
}
virtual size_t
GetIndexOfChildWithName (const ConstString &name)
{
const char* item_name = name.GetCString();
uint32_t idx = ExtractIndexFromString(item_name);
if (idx < UINT32_MAX && idx >= CalculateNumChildren())
return UINT32_MAX;
return idx;
}
virtual
~VectorTypeSyntheticFrontEnd () {}
private:
lldb::Format m_parent_format;
lldb::Format m_item_format;
ClangASTType m_child_type;
size_t m_num_children;
};
}
}
lldb_private::SyntheticChildrenFrontEnd*
lldb_private::formatters::VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP valobj_sp)
{
if (!valobj_sp)
return NULL;
return (new VectorTypeSyntheticFrontEnd(valobj_sp));
}

View File

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

View File

@ -0,0 +1,78 @@
"""
Check that vector types format properly
"""
import os, time
import unittest2
import lldb
from lldbtest import *
import lldbutil
class VectorTypesFormattingTestCase(TestBase):
mydir = TestBase.compute_mydir(__file__)
# rdar://problem/14035604
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
@dsym_test
def test_with_dsym_and_run_command(self):
"""Check that vector types format properly"""
self.buildDsym()
self.propagate_test_commands()
# rdar://problem/14035604
@dwarf_test
def test_with_dwarf_and_run_command(self):
"""Check that vector types format properly"""
self.buildDwarf()
self.propagate_test_commands()
def setUp(self):
# Call super's setUp().
TestBase.setUp(self)
# Find the line number to break at.
self.line = line_number('main.cpp', '// break here')
def propagate_test_commands(self):
"""Check that vector types format properly"""
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True)
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():
pass
# Execute the cleanup function during test case tear down.
self.addTearDownHook(cleanup)
pass # my code never fails
v = self.frame().FindVariable("v")
v.SetPreferSyntheticValue(True)
v.SetFormat(lldb.eFormatVectorOfFloat32)
if self.TraceOn(): print v
self.assertTrue(v.GetNumChildren() == 4, "v as float32[] has 4 children")
self.assertTrue(v.GetChildAtIndex(0).GetData().float[0] == 1.25, "child 0 == 1.25")
self.assertTrue(v.GetChildAtIndex(1).GetData().float[0] == 1.25, "child 1 == 1.25")
self.assertTrue(v.GetChildAtIndex(2).GetData().float[0] == 2.50, "child 2 == 2.50")
self.assertTrue(v.GetChildAtIndex(3).GetData().float[0] == 2.50, "child 3 == 2.50")
self.expect("expr -f int16_t[] -- v", substrs=['[0] = 0', '[1] = 16288', '[2] = 0', '[3] = 16288', '[4] = 0', '[5] = 16416', '[6] = 0', '[7] = 16416'])
self.expect("expr -f uint128_t[] -- v", substrs=['[0] = 85236745249553456609335044694184296448'])
if __name__ == '__main__':
import atexit
lldb.SBDebugger.Initialize()
atexit.register(lambda: lldb.SBDebugger.Terminate())
unittest2.main()

View File

@ -0,0 +1,17 @@
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
typedef float float4 __attribute__((ext_vector_type(4)));
typedef unsigned char vec __attribute__((ext_vector_type(16)));
int main() {
float4 f4 = {1.25, 1.25, 2.50, 2.50};
vec v = (vec)f4;
return 0; // break here
}