From 9fc1944ece6e1a668972e80a5e841dc920009899 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Wed, 6 Jul 2011 02:13:41 +0000 Subject: [PATCH] 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 --- lldb/include/lldb/Core/FormatManager.h | 10 +- lldb/include/lldb/Core/ValueObject.h | 19 +- lldb/include/lldb/Symbol/ClangASTContext.h | 11 + .../lldb/Symbol/TypeHierarchyNavigator.h | 75 ++ lldb/lldb.xcodeproj/project.pbxproj | 6 + lldb/source/Core/DataExtractor.cpp | 4 +- lldb/source/Core/Debugger.cpp | 739 +++++++----------- lldb/source/Core/ValueObject.cpp | 85 +- lldb/source/Symbol/ClangASTContext.cpp | 34 + lldb/source/Symbol/TypeHierarchyNavigator.cpp | 121 +++ lldb/source/Target/StackFrame.cpp | 146 +++- .../TestDataFormatterAdv.py | 85 +- .../data-formatter-advanced/main.cpp | 15 +- .../TestDataFormatterCpp.py | 6 +- 14 files changed, 873 insertions(+), 483 deletions(-) create mode 100644 lldb/include/lldb/Symbol/TypeHierarchyNavigator.h create mode 100644 lldb/source/Symbol/TypeHierarchyNavigator.cpp diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index 00d749260bc8..01f4f4e61691 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -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, SummaryFormat::RegexSummaryCallback>::Get(const char* key, - SummaryFormat::SharedPointer& value); - + SummaryFormat::SharedPointer& value); template<> bool FormatNavigator, SummaryFormat::RegexSummaryCallback>::Delete(const char* type); diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 095066fa6b66..33c2ebba093a 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -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 diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index 3e503fa8f46b..c9d00433672e 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/include/lldb/Symbol/ClangASTContext.h @@ -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); diff --git a/lldb/include/lldb/Symbol/TypeHierarchyNavigator.h b/lldb/include/lldb/Symbol/TypeHierarchyNavigator.h new file mode 100644 index 000000000000..d1657c02686c --- /dev/null +++ b/lldb/include/lldb/Symbol/TypeHierarchyNavigator.h @@ -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_ diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 3aa8f0aa5b7d..03e927c003c7 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -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 = ""; }; 9463D4CC13B1798800C230D4 /* CommandObjectType.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectType.cpp; path = source/Commands/CommandObjectType.cpp; sourceTree = ""; }; 9463D4CE13B179A500C230D4 /* CommandObjectType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = CommandObjectType.h; path = source/Commands/CommandObjectType.h; sourceTree = ""; }; + 9467E65113C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = TypeHierarchyNavigator.cpp; path = source/Symbol/TypeHierarchyNavigator.cpp; sourceTree = ""; }; + 9467E65413C3D98900B3B6F3 /* TypeHierarchyNavigator.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = TypeHierarchyNavigator.h; path = include/lldb/Symbol/TypeHierarchyNavigator.h; sourceTree = ""; }; 961FABB81235DE1600F93A47 /* FuncUnwinders.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FuncUnwinders.cpp; path = source/Symbol/FuncUnwinders.cpp; sourceTree = ""; }; 961FABB91235DE1600F93A47 /* UnwindPlan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindPlan.cpp; path = source/Symbol/UnwindPlan.cpp; sourceTree = ""; }; 961FABBA1235DE1600F93A47 /* UnwindTable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = UnwindTable.cpp; path = source/Symbol/UnwindTable.cpp; sourceTree = ""; }; @@ -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; }; diff --git a/lldb/source/Core/DataExtractor.cpp b/lldb/source/Core/DataExtractor.cpp index 9d6657355348..4cc98f31a658 100644 --- a/lldb/source/Core/DataExtractor.cpp +++ b/lldb/source/Core/DataExtractor.cpp @@ -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; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 21d45cde1da5..18e88f6b7319 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -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 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) diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index a8696be3f7f5..e0816309708d 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -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) { diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index dd297191b48c..5d2f0dd94098 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -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(qual_type.getTypePtr())->getElementType().getAsOpaquePtr(); + return IsScalarType(item_type); +} + bool ClangASTContext::GetCXXClassName (clang_type_t clang_type, std::string &class_name) diff --git a/lldb/source/Symbol/TypeHierarchyNavigator.cpp b/lldb/source/Symbol/TypeHierarchyNavigator.cpp new file mode 100644 index 000000000000..fdbe795be6e8 --- /dev/null +++ b/lldb/source/Symbol/TypeHierarchyNavigator.cpp @@ -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(); + 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(); + if (type_tdef) + return LoopThrough(type_tdef->getDecl()->getUnderlyingType(), callback, eStrippedTypedef, callback_baton); + else + return true; +} diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index efc2f3f56b56..ed50353fd891 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -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(""), + 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(""), + 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(""), + 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(""), + 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(""), + 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(""), + 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(); diff --git a/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py b/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py index a473435340dd..9184b7c45cc0 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py @@ -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 diff --git a/lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp b/lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp index 58432c1613d5..da11fafff15c 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp +++ b/lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp @@ -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. } \ No newline at end of file diff --git a/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py b/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py index 62a6596874df..9f7e00ed9059 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py @@ -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'])