forked from OSchip/llvm-project
new syntax for summary strings:
- ${*expr} now simply means to dereference expr before actually using it - bitfields, array ranges and pointer ranges now work in a (hopefully) more natural and language-compliant way a new class TypeHierarchyNavigator replicates the behavior of the FormatManager in going through type hierarchies when one-lining summary strings, children's summaries can be used as well as values llvm-svn: 134458
This commit is contained in:
parent
4d806e2830
commit
9fc1944ece
|
@ -260,6 +260,13 @@ private:
|
|||
if (!typePtr)
|
||||
return false;
|
||||
ConstString name(ClangASTType::GetTypeNameForQualType(type).c_str());
|
||||
if(vobj.GetBitfieldBitSize() > 0)
|
||||
{
|
||||
// for bitfields, append size to the typename so one can custom format them
|
||||
StreamString sstring;
|
||||
sstring.Printf("%s:%d",name.AsCString(),vobj.GetBitfieldBitSize());
|
||||
name = ConstString(sstring.GetData());
|
||||
}
|
||||
//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;
|
||||
|
@ -357,8 +364,7 @@ private:
|
|||
template<>
|
||||
bool
|
||||
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Get(const char* key,
|
||||
SummaryFormat::SharedPointer& value);
|
||||
|
||||
SummaryFormat::SharedPointer& value);
|
||||
template<>
|
||||
bool
|
||||
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Delete(const char* type);
|
||||
|
|
|
@ -246,6 +246,9 @@ public:
|
|||
|
||||
virtual bool
|
||||
IsPointerType ();
|
||||
|
||||
virtual bool
|
||||
IsScalarType ();
|
||||
|
||||
virtual bool
|
||||
IsPointerOrReferenceType ();
|
||||
|
@ -301,6 +304,12 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsArrayItemForPointer()
|
||||
{
|
||||
return m_is_array_item_for_pointer;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
SetClangAST (clang::ASTContext *ast)
|
||||
{
|
||||
|
@ -357,6 +366,10 @@ public:
|
|||
lldb::Format custom_format = lldb::eFormatInvalid);
|
||||
|
||||
bool
|
||||
DumpPrintableRepresentation(Stream& s,
|
||||
ValueObjectRepresentationStyle val_obj_display = eDisplaySummary,
|
||||
lldb::Format custom_format = lldb::eFormatInvalid);
|
||||
bool
|
||||
GetValueIsValid () const;
|
||||
|
||||
bool
|
||||
|
@ -391,6 +404,9 @@ public:
|
|||
lldb::ValueObjectSP
|
||||
GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetDynamicValue (lldb::DynamicValueType valueType);
|
||||
|
||||
|
@ -537,7 +553,8 @@ protected:
|
|||
m_old_value_valid:1,
|
||||
m_pointers_point_to_load_addrs:1,
|
||||
m_is_deref_of_parent:1,
|
||||
m_is_array_item_for_pointer:1;
|
||||
m_is_array_item_for_pointer:1,
|
||||
m_is_bitfield_for_scalar:1;
|
||||
|
||||
friend class ClangExpressionDeclMap; // For GetValue
|
||||
friend class ClangExpressionVariable; // For SetName
|
||||
|
|
|
@ -661,7 +661,18 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
static bool
|
||||
IsFloatingPointType (lldb::clang_type_t clang_type, uint32_t &count, bool &is_complex);
|
||||
|
||||
// true iff this is one of the types that can "fit"
|
||||
// in a Scalar object
|
||||
static bool
|
||||
IsScalarType (lldb::clang_type_t clang_type);
|
||||
|
||||
static bool
|
||||
IsPointerToScalarType (lldb::clang_type_t clang_type);
|
||||
|
||||
static bool
|
||||
IsArrayOfScalarType (lldb::clang_type_t clang_type);
|
||||
|
||||
static bool
|
||||
GetCXXClassName (lldb::clang_type_t clang_type,
|
||||
std::string &class_name);
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
//===-- TypeHierarchyNavigator.h ------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef lldb_TypeHierarchyNavigator_h_
|
||||
#define lldb_TypeHierarchyNavigator_h_
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
|
||||
// Project includes
|
||||
#include "lldb/lldb-public.h"
|
||||
#include "lldb/lldb-enumerations.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class TypeHierarchyNavigator {
|
||||
|
||||
public:
|
||||
|
||||
enum RelationshipToCurrentType
|
||||
{
|
||||
eRootType,
|
||||
eCXXBaseClass,
|
||||
eCXXVBaseClass,
|
||||
eObjCBaseClass,
|
||||
eStrippedPointer,
|
||||
eStrippedReference,
|
||||
eStrippedTypedef
|
||||
};
|
||||
|
||||
typedef bool (*TypeHierarchyNavigatorCallback)(const clang::QualType& qual_type,
|
||||
RelationshipToCurrentType reason_why_here,
|
||||
void* callback_baton);
|
||||
|
||||
TypeHierarchyNavigator(const clang::QualType& qual_type,
|
||||
ValueObject& val_obj,
|
||||
void* callback_baton = NULL) :
|
||||
m_root_type(qual_type),
|
||||
m_value_object(val_obj),
|
||||
m_default_callback_baton(callback_baton)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
LoopThrough(TypeHierarchyNavigatorCallback callback,
|
||||
void* callback_baton = NULL);
|
||||
|
||||
private:
|
||||
|
||||
bool
|
||||
LoopThrough(const clang::QualType& qual_type,
|
||||
TypeHierarchyNavigatorCallback callback,
|
||||
RelationshipToCurrentType reason_why_here,
|
||||
void* callback_baton);
|
||||
|
||||
const clang::QualType& m_root_type;
|
||||
ValueObject& m_value_object;
|
||||
void* m_default_callback_baton;
|
||||
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
#endif // lldb_TypeHierarchyNavigator_h_
|
|
@ -402,6 +402,7 @@
|
|||
4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
|
||||
9415F61813B2C0EF00A52B36 /* FormatManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */; };
|
||||
9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */; };
|
||||
9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */; };
|
||||
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
|
||||
9A22A161135E30370024DDC3 /* EmulateInstructionARM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A22A15D135E30370024DDC3 /* EmulateInstructionARM.cpp */; };
|
||||
|
@ -1165,6 +1166,8 @@
|
|||
9415F61713B2C0EF00A52B36 /* FormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatManager.cpp; path = source/Core/FormatManager.cpp; sourceTree = "<group>"; };
|
||||
9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectType.cpp; path = source/Commands/CommandObjectType.cpp; sourceTree = "<group>"; };
|
||||
9463D4CE13B179A500C230D4 /* CommandObjectType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectType.h; path = source/Commands/CommandObjectType.h; sourceTree = "<group>"; };
|
||||
9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeHierarchyNavigator.cpp; path = source/Symbol/TypeHierarchyNavigator.cpp; sourceTree = "<group>"; };
|
||||
9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = "<group>"; };
|
||||
961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FuncUnwinders.cpp; path = source/Symbol/FuncUnwinders.cpp; sourceTree = "<group>"; };
|
||||
961FABB91235DE1600F93A47 /* UnwindPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindPlan.cpp; path = source/Symbol/UnwindPlan.cpp; sourceTree = "<group>"; };
|
||||
961FABBA1235DE1600F93A47 /* UnwindTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindTable.cpp; path = source/Symbol/UnwindTable.cpp; sourceTree = "<group>"; };
|
||||
|
@ -2043,6 +2046,8 @@
|
|||
49BB309511F79450001A4197 /* TaggedASTType.h */,
|
||||
26BC7C6510F1B6E900F91463 /* Type.h */,
|
||||
26BC7F2010F1B8EC00F91463 /* Type.cpp */,
|
||||
9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */,
|
||||
9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */,
|
||||
26BC7C6610F1B6E900F91463 /* TypeList.h */,
|
||||
26BC7F2110F1B8EC00F91463 /* TypeList.cpp */,
|
||||
269FF07F12494F8E00225026 /* UnwindPlan.h */,
|
||||
|
@ -3239,6 +3244,7 @@
|
|||
9463D4CD13B1798800C230D4 /* CommandObjectType.cpp in Sources */,
|
||||
9415F61813B2C0EF00A52B36 /* FormatManager.cpp in Sources */,
|
||||
49D8FB3913B5598F00411094 /* ClangASTImporter.cpp in Sources */,
|
||||
9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
|
|
@ -753,7 +753,9 @@ DataExtractor::GetMaxU64Bitfield (uint32_t *offset_ptr, uint32_t size, uint32_t
|
|||
{
|
||||
if (bitfield_bit_offset > 0)
|
||||
uval64 >>= bitfield_bit_offset;
|
||||
uint64_t bitfield_mask = ((1 << bitfield_bit_size) - 1);
|
||||
uint64_t bitfield_mask = ((1ul << bitfield_bit_size) - 1);
|
||||
if(!bitfield_mask && bitfield_bit_offset == 0 && bitfield_bit_size == 64)
|
||||
return uval64;
|
||||
uval64 &= bitfield_mask;
|
||||
}
|
||||
return uval64;
|
||||
|
|
|
@ -694,6 +694,176 @@ TestPromptFormats (StackFrame *frame)
|
|||
}
|
||||
}
|
||||
|
||||
// #define VERBOSE_FORMATPROMPT_OUTPUT
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
#define IFERROR_PRINT_IT if (error.Fail()) \
|
||||
{ \
|
||||
printf("ERROR: %s\n",error.AsCString("unknown")); \
|
||||
break; \
|
||||
}
|
||||
#else // IFERROR_PRINT_IT
|
||||
#define IFERROR_PRINT_IT if (error.Fail()) \
|
||||
break;
|
||||
#endif // IFERROR_PRINT_IT
|
||||
|
||||
static bool
|
||||
ScanFormatDescriptor(const char* var_name_begin,
|
||||
const char* var_name_end,
|
||||
const char** var_name_final,
|
||||
const char** percent_position,
|
||||
lldb::Format* custom_format,
|
||||
ValueObject::ValueObjectRepresentationStyle* val_obj_display)
|
||||
{
|
||||
*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);
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
*custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
*val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
// if this is a V, print the value using the default format
|
||||
if(*format_name == 'V')
|
||||
*val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
// a good custom format tells us to print the value using it
|
||||
else
|
||||
*val_obj_display = ValueObject::eDisplayValue;
|
||||
delete format_name;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
ScanBracketedRange(const char* var_name_begin,
|
||||
const char* var_name_end,
|
||||
const char* var_name_final,
|
||||
const char** open_bracket_position,
|
||||
const char** separator_position,
|
||||
const char** close_bracket_position,
|
||||
const char** var_name_final_if_array_range,
|
||||
int64_t* index_lower,
|
||||
int64_t* index_higher)
|
||||
{
|
||||
*open_bracket_position = ::strchr(var_name_begin,'[');
|
||||
if(*open_bracket_position && *open_bracket_position < var_name_final)
|
||||
{
|
||||
*separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
|
||||
*close_bracket_position = ::strchr(*open_bracket_position,']');
|
||||
// as usual, we assume that [] will come before %
|
||||
//printf("trying to expand a []\n");
|
||||
*var_name_final_if_array_range = *open_bracket_position;
|
||||
if(*close_bracket_position - *open_bracket_position == 1)
|
||||
{
|
||||
*index_lower = 0;
|
||||
}
|
||||
else if (*separator_position == NULL || *separator_position > var_name_end)
|
||||
{
|
||||
char *end = NULL;
|
||||
*index_lower = ::strtoul (*open_bracket_position+1, &end, 0);
|
||||
*index_higher = *index_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;
|
||||
*index_lower = ::strtoul (*open_bracket_position+1, &end, 0);
|
||||
*index_higher = ::strtoul (*separator_position+1, &end, 0);
|
||||
//printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
if (*index_lower > *index_higher && *index_higher > 0)
|
||||
{
|
||||
int temp = *index_lower;
|
||||
*index_lower = *index_higher;
|
||||
*index_higher = temp;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static ValueObjectSP
|
||||
ExpandExpressionPath(ValueObject* vobj,
|
||||
StackFrame* frame,
|
||||
bool* do_deref_pointer,
|
||||
const char* var_name_begin,
|
||||
const char* var_name_final,
|
||||
Error& error)
|
||||
{
|
||||
|
||||
StreamString sstring;
|
||||
VariableSP var_sp;
|
||||
|
||||
if(*do_deref_pointer)
|
||||
sstring.PutChar('*');
|
||||
else if(vobj->IsDereferenceOfParent() && ClangASTContext::IsPointerType(vobj->GetParent()->GetClangType()) && !vobj->IsArrayItemForPointer())
|
||||
{
|
||||
sstring.PutChar('*');
|
||||
*do_deref_pointer = true;
|
||||
}
|
||||
|
||||
vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to expand in phase 0: %s\n",sstring.GetData());
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to expand in phase 1: %s\n",sstring.GetData());
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
std::string name = std::string(sstring.GetData());
|
||||
ValueObjectSP target = frame->GetValueForVariableExpressionPath (name.c_str(),
|
||||
eNoDynamicValues,
|
||||
0,
|
||||
var_sp,
|
||||
error);
|
||||
return target;
|
||||
}
|
||||
|
||||
static ValueObjectSP
|
||||
ExpandIndexedExpression(ValueObject* vobj,
|
||||
uint32_t index,
|
||||
StackFrame* frame,
|
||||
Error error)
|
||||
{
|
||||
ValueObjectSP item;
|
||||
bool is_array = ClangASTContext::IsArrayType(vobj->GetClangType());
|
||||
|
||||
if(is_array)
|
||||
return vobj->GetChildAtIndex(index, true);
|
||||
else
|
||||
{
|
||||
const char* ptr_deref_format = "%s[%d]";
|
||||
char* ptr_deref_buffer = new char[1024];
|
||||
StreamString expr_path_string;
|
||||
vobj->GetExpressionPath(expr_path_string, true, ValueObject::eHonorPointers);
|
||||
const char* expr_path = expr_path_string.GetData();
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to deref in phase 0: %s\n",expr_path);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
::sprintf(ptr_deref_buffer, ptr_deref_format, expr_path, index);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to deref in phase 1: %s\n",ptr_deref_buffer);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
lldb::VariableSP var_sp;
|
||||
item = frame->GetValueForVariableExpressionPath (ptr_deref_buffer,
|
||||
eNoDynamicValues,
|
||||
0,
|
||||
var_sp,
|
||||
error);
|
||||
delete ptr_deref_buffer;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::FormatPrompt
|
||||
(
|
||||
|
@ -783,6 +953,7 @@ Debugger::FormatPrompt
|
|||
FileSpec format_file_spec;
|
||||
const RegisterInfo *reg_info = NULL;
|
||||
RegisterContext *reg_ctx = NULL;
|
||||
bool do_deref_pointer = false;
|
||||
|
||||
// Each variable must set success to true below...
|
||||
bool var_success = false;
|
||||
|
@ -791,270 +962,19 @@ Debugger::FormatPrompt
|
|||
case '*':
|
||||
{
|
||||
if (!vobj) break;
|
||||
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));
|
||||
bool is_pointer = type_flags.Test (ClangASTContext::eTypeIsPointer),
|
||||
is_array = type_flags.Test (ClangASTContext::eTypeIsArray);
|
||||
if ( is_array ||
|
||||
( is_pointer && ::strchr(var_name_begin,'[') && ::strchr(var_name_begin,'[') < var_name_end )
|
||||
)
|
||||
{
|
||||
const char* var_name_final;
|
||||
const char* close_bracket_position = NULL;
|
||||
const char* percent_position = NULL;
|
||||
const char* targetvalue;
|
||||
lldb::Format custom_format = eFormatInvalid;
|
||||
int index_lower = -1;
|
||||
int index_higher = -1;
|
||||
ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary;
|
||||
{
|
||||
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);
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
// if this is a V, print the value using the default format
|
||||
if(*format_name == 'V')
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
// a good custom format tells us to print the value using it
|
||||
else
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char* open_bracket_position = ::strchr(var_name_begin,'[');
|
||||
if(open_bracket_position && open_bracket_position < var_name_final)
|
||||
{
|
||||
// TODO: pick a way to say "all entries". this will make more sense once
|
||||
// regex typenames are in place. now, you need to be size-aware anyways
|
||||
const char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
|
||||
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(close_bracket_position - open_bracket_position == 1)
|
||||
{
|
||||
if(is_array)
|
||||
{
|
||||
index_lower = 0;
|
||||
index_higher = vobj->GetNumChildren() - 1;
|
||||
}
|
||||
else
|
||||
break; // cannot auto-determine size for pointers
|
||||
}
|
||||
else if (separator_position == NULL || separator_position > var_name_end)
|
||||
{
|
||||
char *end = NULL;
|
||||
index_lower = ::strtoul (open_bracket_position+1, &end, 0);
|
||||
index_higher = index_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;
|
||||
index_lower = ::strtoul (open_bracket_position+1, &end, 0);
|
||||
index_higher = ::strtoul (separator_position+1, &end, 0);
|
||||
//printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher);
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (index_lower > index_higher)
|
||||
{
|
||||
int temp = index_lower;
|
||||
index_lower = index_higher;
|
||||
index_higher = temp;
|
||||
}
|
||||
//*((char*)open_bracket_position) = '\0';
|
||||
//printf("variable name is %s\n",var_name_begin);
|
||||
//*((char*)open_bracket_position) = '[';
|
||||
}
|
||||
}
|
||||
|
||||
// if you just type a range, lldb will do the "right thing" in picking
|
||||
// a reasonable display for the array entries. you can override this by
|
||||
// giving other input (e.g. ${*var[1-3].member1%uint8_t[]}) and they
|
||||
// will be honored
|
||||
char* special_directions = NULL;
|
||||
if (close_bracket_position && (var_name_end-close_bracket_position > 1))
|
||||
{
|
||||
int base_len = var_name_end-close_bracket_position;
|
||||
special_directions = new char[8+base_len];
|
||||
special_directions[0] = '$';
|
||||
special_directions[1] = '{';
|
||||
special_directions[2] = 'v';
|
||||
special_directions[3] = 'a';
|
||||
special_directions[4] = 'r';
|
||||
memcpy(special_directions+5, close_bracket_position+1, base_len);
|
||||
special_directions[base_len+7] = '\0';
|
||||
printf("%s\n",special_directions);
|
||||
}
|
||||
|
||||
// let us display items index_lower thru index_higher of this array
|
||||
s.PutChar('[');
|
||||
var_success = true;
|
||||
const char* expr_path = NULL;
|
||||
const char* ptr_deref_format = "%s[%d]";
|
||||
char* ptr_deref_buffer = new char[1024];
|
||||
StreamString expr_path_string;
|
||||
|
||||
if(is_pointer)
|
||||
{
|
||||
vobj->GetExpressionPath(expr_path_string, true, ValueObject::eHonorPointers);
|
||||
expr_path = expr_path_string.GetData();
|
||||
}
|
||||
|
||||
for(;index_lower<=index_higher;index_lower++)
|
||||
{
|
||||
ValueObject* item;
|
||||
|
||||
if(is_array)
|
||||
item = vobj->GetChildAtIndex(index_lower, true).get();
|
||||
else
|
||||
{
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to deref in phase 0: %s\n",expr_path);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
::sprintf(ptr_deref_buffer, ptr_deref_format, expr_path, index_lower);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to deref in phase 1: %s\n",ptr_deref_buffer);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
lldb::VariableSP var_sp;
|
||||
Error error;
|
||||
item = exe_ctx->frame->GetValueForVariableExpressionPath (ptr_deref_buffer,
|
||||
eNoDynamicValues,
|
||||
0,
|
||||
var_sp,
|
||||
error).get();
|
||||
if (error.Fail())
|
||||
{
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("ERROR: %s\n",error.AsCString("unknown"));
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!special_directions)
|
||||
{
|
||||
targetvalue = item->GetPrintableRepresentation(val_obj_display, custom_format);
|
||||
if(targetvalue)
|
||||
s.PutCString(targetvalue);
|
||||
var_success &= (targetvalue != NULL);
|
||||
if(custom_format != eFormatInvalid)
|
||||
item->SetFormat(eFormatDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
var_success &= FormatPrompt(special_directions, sc, exe_ctx, addr, s, NULL, item);
|
||||
}
|
||||
|
||||
if(index_lower < index_higher)
|
||||
s.PutChar(',');
|
||||
}
|
||||
s.PutChar(']');
|
||||
break;
|
||||
|
||||
}
|
||||
else if (is_pointer)
|
||||
{
|
||||
var_name_begin++;
|
||||
uint32_t offset = 0;
|
||||
DataExtractor read_for_null = vobj->GetDataExtractor();
|
||||
if (read_for_null.GetPointer(&offset) == 0)
|
||||
break;
|
||||
if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type) )
|
||||
{
|
||||
Error error;
|
||||
realvobj = vobj;
|
||||
vobj = vobj->Dereference(error).get();
|
||||
if(!vobj || error.Fail())
|
||||
break;
|
||||
}
|
||||
else 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 /*some other pointer type*/
|
||||
{
|
||||
Error error;
|
||||
realvobj = vobj;
|
||||
vobj = vobj->Dereference(error).get();
|
||||
if(!vobj || error.Fail())
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
do_deref_pointer = true;
|
||||
var_name_begin++;
|
||||
}
|
||||
case 'v':
|
||||
{
|
||||
const char* targetvalue;
|
||||
ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary;
|
||||
ValueObject* target;
|
||||
lldb::Format custom_format = eFormatInvalid;
|
||||
int bitfield_lower = -1;
|
||||
int bitfield_higher = -1;
|
||||
const char* var_name_final;
|
||||
const char* var_name_final_if_array_range = NULL;
|
||||
const char* close_bracket_position;
|
||||
int64_t index_lower = -1, index_higher = -1;
|
||||
bool is_array_range = false;
|
||||
if (!vobj) break;
|
||||
// simplest case ${var}, just print vobj's value
|
||||
if (::strncmp (var_name_begin, "var}", strlen("var}")) == 0)
|
||||
|
@ -1065,217 +985,140 @@ Debugger::FormatPrompt
|
|||
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;
|
||||
const char* percent_position;
|
||||
target = vobj;
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
{
|
||||
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);
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
}
|
||||
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;
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
{
|
||||
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);
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
delete format_name;
|
||||
break;
|
||||
}
|
||||
else
|
||||
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)
|
||||
{
|
||||
const char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
|
||||
const 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)
|
||||
{
|
||||
int temp = bitfield_lower;
|
||||
bitfield_lower = bitfield_higher;
|
||||
bitfield_higher = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
ScanFormatDescriptor(var_name_begin,
|
||||
var_name_end,
|
||||
&var_name_final,
|
||||
&percent_position,
|
||||
&custom_format,
|
||||
&val_obj_display);
|
||||
}
|
||||
// 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);
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
// if this is a V, print the value using the default format
|
||||
if(*format_name == 'V')
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
// a good custom format tells us to print the value using it
|
||||
else
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char* open_bracket_position = ::strchr(var_name_begin,'[');
|
||||
if(open_bracket_position && open_bracket_position < var_name_final)
|
||||
{
|
||||
const char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
|
||||
const 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)
|
||||
{
|
||||
int temp = bitfield_lower;
|
||||
bitfield_lower = bitfield_higher;
|
||||
bitfield_higher = temp;
|
||||
}
|
||||
//*((char*)open_bracket_position) = '\0';
|
||||
//printf("variable name is %s\n",var_name_begin);
|
||||
//*((char*)open_bracket_position) = '[';
|
||||
}
|
||||
}
|
||||
|
||||
const char* percent_position;
|
||||
ScanFormatDescriptor(var_name_begin,
|
||||
var_name_end,
|
||||
&var_name_final,
|
||||
&percent_position,
|
||||
&custom_format,
|
||||
&val_obj_display);
|
||||
|
||||
const char* open_bracket_position;
|
||||
const char* separator_position;
|
||||
ScanBracketedRange(var_name_begin,
|
||||
var_name_end,
|
||||
var_name_final,
|
||||
&open_bracket_position,
|
||||
&separator_position,
|
||||
&close_bracket_position,
|
||||
&var_name_final_if_array_range,
|
||||
&index_lower,
|
||||
&index_higher);
|
||||
|
||||
Error error;
|
||||
lldb::VariableSP var_sp;
|
||||
StreamString sstring;
|
||||
vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to expand in phase 0: %s\n",sstring.GetData());
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to expand in phase 1: %s\n",sstring.GetData());
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
std::string name = std::string(sstring.GetData());
|
||||
target = exe_ctx->frame->GetValueForVariableExpressionPath (name.c_str(),
|
||||
eNoDynamicValues,
|
||||
0,
|
||||
var_sp,
|
||||
error).get();
|
||||
if (error.Fail())
|
||||
target = ExpandExpressionPath(vobj,
|
||||
exe_ctx->frame,
|
||||
&do_deref_pointer,
|
||||
var_name_begin,
|
||||
var_name_final,
|
||||
error).get();
|
||||
|
||||
if (error.Fail() || !target)
|
||||
{
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("ERROR: %s\n",error.AsCString("unknown"));
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
break;
|
||||
if (var_name_final_if_array_range)
|
||||
{
|
||||
target = ExpandExpressionPath(vobj,
|
||||
exe_ctx->frame,
|
||||
&do_deref_pointer,
|
||||
var_name_begin,
|
||||
var_name_final_if_array_range,
|
||||
error).get();
|
||||
}
|
||||
|
||||
IFERROR_PRINT_IT
|
||||
else
|
||||
is_array_range = true;
|
||||
}
|
||||
|
||||
do_deref_pointer = false; // I have honored the request to deref
|
||||
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (bitfield_lower >= 0)
|
||||
|
||||
if(do_deref_pointer)
|
||||
{
|
||||
//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");
|
||||
// I have not deref-ed yet, let's do it
|
||||
// this happens when we are not going through GetValueForVariableExpressionPath
|
||||
// to get to the target ValueObject
|
||||
Error error;
|
||||
target = target->Dereference(error).get();
|
||||
IFERROR_PRINT_IT
|
||||
do_deref_pointer = false;
|
||||
}
|
||||
|
||||
if(!is_array_range)
|
||||
var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format);
|
||||
else
|
||||
{
|
||||
// format this as usual
|
||||
targetvalue = target->GetPrintableRepresentation(val_obj_display, custom_format);
|
||||
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");
|
||||
bool is_array = ClangASTContext::IsArrayType(vobj->GetClangType());
|
||||
bool is_pointer = ClangASTContext::IsPointerType(vobj->GetClangType());
|
||||
|
||||
if(!is_array && !is_pointer)
|
||||
break;
|
||||
|
||||
char* special_directions = NULL;
|
||||
if (close_bracket_position && (var_name_end-close_bracket_position > 1))
|
||||
{
|
||||
int base_len = var_name_end-close_bracket_position;
|
||||
special_directions = new char[8+base_len];
|
||||
special_directions[0] = '$';
|
||||
special_directions[1] = '{';
|
||||
special_directions[2] = 'v';
|
||||
special_directions[3] = 'a';
|
||||
special_directions[4] = 'r';
|
||||
memcpy(special_directions+5, close_bracket_position+1, base_len);
|
||||
special_directions[base_len+7] = '\0';
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("%s\n",special_directions);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
}
|
||||
|
||||
// let us display items index_lower thru index_higher of this array
|
||||
s.PutChar('[');
|
||||
var_success = true;
|
||||
|
||||
if(index_higher < 0)
|
||||
index_higher = vobj->GetNumChildren() - 1;
|
||||
|
||||
for(;index_lower<=index_higher;index_lower++)
|
||||
{
|
||||
Error error;
|
||||
ValueObject* item = ExpandIndexedExpression(vobj,
|
||||
index_lower,
|
||||
exe_ctx->frame,
|
||||
error).get();
|
||||
|
||||
|
||||
IFERROR_PRINT_IT
|
||||
if (!special_directions)
|
||||
var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format);
|
||||
else
|
||||
var_success &= FormatPrompt(special_directions, sc, exe_ctx, addr, s, NULL, item);
|
||||
|
||||
if(index_lower < index_higher)
|
||||
s.PutChar(',');
|
||||
}
|
||||
s.PutChar(']');
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
case 'a':
|
||||
if (::strncmp (var_name_begin, "addr}", strlen("addr}")) == 0)
|
||||
|
|
|
@ -74,6 +74,7 @@ ValueObject::ValueObject (ValueObject &parent) :
|
|||
m_pointers_point_to_load_addrs (false),
|
||||
m_is_deref_of_parent (false),
|
||||
m_is_array_item_for_pointer(false),
|
||||
m_is_bitfield_for_scalar(false),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_summary_format(),
|
||||
m_last_value_format()
|
||||
|
@ -110,6 +111,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
|
|||
m_pointers_point_to_load_addrs (false),
|
||||
m_is_deref_of_parent (false),
|
||||
m_is_array_item_for_pointer(false),
|
||||
m_is_bitfield_for_scalar(false),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_summary_format(),
|
||||
m_last_value_format()
|
||||
|
@ -515,7 +517,7 @@ ValueObject::GetSummaryAsCString ()
|
|||
s.PutCString(", ");
|
||||
s.PutCString(child_sp.get()->GetName().AsCString());
|
||||
s.PutChar('=');
|
||||
s.PutCString(child_sp.get()->GetValueAsCString());
|
||||
s.PutCString(child_sp.get()->GetPrintableRepresentation());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -768,7 +770,9 @@ ValueObject::GetValueAsCString ()
|
|||
if (m_last_value_format)
|
||||
format = m_last_value_format->m_format;
|
||||
else
|
||||
format = ClangASTType::GetFormat(clang_type);
|
||||
// force the system into using unsigned integers for bitfields
|
||||
format = (m_is_bitfield_for_scalar ? eFormatUnsigned :
|
||||
ClangASTType::GetFormat(clang_type));
|
||||
}
|
||||
|
||||
if (ClangASTType::DumpTypeValue (GetClangAST(), // The clang AST
|
||||
|
@ -844,15 +848,35 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d
|
|||
break;
|
||||
}
|
||||
|
||||
if (!return_value)
|
||||
{
|
||||
// try to pick the other choice
|
||||
if (val_obj_display == eDisplayValue)
|
||||
return_value = GetSummaryAsCString();
|
||||
else if (val_obj_display == eDisplaySummary)
|
||||
return_value = GetValueAsCString();
|
||||
else
|
||||
return_value = "";
|
||||
}
|
||||
|
||||
// try to use the value if the user's choice failed
|
||||
if(!return_value && val_obj_display != eDisplayValue)
|
||||
return_value = GetValueAsCString();
|
||||
|
||||
return return_value;
|
||||
return (return_value ? return_value : "");
|
||||
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObject::DumpPrintableRepresentation(Stream& s,
|
||||
ValueObjectRepresentationStyle val_obj_display,
|
||||
lldb::Format custom_format)
|
||||
{
|
||||
const char *targetvalue = GetPrintableRepresentation(val_obj_display, custom_format);
|
||||
if(targetvalue)
|
||||
s.PutCString(targetvalue);
|
||||
bool var_success = (targetvalue != NULL);
|
||||
if(custom_format != eFormatInvalid)
|
||||
SetFormat(eFormatDefault);
|
||||
return var_success;
|
||||
}
|
||||
|
||||
addr_t
|
||||
ValueObject::GetAddressOf (AddressType &address_type, bool scalar_is_load_address)
|
||||
{
|
||||
|
@ -1072,6 +1096,12 @@ ValueObject::IsPointerType ()
|
|||
return ClangASTContext::IsPointerType (GetClangType());
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObject::IsScalarType ()
|
||||
{
|
||||
return ClangASTContext::IsScalarType (GetClangType());
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObject::IsIntegerType (bool &is_signed)
|
||||
{
|
||||
|
@ -1128,6 +1158,47 @@ ValueObject::GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create)
|
|||
return synthetic_child_sp;
|
||||
}
|
||||
|
||||
ValueObjectSP
|
||||
ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create)
|
||||
{
|
||||
ValueObjectSP synthetic_child_sp;
|
||||
if (IsScalarType ())
|
||||
{
|
||||
char index_str[64];
|
||||
snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to);
|
||||
ConstString index_const_str(index_str);
|
||||
// Check if we have already created a synthetic array member in this
|
||||
// valid object. If we have we will re-use it.
|
||||
synthetic_child_sp = GetSyntheticChild (index_const_str);
|
||||
if (!synthetic_child_sp)
|
||||
{
|
||||
ValueObjectChild *synthetic_child;
|
||||
// We haven't made a synthetic array member for INDEX yet, so
|
||||
// lets make one and cache it for any future reference.
|
||||
synthetic_child = new ValueObjectChild(*this,
|
||||
GetClangAST(),
|
||||
GetClangType(),
|
||||
index_const_str,
|
||||
GetByteSize(),
|
||||
0,
|
||||
to-from+1,
|
||||
from,
|
||||
false,
|
||||
false);
|
||||
|
||||
// Cache the value if we got one back...
|
||||
if (synthetic_child)
|
||||
{
|
||||
AddSyntheticChild(index_const_str, synthetic_child);
|
||||
synthetic_child_sp = synthetic_child->GetSP();
|
||||
synthetic_child_sp->SetName(index_str);
|
||||
synthetic_child_sp->m_is_bitfield_for_scalar = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return synthetic_child_sp;
|
||||
}
|
||||
|
||||
void
|
||||
ValueObject::CalculateDynamicValue (lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
|
|
|
@ -4464,6 +4464,40 @@ ClangASTContext::IsFloatingPointType (clang_type_t clang_type, uint32_t &count,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ClangASTContext::IsScalarType (lldb::clang_type_t clang_type)
|
||||
{
|
||||
bool is_signed;
|
||||
if (ClangASTContext::IsIntegerType(clang_type, is_signed))
|
||||
return true;
|
||||
|
||||
uint32_t count;
|
||||
bool is_complex;
|
||||
return ClangASTContext::IsFloatingPointType(clang_type, count, is_complex) && !is_complex;
|
||||
}
|
||||
|
||||
bool
|
||||
ClangASTContext::IsPointerToScalarType (lldb::clang_type_t clang_type)
|
||||
{
|
||||
if (!IsPointerType(clang_type))
|
||||
return false;
|
||||
|
||||
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
||||
lldb::clang_type_t pointee_type = qual_type.getTypePtr()->getPointeeType().getAsOpaquePtr();
|
||||
return IsScalarType(pointee_type);
|
||||
}
|
||||
|
||||
bool
|
||||
ClangASTContext::IsArrayOfScalarType (lldb::clang_type_t clang_type)
|
||||
{
|
||||
if (!IsArrayType(clang_type))
|
||||
return false;
|
||||
|
||||
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
||||
lldb::clang_type_t item_type = cast<ArrayType>(qual_type.getTypePtr())->getElementType().getAsOpaquePtr();
|
||||
return IsScalarType(item_type);
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ClangASTContext::GetCXXClassName (clang_type_t clang_type, std::string &class_name)
|
||||
|
|
|
@ -0,0 +1,121 @@
|
|||
//===-- TypeHierarchyNavigator.cpp -----------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/Core/Error.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Symbol/ClangASTContext.h"
|
||||
#include "lldb/Symbol/TypeHierarchyNavigator.h"
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
|
||||
bool
|
||||
TypeHierarchyNavigator::LoopThrough(TypeHierarchyNavigatorCallback callback,
|
||||
void* callback_baton)
|
||||
{
|
||||
return LoopThrough(m_root_type,
|
||||
callback,
|
||||
eRootType,
|
||||
(callback_baton ? callback_baton : m_default_callback_baton));
|
||||
}
|
||||
|
||||
bool
|
||||
TypeHierarchyNavigator::LoopThrough(const clang::QualType& qual_type,
|
||||
TypeHierarchyNavigatorCallback callback,
|
||||
RelationshipToCurrentType reason_why_here,
|
||||
void* callback_baton)
|
||||
{
|
||||
if (qual_type.isNull())
|
||||
return true;
|
||||
clang::QualType type = qual_type.getUnqualifiedType();
|
||||
type.removeLocalConst(); type.removeLocalVolatile(); type.removeLocalRestrict();
|
||||
const clang::Type* typePtr = type.getTypePtrOrNull();
|
||||
if (!typePtr)
|
||||
return true;
|
||||
if (!callback(type, reason_why_here, callback_baton))
|
||||
return false;
|
||||
// look for a "base type", whatever that means
|
||||
if (typePtr->isReferenceType())
|
||||
{
|
||||
if (LoopThrough(type.getNonReferenceType(), callback, eStrippedReference, callback_baton) == false)
|
||||
return false;
|
||||
}
|
||||
if (typePtr->isPointerType())
|
||||
{
|
||||
if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false)
|
||||
return false;
|
||||
}
|
||||
if (typePtr->isObjCObjectPointerType())
|
||||
{
|
||||
/*
|
||||
for some reason, C++ can quite easily obtain the type hierarchy for a ValueObject
|
||||
even if the VO represent a pointer-to-class, as long as the typePtr is right
|
||||
Objective-C on the other hand cannot really complete an @interface when
|
||||
the VO refers to a pointer-to-@interface
|
||||
*/
|
||||
Error error;
|
||||
ValueObject* target = m_value_object.Dereference(error).get();
|
||||
if(error.Fail() || !target)
|
||||
return true;
|
||||
if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false)
|
||||
return false;
|
||||
}
|
||||
const clang::ObjCObjectType *objc_class_type = typePtr->getAs<clang::ObjCObjectType>();
|
||||
if (objc_class_type)
|
||||
{
|
||||
clang::ASTContext *ast = m_value_object.GetClangAST();
|
||||
if (ClangASTContext::GetCompleteType(ast, m_value_object.GetClangType()) && !objc_class_type->isObjCId())
|
||||
{
|
||||
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
||||
if(class_interface_decl)
|
||||
{
|
||||
clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
|
||||
if(superclass_interface_decl)
|
||||
{
|
||||
clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl));
|
||||
return LoopThrough(ivar_qual_type, callback, eObjCBaseClass, callback_baton);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for C++ classes, navigate up the hierarchy
|
||||
if (typePtr->isRecordType())
|
||||
{
|
||||
clang::CXXRecordDecl* record = typePtr->getAsCXXRecordDecl();
|
||||
if (record)
|
||||
{
|
||||
if (!record->hasDefinition())
|
||||
ClangASTContext::GetCompleteType(m_value_object.GetClangAST(), m_value_object.GetClangType());
|
||||
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 (LoopThrough(pos->getType(), callback, eCXXBaseClass, callback_baton) == false)
|
||||
return false;
|
||||
}
|
||||
if (record->getNumVBases() > 0)
|
||||
{
|
||||
end = record->vbases_end();
|
||||
for (pos = record->vbases_begin(); pos != end; pos++)
|
||||
if (LoopThrough(pos->getType(), callback, eCXXVBaseClass, callback_baton) == false)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// try to strip typedef chains
|
||||
const clang::TypedefType* type_tdef = type->getAs<clang::TypedefType>();
|
||||
if (type_tdef)
|
||||
return LoopThrough(type_tdef->getDecl()->getUnderlyingType(), callback, eStrippedTypedef, callback_baton);
|
||||
else
|
||||
return true;
|
||||
}
|
|
@ -645,9 +645,47 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
|
|||
{
|
||||
char *end = NULL;
|
||||
long child_index = ::strtol (&var_path[1], &end, 0);
|
||||
if (end && *end == ']')
|
||||
if (end && *end == ']'
|
||||
&& *(end-1) != '[') // this code forces an error in the case of arr[]. as bitfield[] is not a good syntax we're good to go
|
||||
{
|
||||
|
||||
if (ClangASTContext::IsPointerToScalarType(valobj_sp->GetClangType()) && deref)
|
||||
{
|
||||
// what we have is *ptr[low]. the most similar C++ syntax is to deref ptr
|
||||
// and extract bit low out of it. reading array item low
|
||||
// would be done by saying ptr[low], without a deref * sign
|
||||
Error error;
|
||||
ValueObjectSP temp(valobj_sp->Dereference(error));
|
||||
if (error.Fail())
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"",
|
||||
valobj_sp->GetTypeName().AsCString("<invalid type>"),
|
||||
var_expr_path_strm.GetString().c_str());
|
||||
return ValueObjectSP();
|
||||
}
|
||||
valobj_sp = temp;
|
||||
deref = false;
|
||||
}
|
||||
else if (ClangASTContext::IsArrayOfScalarType(valobj_sp->GetClangType()) && deref)
|
||||
{
|
||||
// what we have is *arr[low]. the most similar C++ syntax is to get arr[0]
|
||||
// (an operation that is equivalent to deref-ing arr)
|
||||
// and extract bit low out of it. reading array item low
|
||||
// would be done by saying arr[low], without a deref * sign
|
||||
Error error;
|
||||
ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true));
|
||||
if (error.Fail())
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"",
|
||||
valobj_sp->GetTypeName().AsCString("<invalid type>"),
|
||||
var_expr_path_strm.GetString().c_str());
|
||||
return ValueObjectSP();
|
||||
}
|
||||
valobj_sp = temp;
|
||||
deref = false;
|
||||
}
|
||||
|
||||
if (valobj_sp->IsPointerType ())
|
||||
{
|
||||
child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true);
|
||||
|
@ -674,6 +712,19 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
|
|||
var_expr_path_strm.GetString().c_str());
|
||||
}
|
||||
}
|
||||
else if (ClangASTContext::IsScalarType(valobj_sp->GetClangType()))
|
||||
{
|
||||
// this is a bitfield asking to display just one bit
|
||||
child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, child_index, true);
|
||||
if (!child_valobj_sp)
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
error.SetErrorStringWithFormat ("bitfield range %i-%i is not valid for \"(%s) %s\"",
|
||||
child_index, child_index,
|
||||
valobj_sp->GetTypeName().AsCString("<invalid type>"),
|
||||
var_expr_path_strm.GetString().c_str());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
|
@ -702,6 +753,97 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
|
|||
// able to find the child member
|
||||
break;
|
||||
}
|
||||
else if(end && *end == '-')
|
||||
{
|
||||
// this is most probably a BitField, let's take a look
|
||||
char *real_end = NULL;
|
||||
long final_index = ::strtol (end+1, &real_end, 0);
|
||||
if(real_end && *real_end == ']')
|
||||
{
|
||||
// if the format given is [high-low], swap range
|
||||
if(child_index > final_index)
|
||||
{
|
||||
long temp = child_index;
|
||||
child_index = final_index;
|
||||
final_index = temp;
|
||||
}
|
||||
|
||||
if (ClangASTContext::IsPointerToScalarType(valobj_sp->GetClangType()) && deref)
|
||||
{
|
||||
// what we have is *ptr[low-high]. the most similar C++ syntax is to deref ptr
|
||||
// and extract bits low thru high out of it. reading array items low thru high
|
||||
// would be done by saying ptr[low-high], without a deref * sign
|
||||
Error error;
|
||||
ValueObjectSP temp(valobj_sp->Dereference(error));
|
||||
if (error.Fail())
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"",
|
||||
valobj_sp->GetTypeName().AsCString("<invalid type>"),
|
||||
var_expr_path_strm.GetString().c_str());
|
||||
return ValueObjectSP();
|
||||
}
|
||||
valobj_sp = temp;
|
||||
deref = false;
|
||||
}
|
||||
else if (ClangASTContext::IsArrayOfScalarType(valobj_sp->GetClangType()) && deref)
|
||||
{
|
||||
// what we have is *arr[low-high]. the most similar C++ syntax is to get arr[0]
|
||||
// (an operation that is equivalent to deref-ing arr)
|
||||
// and extract bits low thru high out of it. reading array items low thru high
|
||||
// would be done by saying arr[low-high], without a deref * sign
|
||||
Error error;
|
||||
ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true));
|
||||
if (error.Fail())
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"",
|
||||
valobj_sp->GetTypeName().AsCString("<invalid type>"),
|
||||
var_expr_path_strm.GetString().c_str());
|
||||
return ValueObjectSP();
|
||||
}
|
||||
valobj_sp = temp;
|
||||
deref = false;
|
||||
}
|
||||
|
||||
child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true);
|
||||
if (!child_valobj_sp)
|
||||
{
|
||||
valobj_sp->GetExpressionPath (var_expr_path_strm, false);
|
||||
error.SetErrorStringWithFormat ("bitfield range %i-%i is not valid for \"(%s) %s\"",
|
||||
child_index, final_index,
|
||||
valobj_sp->GetTypeName().AsCString("<invalid type>"),
|
||||
var_expr_path_strm.GetString().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
if (!child_valobj_sp)
|
||||
{
|
||||
// Invalid bitfield range...
|
||||
return ValueObjectSP();
|
||||
}
|
||||
|
||||
// Erase the bitfield member specification '[%i-%i]' where
|
||||
// %i is the index
|
||||
var_path.erase(0, (real_end - var_path.c_str()) + 1);
|
||||
separator_idx = var_path.find_first_of(".-[");
|
||||
if (use_dynamic != lldb::eNoDynamicValues)
|
||||
{
|
||||
ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
|
||||
if (dynamic_value_sp)
|
||||
child_valobj_sp = dynamic_value_sp;
|
||||
}
|
||||
// Break out early from the switch since we were
|
||||
// able to find the child member
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error.SetErrorStringWithFormat("invalid square bracket encountered after \"%s\" in \"%s\"",
|
||||
var_expr_path_strm.GetString().c_str(),
|
||||
var_path.c_str());
|
||||
}
|
||||
return ValueObjectSP();
|
||||
|
||||
|
|
|
@ -53,13 +53,6 @@ class DataFormatterTestCase(TestBase):
|
|||
# Execute the cleanup function during test case tear down.
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
self.runCmd("type summary add -f \"pippo\" -x \"IUseCharStar\"")
|
||||
|
||||
self.expect("frame variable iEncapsulateCharStar",
|
||||
substrs = ['pippo'])
|
||||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -f \"pippo\" \"i_am_cool\"")
|
||||
|
||||
self.runCmd("type summary add -f \"pluto\" -x \"i_am_cool[a-z]*\"")
|
||||
|
@ -77,12 +70,12 @@ class DataFormatterTestCase(TestBase):
|
|||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -f \"${*var[]}\" -x \"int \\[[0-9]\\]")
|
||||
self.runCmd("type summary add -f \"${var[]}\" -x \"int \\[[0-9]\\]")
|
||||
|
||||
self.expect("frame variable int_array",
|
||||
substrs = ['1,2,3,4,5'])
|
||||
|
||||
self.runCmd("type summary add -f \"${*var[].integer}\" -x \"i_am_cool \\[[0-9]\\]")
|
||||
self.runCmd("type summary add -f \"${var[].integer}\" -x \"i_am_cool \\[[0-9]\\]")
|
||||
|
||||
self.expect("frame variable cool_array",
|
||||
substrs = ['1,1,1,1,6'])
|
||||
|
@ -93,17 +86,79 @@ class DataFormatterTestCase(TestBase):
|
|||
|
||||
self.expect("frame variable iAmInt",
|
||||
substrs = ['01'])
|
||||
|
||||
self.runCmd("type summary add -f \"${*var[0-1]%x}\" \"int\"")
|
||||
|
||||
self.expect("frame variable iAmInt", matching=False,
|
||||
substrs = ['01'])
|
||||
|
||||
|
||||
self.runCmd("type summary add -f \"${var[0-1]%x}\" \"int\"")
|
||||
|
||||
self.expect("frame variable iAmInt",
|
||||
substrs = ['01'])
|
||||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -f \"${var[0-1]%x}\" int")
|
||||
self.runCmd("type summary add -f \"${var[0-31]%x}\" float")
|
||||
|
||||
self.expect("frame variable *pointer",
|
||||
substrs = ['0x',
|
||||
'2'])
|
||||
|
||||
self.expect("frame variable cool_array[3].floating",
|
||||
substrs = ['0x'])
|
||||
|
||||
self.runCmd("type summary add -f \"low bits are ${*var[0-1]} tgt is ${*var}\" \"int *\"")
|
||||
|
||||
self.expect("frame variable pointer",
|
||||
substrs = ['low bits are',
|
||||
'tgt is 6'])
|
||||
|
||||
self.runCmd("type summary add -f \"${*var[0-1]}\" -x \"int \[[0-9]\]\"")
|
||||
|
||||
self.expect("frame variable int_array",
|
||||
substrs = ['3'])
|
||||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -f \"${var[0-1]}\" -x \"int \[[0-9]\]\"")
|
||||
|
||||
self.expect("frame variable int_array",
|
||||
substrs = ['1,2'])
|
||||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -c -x \"i_am_cool \[[0-9]\]\"")
|
||||
self.runCmd("type summary add -c i_am_cool")
|
||||
|
||||
self.expect("frame variable cool_array",
|
||||
substrs = ['[0]',
|
||||
'[1]',
|
||||
'[2]',
|
||||
'[3]',
|
||||
'[4]',
|
||||
'integer',
|
||||
'character',
|
||||
'floating'])
|
||||
|
||||
self.runCmd("type summary add -f \"int = ${*var.int_pointer}, float = ${*var.float_pointer}\" IWrapPointers")
|
||||
|
||||
self.expect("frame variable wrapper",
|
||||
substrs = ['int = 4',
|
||||
'float = 1.1'])
|
||||
|
||||
self.runCmd("type summary add -f \"low bits = ${*var.int_pointer[2]}\" IWrapPointers -p")
|
||||
|
||||
self.expect("frame variable wrapper",
|
||||
substrs = ['low bits = 1'])
|
||||
|
||||
self.expect("frame variable *wrap_pointer",
|
||||
substrs = ['low bits = 1'])
|
||||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -f \"${var[0][0-2]%hex}\" -x \"int \[[0-9]\]\"")
|
||||
|
||||
self.expect("frame variable int_array",
|
||||
substrs = ['0x',
|
||||
'7'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -34,10 +34,11 @@ struct i_am_cooler
|
|||
floating((F1 + F2)/2) {}
|
||||
};
|
||||
|
||||
struct IUseCharStar
|
||||
struct IWrapPointers
|
||||
{
|
||||
const char* pointer;
|
||||
IUseCharStar() : pointer("Hello world") {}
|
||||
int* int_pointer;
|
||||
float* float_pointer;
|
||||
IWrapPointers() : int_pointer(new int(4)), float_pointer(new float(1.111)) {}
|
||||
};
|
||||
|
||||
int main (int argc, const char * argv[])
|
||||
|
@ -58,7 +59,13 @@ int main (int argc, const char * argv[])
|
|||
|
||||
int int_array[] = {1,2,3,4,5};
|
||||
|
||||
IUseCharStar iEncapsulateCharStar;
|
||||
IWrapPointers wrapper;
|
||||
|
||||
*int_array = -1;
|
||||
|
||||
int* pointer = &cool_array[4].integer;
|
||||
|
||||
IWrapPointers *wrap_pointer = &wrapper;
|
||||
|
||||
return 0; // Set break point at this line.
|
||||
}
|
|
@ -129,7 +129,7 @@ class DataFormatterTestCase(TestBase):
|
|||
substrs = ['a test'],
|
||||
matching = False)
|
||||
|
||||
self.runCmd("type summary add -f \"${*var[1-3]}\" \"int [5]\"")
|
||||
self.runCmd("type summary add -f \"${var[1-3]}\" \"int [5]\"")
|
||||
|
||||
self.expect("frame variable int_array",
|
||||
substrs = ['2',
|
||||
|
@ -138,8 +138,8 @@ class DataFormatterTestCase(TestBase):
|
|||
|
||||
self.runCmd("type summary clear")
|
||||
|
||||
self.runCmd("type summary add -f \"${*var[0-2].integer}\" \"i_am_cool *\"")
|
||||
self.runCmd("type summary add -f \"${*var[2-4].integer}\" \"i_am_cool [5]\"")
|
||||
self.runCmd("type summary add -f \"${var[0-2].integer}\" \"i_am_cool *\"")
|
||||
self.runCmd("type summary add -f \"${var[2-4].integer}\" \"i_am_cool [5]\"")
|
||||
|
||||
self.expect("frame variable cool_array",
|
||||
substrs = ['1,1,6'])
|
||||
|
|
Loading…
Reference in New Issue