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:
Enrico Granata 2011-07-06 02:13:41 +00:00
parent 4d806e2830
commit 9fc1944ece
14 changed files with 873 additions and 483 deletions

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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_

View File

@ -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;
};

View File

@ -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;

View File

@ -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)

View File

@ -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)
{

View File

@ -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)

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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.
}

View File

@ -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'])