forked from OSchip/llvm-project
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:
parent
d07b2b4228
commit
0ddbf3633c
|
@ -864,7 +864,7 @@ public:
|
|||
lldb::Format
|
||||
GetFormat () const;
|
||||
|
||||
void
|
||||
virtual void
|
||||
SetFormat (lldb::Format format)
|
||||
{
|
||||
if (format != m_format)
|
||||
|
|
|
@ -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 ();
|
||||
|
|
|
@ -398,6 +398,7 @@ namespace lldb_private {
|
|||
|
||||
SyntheticChildrenFrontEnd* LibcxxInitializerListSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
|
||||
|
||||
SyntheticChildrenFrontEnd* VectorTypeSyntheticFrontEndCreator (CXXSyntheticChildren*, lldb::ValueObjectSP);
|
||||
} // namespace formatters
|
||||
} // namespace lldb_private
|
||||
|
||||
|
|
|
@ -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 */,
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -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()
|
|
@ -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
|
||||
}
|
Loading…
Reference in New Issue