diff options
-rw-r--r-- | lldb/include/lldb/Core/FormatManager.h | 5 | ||||
-rw-r--r-- | lldb/include/lldb/Core/ValueObject.h | 6 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | lldb/source/Core/DataExtractor.cpp | 7 | ||||
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 24 | ||||
-rw-r--r-- | lldb/source/Core/FormatManager.cpp | 30 | ||||
-rw-r--r-- | lldb/source/Core/ValueObject.cpp | 190 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py | 4 | ||||
-rwxr-xr-x | lldb/www/varformats.html | 81 |
9 files changed, 275 insertions, 78 deletions
diff --git a/lldb/include/lldb/Core/FormatManager.h b/lldb/include/lldb/Core/FormatManager.h index bd408a5697c..f1bd52cc38b 100644 --- a/lldb/include/lldb/Core/FormatManager.h +++ b/lldb/include/lldb/Core/FormatManager.h @@ -499,6 +499,11 @@ public: static const char * GetFormatAsCString (lldb::Format format); + // when DataExtractor dumps a vectorOfT, it uses a predefined format for each item + // this method returns it, or eFormatInvalid if vector_format is not a vectorOf + static lldb::Format + GetSingleItemFormat(lldb::Format vector_format); + void Changed() { diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index 182d078d9b3..87f41d90371 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -602,7 +602,9 @@ public: void ReadPointedString(Stream& s, Error& error, - uint32_t max_length = 0); + uint32_t max_length = 0, + bool honor_array = true, + lldb::Format item_format = lldb::eFormatCharArray); bool GetIsConstant () const @@ -741,6 +743,8 @@ protected: m_is_array_item_for_pointer:1, m_is_bitfield_for_scalar:1; + // used to prevent endless looping into GetpPrintableRepresentation() + uint32_t m_dump_printable_counter; friend class ClangExpressionDeclMap; // For GetValue friend class ClangExpressionVariable; // For SetName friend class Target; // For SetName diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 8b3b148fda3..41882a2fca6 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -403,6 +403,7 @@ 4CCA645813B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644A13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp */; }; 4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; }; 9415F61813B2C0EF00A52B36 /* FormatManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */; }; + 94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 94611EB113CCA4A4003A22AF /* RefCounter.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, ); }; }; @@ -1170,6 +1171,8 @@ 69A01E201236C5D400C660B5 /* TimeValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeValue.cpp; sourceTree = "<group>"; }; 9415F61613B2C0DC00A52B36 /* FormatManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = FormatManager.h; path = include/lldb/Core/FormatManager.h; sourceTree = "<group>"; }; 9415F61713B2C0EF00A52B36 /* FormatManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FormatManager.cpp; path = source/Core/FormatManager.cpp; sourceTree = "<group>"; }; + 94611EAF13CCA363003A22AF /* RefCounter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = RefCounter.h; path = include/lldb/Utility/RefCounter.h; sourceTree = "<group>"; }; + 94611EB113CCA4A4003A22AF /* RefCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RefCounter.cpp; path = source/Utility/RefCounter.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>"; }; @@ -1780,6 +1783,8 @@ isa = PBXGroup; children = ( 264723A511FA076E00DE380C /* CleanUp.h */, + 94611EAF13CCA363003A22AF /* RefCounter.h */, + 94611EB113CCA4A4003A22AF /* RefCounter.cpp */, 261B5A5211C3F2AD00AABD0A /* SharingPtr.cpp */, 4C2FAE2E135E3A70001EDE44 /* SharedCluster.h */, 261B5A5311C3F2AD00AABD0A /* SharingPtr.h */, @@ -3265,6 +3270,7 @@ 9467E65213C3D97600B3B6F3 /* TypeHierarchyNavigator.cpp in Sources */, 26ED3D6D13C563810017D45E /* OptionGroupVariable.cpp in Sources */, 26F4214413C6515B00E04E5E /* DynamicLoaderMacOSXKernel.cpp in Sources */, + 94611EB213CCA4A4003A22AF /* RefCounter.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/source/Core/DataExtractor.cpp b/lldb/source/Core/DataExtractor.cpp index 4cc98f31a65..aea0c471fcb 100644 --- a/lldb/source/Core/DataExtractor.cpp +++ b/lldb/source/Core/DataExtractor.cpp @@ -1610,8 +1610,11 @@ DataExtractor::Dump s->Printf("0x%8.8x", GetU32 (&offset)); break; - case eFormatVectorOfChar: - s->PutChar('{'); +// please keep the single-item formats below in sync with FormatManager::GetSingleItemFormat +// if you fail to do so, users will start getting different outputs depending on internal +// implementation details they should not care about || + case eFormatVectorOfChar: // || + s->PutChar('{'); // \/ offset = Dump (s, start_offset, eFormatCharArray, 1, item_byte_size, item_byte_size, LLDB_INVALID_ADDRESS, 0, 0); s->PutChar('}'); break; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 9b34331e84f..2c36dbb8c66 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -694,6 +694,7 @@ TestPromptFormats (StackFrame *frame) } } +// FIXME this should eventually be replaced by proper use of LLDB logging facilities //#define VERBOSE_FORMATPROMPT_OUTPUT #ifdef VERBOSE_FORMATPROMPT_OUTPUT #define IFERROR_PRINT_IT if (error.Fail()) \ @@ -1090,14 +1091,29 @@ Debugger::FormatPrompt IFERROR_PRINT_IT do_deref_pointer = false; } + + bool is_array = ClangASTContext::IsArrayType(target->GetClangType()); + bool is_pointer = ClangASTContext::IsPointerType(target->GetClangType()); + + if ((is_array || is_pointer) && (!is_array_range) && val_obj_display == ValueObject::eDisplayValue) // this should be wrong, but there are some exceptions + { +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("I am into array || pointer && !range\n"); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + // try to use the special cases + var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); + if (!var_success) + s << "<invalid, please use [] operator>"; +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("outcome was : %s\n", var_success ? "good" : "bad"); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + break; + } if (!is_array_range) var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); else - { - bool is_array = ClangASTContext::IsArrayType(target->GetClangType()); - bool is_pointer = ClangASTContext::IsPointerType(target->GetClangType()); - + { if (!is_array && !is_pointer) break; diff --git a/lldb/source/Core/FormatManager.cpp b/lldb/source/Core/FormatManager.cpp index ece30068e4d..040b9cd9ebd 100644 --- a/lldb/source/Core/FormatManager.cpp +++ b/lldb/source/Core/FormatManager.cpp @@ -187,3 +187,33 @@ FormatNavigator<lldb::RegularExpressionSP, SummaryFormat>::Delete(const char* ty } return false; } + +lldb::Format +FormatManager::GetSingleItemFormat(lldb::Format vector_format) +{ + switch(vector_format) + { + case eFormatVectorOfChar: + return eFormatCharArray; + + case eFormatVectorOfSInt8: + case eFormatVectorOfSInt16: + case eFormatVectorOfSInt32: + case eFormatVectorOfSInt64: + return eFormatDecimal; + + case eFormatVectorOfUInt8: + case eFormatVectorOfUInt16: + case eFormatVectorOfUInt32: + case eFormatVectorOfUInt64: + case eFormatVectorOfUInt128: + return eFormatHex; + + case eFormatVectorOfFloat32: + case eFormatVectorOfFloat64: + return eFormatFloat; + + default: + return lldb::eFormatInvalid; + } +} diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index d39b836f021..d8e0e0f8ef8 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -40,8 +40,11 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/Utility/RefCounter.h" + using namespace lldb; using namespace lldb_private; +using namespace lldb_utility; static lldb::user_id_t g_value_obj_uid = 0; @@ -78,7 +81,8 @@ ValueObject::ValueObject (ValueObject &parent) : m_last_format_mgr_revision(0), m_last_summary_format(), m_last_value_format(), - m_forced_summary_format() + m_forced_summary_format(), + m_dump_printable_counter(0) { m_manager->ManageObject(this); } @@ -116,7 +120,8 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) : m_last_format_mgr_revision(0), m_last_summary_format(), m_last_value_format(), - m_forced_summary_format() + m_forced_summary_format(), + m_dump_printable_counter(0) { m_manager = new ValueObjectManager(); m_manager->ManageObject (this); @@ -752,11 +757,13 @@ ValueObject::IsCStringContainer(bool check_pointer) void ValueObject::ReadPointedString(Stream& s, Error& error, - uint32_t max_length) + uint32_t max_length, + bool honor_array, + lldb::Format item_format) { if (max_length == 0) - max_length = 128; // this should be a setting, or a formatting parameter + max_length = 128; // FIXME this should be a setting, or a formatting parameter clang_type_t clang_type = GetClangType(); clang_type_t elem_or_pointee_clang_type; @@ -781,14 +788,10 @@ ValueObject::ReadPointedString(Stream& s, { // We have an array cstr_len = ClangASTContext::GetArraySize (clang_type); - if (cstr_len > max_length) // TODO: make cap a setting + if (cstr_len > max_length) { - cstr_len = ClangASTContext::GetArraySize (clang_type); - if (cstr_len > max_length) // TODO: make cap a setting - { - capped_data = true; - cstr_len = max_length; - } + capped_data = true; + cstr_len = max_length; } cstr_address = GetAddressOf (cstr_address_type, true); } @@ -803,9 +806,8 @@ ValueObject::ReadPointedString(Stream& s, DataExtractor data; size_t bytes_read = 0; std::vector<char> data_buffer; - Error error; bool prefer_file_cache = false; - if (cstr_len > 0) + if (cstr_len > 0 && honor_array) { data_buffer.resize(cstr_len); data.SetData (&data_buffer.front(), data_buffer.size(), lldb::endian::InlHostByteOrder()); @@ -819,7 +821,7 @@ ValueObject::ReadPointedString(Stream& s, s << '"'; data.Dump (&s, 0, // Start offset in "data" - eFormatCharArray, // Print as characters + item_format, 1, // Size of item (1 byte for a char!) bytes_read, // How many bytes to print? UINT32_MAX, // num per line @@ -833,7 +835,8 @@ ValueObject::ReadPointedString(Stream& s, } else { - const size_t k_max_buf_size = 256; + cstr_len = max_length; + const size_t k_max_buf_size = 64; data_buffer.resize (k_max_buf_size + 1); // NULL terminate in case we don't get the entire C string data_buffer.back() = '\0'; @@ -852,10 +855,12 @@ ValueObject::ReadPointedString(Stream& s, break; if (len > bytes_read) len = bytes_read; + if (len > cstr_len) + len = cstr_len; data.Dump (&s, 0, // Start offset in "data" - eFormatCharArray, // Print as characters + item_format, 1, // Size of item (1 byte for a char!) len, // How many bytes to print? UINT32_MAX, // num per line @@ -865,6 +870,12 @@ ValueObject::ReadPointedString(Stream& s, if (len < k_max_buf_size) break; + if (len >= cstr_len) + { + s << "..."; + break; + } + cstr_len -= len; cstr_so_addr.Slide (k_max_buf_size); } s << '"'; @@ -1016,6 +1027,9 @@ const char * ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display, lldb::Format custom_format) { + + RefCounter ref(&m_dump_printable_counter); + if(custom_format != lldb::eFormatInvalid) SetFormat(custom_format); @@ -1034,18 +1048,18 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d break; } - if (!return_value) + // this code snippet might lead to endless recursion, thus we use a RefCounter here to + // check that we are not looping endlessly + if (!return_value && (m_dump_printable_counter < 3)) { // 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 = ""; } - return (return_value ? return_value : ""); + return (return_value ? return_value : "<error>"); } @@ -1054,25 +1068,129 @@ ValueObject::DumpPrintableRepresentation(Stream& s, ValueObjectRepresentationStyle val_obj_display, lldb::Format custom_format) { + + clang_type_t elem_or_pointee_type; + Flags flags(ClangASTContext::GetTypeInfo(GetClangType(), GetClangAST(), &elem_or_pointee_type)); - if (IsCStringContainer(true) && - val_obj_display == ValueObject::eDisplayValue && - custom_format == lldb::eFormatCString) + if (flags.AnySet(ClangASTContext::eTypeIsArray | ClangASTContext::eTypeIsPointer) + && val_obj_display == ValueObject::eDisplayValue) { - Error error; - ReadPointedString(s, error); - return error.Success(); - } - else - { - 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; + // when being asked to get a printable display an array or pointer type directly, + // try to "do the right thing" + + if (IsCStringContainer(true) && + (custom_format == lldb::eFormatCString || + custom_format == lldb::eFormatCharArray || + custom_format == lldb::eFormatChar || + custom_format == lldb::eFormatVectorOfChar)) // print char[] & char* directly + { + Error error; + ReadPointedString(s, + error, + 0, + (custom_format == lldb::eFormatVectorOfChar) || + (custom_format == lldb::eFormatCharArray)); + return !error.Fail(); + } + + if (custom_format == lldb::eFormatEnum) + return false; + + // this only works for arrays, because I have no way to know when + // the pointed memory ends, and no special \0 end of data marker + if (flags.Test(ClangASTContext::eTypeIsArray)) + { + if ((custom_format == lldb::eFormatBytes) || + (custom_format == lldb::eFormatBytesWithASCII)) + { + uint32_t count = GetNumChildren(); + + s << '['; + for (uint32_t low = 0; low < count; low++) + { + + if (low) + s << ','; + + ValueObjectSP child = GetChildAtIndex(low,true); + if (!child.get()) + { + s << "<error>"; + continue; + } + child->DumpPrintableRepresentation(s, ValueObject::eDisplayValue, custom_format); + } + + s << ']'; + + return true; + } + + if ((custom_format == lldb::eFormatVectorOfChar) || + (custom_format == lldb::eFormatVectorOfFloat32) || + (custom_format == lldb::eFormatVectorOfFloat64) || + (custom_format == lldb::eFormatVectorOfSInt16) || + (custom_format == lldb::eFormatVectorOfSInt32) || + (custom_format == lldb::eFormatVectorOfSInt64) || + (custom_format == lldb::eFormatVectorOfSInt8) || + (custom_format == lldb::eFormatVectorOfUInt128) || + (custom_format == lldb::eFormatVectorOfUInt16) || + (custom_format == lldb::eFormatVectorOfUInt32) || + (custom_format == lldb::eFormatVectorOfUInt64) || + (custom_format == lldb::eFormatVectorOfUInt8)) // arrays of bytes, bytes with ASCII or any vector format should be printed directly + { + uint32_t count = GetNumChildren(); + + lldb::Format format = FormatManager::GetSingleItemFormat(custom_format); + + s << '['; + for (uint32_t low = 0; low < count; low++) + { + + if (low) + s << ','; + + ValueObjectSP child = GetChildAtIndex(low,true); + if (!child.get()) + { + s << "<error>"; + continue; + } + child->DumpPrintableRepresentation(s, ValueObject::eDisplayValue, format); + } + + s << ']'; + + return true; + } + } + + if ((custom_format == lldb::eFormatBoolean) || + (custom_format == lldb::eFormatBinary) || + (custom_format == lldb::eFormatChar) || + (custom_format == lldb::eFormatCharPrintable) || + (custom_format == lldb::eFormatComplexFloat) || + (custom_format == lldb::eFormatDecimal) || + (custom_format == lldb::eFormatHex) || + (custom_format == lldb::eFormatFloat) || + (custom_format == lldb::eFormatOctal) || + (custom_format == lldb::eFormatOSType) || + (custom_format == lldb::eFormatUnicode16) || + (custom_format == lldb::eFormatUnicode32) || + (custom_format == lldb::eFormatUnsigned) || + (custom_format == lldb::eFormatPointer) || + (custom_format == lldb::eFormatComplexInteger) || + (custom_format == lldb::eFormatComplex) || + (custom_format == lldb::eFormatDefault)) // use the [] operator + return false; } + 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 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 12f6b6d0ba9..f5a206b39f4 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py @@ -97,7 +97,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("type summary add -f \"arr = ${var%s}\" -x \"char \\[[0-9]+\\]\" -v") self.expect("frame variable strarr", - substrs = ['arr = "Hello world!\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"']) + substrs = ['arr = "Hello world!"']) self.runCmd("type summary clear") @@ -109,7 +109,7 @@ class DataFormatterTestCase(TestBase): self.runCmd("type summary add -f \"arr = ${var%s}\" -x \"char \\[[0-9]+\\]\" -v") self.expect("frame variable strarr", - substrs = ['arr = "Hello world!\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0\\0"']) + substrs = ['arr = "Hello world!']) self.expect("frame variable strptr", substrs = ['ptr = "Hello world!"']) diff --git a/lldb/www/varformats.html b/lldb/www/varformats.html index dadc7c73a46..a0d87072339 100755 --- a/lldb/www/varformats.html +++ b/lldb/www/varformats.html @@ -97,8 +97,13 @@ variables in your program to print out as hex, you can add a format to the <code>int</code> type.<br></p> - <p>This is done by typing <code>type format add -f hex - int</code> at the LLDB command line.</p> + <p>This is done by typing + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> type format add -f hex int + </td> + <table> + at the LLDB command line.</p> <p>The <code>-f</code> option accepts a <a href="#formatstable">format name</a>, and a list of @@ -124,8 +129,12 @@ untouched for other types.</p> <p>If you simply type <br> - <code>type format add -f hex A<br> - type format add -f pointer C</code><br> + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> type format add -f hex A<br> + <b>(lldb)</b> type format add -f pointer C + </td> + <table> <br> values of type <code>B</code> will be shown as hex and values of type <code>D</code> as pointers.</p> @@ -135,8 +144,12 @@ you can use the option <code>-C no</code> to prevent cascading, thus making the two commands required to achieve your goal:<br> - <code> type format add -f hex -C no A<br> - type format add -f pointer -C no C </code></p> + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> type format add -C no -f hex A<br> + <b>(lldb)</b> type format add -C no -f pointer C + </td> + <table> <p>Two additional options that you will want to look at are <code>-p</code> and <code>-r</code>. These two @@ -169,7 +182,11 @@ in a custom format, while leaving the others of the same type untouched, you can simply type:<br> <br> - <code>frame variable counter -f hex</code></p> + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> frame variable counter -f hex + </td> + <table> <p>This has the effect of displaying the value of <code>counter</code> as an hexadecimal number, and will keep showing it this @@ -365,42 +382,34 @@ <div class="post"> <h1 class="postheader">type summary</h1> <div class="postcontent"> - <p>Type summaries enable you to add more information to - the default viewing format for a type, or to completely - replace it with your own display option. Unlike formats - which only apply to basic types, summaries can be used - on every type (basic types, classes (C++ and - Objective-C), arrays, ...).</p> - <p>The basic idea beneath type summaries is extracting - information from variables and arranging it in a format - that is suitable for display:</p> + <p>Type formats work by showing a different kind of display for + the value of a variable. However, they only work for basic types. + When you want to display a class or struct in a custom format, you + cannot do that using formats.</p> + <p>A different feature, type summaries, works by extracting + information from classes, structures, ... (<i>aggregate types</i>) + and arranging it in a user-defined format, as in the following example:</p> <p> <i>before adding a summary...</i><br> <code> <b>(lldb)</b> fr var -T one<br> (i_am_cool) one = {<br> - (int) integer = 3<br> - (float) floating = 3.14159<br> - (char) character = 'E'<br> + (int) integer = 3<br> + (float) floating = 3.14159<br> + (char) character = 'E'<br> }<br> </code> <br> <i>after adding a summary...</i><br> <code> <b>(lldb)</b> fr var one<br> (i_am_cool) one = int = 3, float = 3.14159, char = 69<br> </code> </p> - <p>Evidently, somehow we managed to tell LLDB to grab the - three member variables of the <code>i_am_cool</code> - datatype, mix their values with some text, and even ask - it to display the <code>character</code> member using a - custom format.</p> - <p>The way to do this is add a <i>summary string</i> to + <p>The way to obtain this effect is to bind a <i>summary string</i> to the datatype using the <code>type summary add</code> command.</p> - <p>Its syntax is similar to <code>type format add</code>, - but some more options are supported that will be - described in the follow-up.</p> - <p>The main option to <code>type summary add</code> is <code>-f</code> - which accepts as parameter a summary string. After that, - you can type as many type names as you want to associate - the given summary string to them.</p> + <p>In the example, the command we type was:</p> + <table class="stats" width="620" cellspacing="0"> + <td class="content"> + <b>(lldb)</b> frame variable counter -f hex + </td> + <table> </div> </div> <div class="post"> @@ -687,7 +696,13 @@ classes, look at the virtual base classes (and bases of bases, ...)</li> <li>If this object's type is a typedef, go through - typedef hierarchy</li> + typedef hierarchy (LLDB might not be able to do this if + the compiler has not emitted enough information. If the + required information to traverse typedef hierarchies is + missing, type cascading will not work. The + <a href="http://clang.llvm.org/">clang compiler</a>, + part of the LLVM project, emits the correct debugging + information for LLDB to cascade)</li> <li>If everything has failed, repeat the above search, looking for regular expressions instead of exact matches</li> |