diff options
-rw-r--r-- | lldb/include/lldb/Core/ValueObject.h | 120 | ||||
-rw-r--r-- | lldb/include/lldb/Interpreter/CommandObject.h | 12 | ||||
-rw-r--r-- | lldb/lldb.xcodeproj/project.pbxproj | 6 | ||||
-rw-r--r-- | lldb/source/Core/Debugger.cpp | 192 | ||||
-rw-r--r-- | lldb/source/Core/ValueObject.cpp | 406 | ||||
-rw-r--r-- | lldb/source/Interpreter/CommandObject.cpp | 4 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py | 13 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp | 41 | ||||
-rw-r--r-- | lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py | 6 | ||||
-rwxr-xr-x | lldb/www/varformats.html | 1293 |
10 files changed, 1417 insertions, 676 deletions
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index fe7219770f8..ef3bc9229d7 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -73,10 +73,111 @@ public: enum ValueObjectRepresentationStyle { - eDisplayValue, + eDisplayValue = 1, eDisplaySummary, eDisplayLanguageSpecific }; + + enum ExpressionPathScanEndReason + { + eEndOfString = 1, // out of data to parse + eNoSuchChild, // child element not found + eEmptyRangeNotAllowed, // [] only allowed for arrays + eDotInsteadOfArrow, // . used when -> should be used + eArrowInsteadOfDot, // -> used when . should be used + eFragileIVarNotAllowed, // ObjC ivar expansion not allowed + eRangeOperatorNotAllowed, // [] not allowed by options + eRangeOperatorInvalid, // [] not valid on objects other than scalars, pointers or arrays + eArrayRangeOperatorMet, // [] is good for arrays, but I cannot parse it + eBitfieldRangeOperatorMet, // [] is good for bitfields, but I cannot parse after it + eUnexpectedSymbol, // something is malformed in the expression + eTakingAddressFailed, // impossible to apply & operator + eDereferencingFailed, // impossible to apply * operator + eUnknown = 0xFFFF + }; + + enum ExpressionPathEndResultType + { + ePlain = 1, // anything but... + eBitfield, // a bitfield + eBoundedRange, // a range [low-high] + eUnboundedRange, // a range [] + eInvalid = 0xFFFF + }; + + enum ExpressionPathAftermath + { + eNothing = 1, // just return it + eDereference, // dereference the target + eTakeAddress // take target's address + }; + + struct GetValueForExpressionPathOptions + { + bool m_check_dot_vs_arrow_syntax; + bool m_no_fragile_ivar; + bool m_allow_bitfields_syntax; + + GetValueForExpressionPathOptions(bool dot = false, + bool no_ivar = false, + bool bitfield = true) : + m_check_dot_vs_arrow_syntax(dot), + m_no_fragile_ivar(no_ivar), + m_allow_bitfields_syntax(bitfield) + { + } + + GetValueForExpressionPathOptions& + DoCheckDotVsArrowSyntax() + { + m_check_dot_vs_arrow_syntax = true; + return *this; + } + + GetValueForExpressionPathOptions& + DontCheckDotVsArrowSyntax() + { + m_check_dot_vs_arrow_syntax = false; + return *this; + } + + GetValueForExpressionPathOptions& + DoAllowFragileIVar() + { + m_no_fragile_ivar = false; + return *this; + } + + GetValueForExpressionPathOptions& + DontAllowFragileIVar() + { + m_no_fragile_ivar = true; + return *this; + } + + GetValueForExpressionPathOptions& + DoAllowBitfieldSyntax() + { + m_allow_bitfields_syntax = true; + return *this; + } + + GetValueForExpressionPathOptions& + DontAllowBitfieldSyntax() + { + m_allow_bitfields_syntax = false; + return *this; + } + + static const GetValueForExpressionPathOptions + DefaultOptions() + { + static GetValueForExpressionPathOptions g_default_options; + + return g_default_options; + } + + }; class EvaluationPoint { @@ -280,6 +381,14 @@ public: virtual void GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExpressionPathFormat = eDereferencePointers); + lldb::ValueObjectSP + GetValueForExpressionPath(const char* expression, + const char** first_unparsed = NULL, + ExpressionPathScanEndReason* reason_to_stop = NULL, + ExpressionPathEndResultType* final_value_type = NULL, + const GetValueForExpressionPathOptions& options = GetValueForExpressionPathOptions::DefaultOptions(), + ExpressionPathAftermath* final_task_on_target = NULL); + virtual bool IsInScope () { @@ -636,6 +745,15 @@ private: //------------------------------------------------------------------ // For ValueObject only //------------------------------------------------------------------ + + lldb::ValueObjectSP + GetValueForExpressionPath_Impl(const char* expression, + const char** first_unparsed, + ExpressionPathScanEndReason* reason_to_stop, + ExpressionPathEndResultType* final_value_type, + const GetValueForExpressionPathOptions& options, + ExpressionPathAftermath* final_task_on_target); + DISALLOW_COPY_AND_ASSIGN (ValueObject); }; diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h index 0503e84fff8..f14ff605b5c 100644 --- a/lldb/include/lldb/Interpreter/CommandObject.h +++ b/lldb/include/lldb/Interpreter/CommandObject.h @@ -33,6 +33,18 @@ public: { ArgumentHelpCallbackFunction *help_callback; bool self_formatting; + + const char* + operator () () const + { + return (*help_callback)(); + } + + operator bool() const + { + return (help_callback != NULL); + } + }; struct ArgumentTableEntry // Entries in the main argument information table diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 2f0e751889d..8b3b148fda3 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -1786,12 +1786,12 @@ 26F996A7119B79C300412154 /* ARM_DWARF_Registers.h */, 26ECA04213665FED008D1F18 /* ARM_DWARF_Registers.cpp */, 26F996A8119B79C300412154 /* ARM_GCC_Registers.h */, - 2660D9F611922A1300958FBD /* StringExtractor.cpp */, 2660D9F711922A1300958FBD /* StringExtractor.h */, - 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */, + 2660D9F611922A1300958FBD /* StringExtractor.cpp */, 2676A094119C93C8008A98EF /* StringExtractorGDBRemote.h */, - 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */, + 2676A093119C93C8008A98EF /* StringExtractorGDBRemote.cpp */, 2682F16B115EDA0D00CCFF99 /* PseudoTerminal.h */, + 2682F16A115EDA0D00CCFF99 /* PseudoTerminal.cpp */, ); name = Utility; sourceTree = "<group>"; diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp index 763fa258cea..e7b97a59077 100644 --- a/lldb/source/Core/Debugger.cpp +++ b/lldb/source/Core/Debugger.cpp @@ -694,7 +694,7 @@ TestPromptFormats (StackFrame *frame) } } -// #define VERBOSE_FORMATPROMPT_OUTPUT +//#define VERBOSE_FORMATPROMPT_OUTPUT #ifdef VERBOSE_FORMATPROMPT_OUTPUT #define IFERROR_PRINT_IT if (error.Fail()) \ { \ @@ -832,35 +832,41 @@ static ValueObjectSP ExpandIndexedExpression(ValueObject* vobj, uint32_t index, StackFrame* frame, - Error error) + bool deref_pointer) { - 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(); + const char* ptr_deref_format = "[%d]"; + std::auto_ptr<char> ptr_deref_buffer(new char[10]); + ::sprintf(ptr_deref_buffer.get(), ptr_deref_format, index); #ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("name to deref in phase 0: %s\n",expr_path); + printf("name to deref: %s\n",ptr_deref_buffer.get()); #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); + const char* first_unparsed; + ValueObject::GetValueForExpressionPathOptions options; + ValueObject::ExpressionPathEndResultType final_value_type; + ValueObject::ExpressionPathScanEndReason reason_to_stop; + ValueObject::ExpressionPathAftermath what_next = (deref_pointer ? ValueObject::eDereference : ValueObject::eNothing); + ValueObjectSP item = vobj->GetValueForExpressionPath (ptr_deref_buffer.get(), + &first_unparsed, + &reason_to_stop, + &final_value_type, + options, + &what_next); + if (!item) + { +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("ERROR: unparsed portion = %s, why stopping = %d," + " final_value_type %d\n", + first_unparsed, reason_to_stop, final_value_type); #endif //VERBOSE_FORMATPROMPT_OUTPUT - lldb::VariableSP var_sp; - item = frame->GetValueForVariableExpressionPath (ptr_deref_buffer, - eNoDynamicValues, - 0, - var_sp, - error); - delete ptr_deref_buffer; } +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + else + { + printf("ALL RIGHT: unparsed portion = %s, why stopping = %d," + " final_value_type %d\n", + first_unparsed, reason_to_stop, final_value_type); + } +#endif //VERBOSE_FORMATPROMPT_OUTPUT return item; } @@ -954,8 +960,9 @@ Debugger::FormatPrompt const RegisterInfo *reg_info = NULL; RegisterContext *reg_ctx = NULL; bool do_deref_pointer = false; - bool did_deref_pointer = true; - + ValueObject::ExpressionPathScanEndReason reason_to_stop; + ValueObject::ExpressionPathEndResultType final_value_type; + // Each variable must set success to true below... bool var_success = false; switch (var_name_begin[0]) @@ -971,6 +978,10 @@ Debugger::FormatPrompt case 'v': { + ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ? + ValueObject::eDereference : ValueObject::eNothing); + ValueObject::GetValueForExpressionPathOptions options; + options.DontCheckDotVsArrowSyntax().DoAllowBitfieldSyntax().DoAllowFragileIVar(); ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary; ValueObject* target = NULL; lldb::Format custom_format = eFormatInvalid; @@ -980,6 +991,8 @@ Debugger::FormatPrompt int64_t index_lower = -1; int64_t index_higher = -1; bool is_array_range = false; + const char* first_unparsed; + if (!vobj) break; // simplest case ${var}, just print vobj's value if (::strncmp (var_name_begin, "var}", strlen("var}")) == 0) @@ -1025,57 +1038,47 @@ Debugger::FormatPrompt &index_higher); Error error; - target = ExpandExpressionPath (vobj, - exe_ctx->frame, - &do_deref_pointer, - var_name_begin, - var_name_final, - error).get(); - - if (error.Fail() || !target) + + std::auto_ptr<char> expr_path(new char[var_name_final-var_name_begin-1]); + ::memset(expr_path.get(), 0, var_name_final-var_name_begin-1); + memcpy(expr_path.get(), var_name_begin+3,var_name_final-var_name_begin-3); + +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("symbol to expand: %s\n",expr_path.get()); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + + target = vobj->GetValueForExpressionPath(expr_path.get(), + &first_unparsed, + &reason_to_stop, + &final_value_type, + options, + &what_next).get(); + + if (!target) { #ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("ERROR: %s\n",error.AsCString("unknown")); + printf("ERROR: unparsed portion = %s, why stopping = %d," + " final_value_type %d\n", + first_unparsed, reason_to_stop, final_value_type); #endif //VERBOSE_FORMATPROMPT_OUTPUT - 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(); - } - - if (var_name_final_if_array_range && (error.Fail() || !target)) - { - bool fake_do_deref = false; - target = ExpandExpressionPath(vobj, - exe_ctx->frame, - &fake_do_deref, - var_name_begin, - var_name_final_if_array_range, - error).get(); - - did_deref_pointer = false; - - if (target && ClangASTContext::IsArrayType(target->GetClangType())) - error.Clear(); - else - error.SetErrorString("error in expression"); - } - - IFERROR_PRINT_IT - else - is_array_range = true; + break; } - - if (did_deref_pointer) - do_deref_pointer = false; // I have honored the request to deref - +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + else + { + printf("ALL RIGHT: unparsed portion = %s, why stopping = %d," + " final_value_type %d\n", + first_unparsed, reason_to_stop, final_value_type); + } +#endif //VERBOSE_FORMATPROMPT_OUTPUT } else break; + + is_array_range = (final_value_type == ValueObject::eBoundedRange || + final_value_type == ValueObject::eUnboundedRange); + + do_deref_pointer = (what_next == ValueObject::eDereference); if (do_deref_pointer && !is_array_range) { @@ -1092,30 +1095,22 @@ Debugger::FormatPrompt var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); else { - bool is_array = ClangASTContext::IsArrayType(vobj->GetClangType()); - bool is_pointer = ClangASTContext::IsPointerType(vobj->GetClangType()); + bool is_array = ClangASTContext::IsArrayType(target->GetClangType()); + bool is_pointer = ClangASTContext::IsPointerType(target->GetClangType()); if (!is_array && !is_pointer) break; - char* special_directions = NULL; + const char* special_directions = NULL; + StreamString special_directions_writer; if (close_bracket_position && (var_name_end-close_bracket_position > 1)) { - int base_len = var_name_end-close_bracket_position; - special_directions = new char[7+base_len]; - int star_offset = (do_deref_pointer ? 1 : 0); - special_directions[0] = '$'; - special_directions[1] = '{'; - if (do_deref_pointer) - special_directions[2] = '*'; - special_directions[2+star_offset] = 'v'; - special_directions[3+star_offset] = 'a'; - special_directions[4+star_offset] = 'r'; - memcpy(special_directions+5+star_offset, close_bracket_position+1, base_len); - special_directions[base_len+5+star_offset] = '\0'; -#ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("%s\n",special_directions); -#endif //VERBOSE_FORMATPROMPT_OUTPUT + ConstString additional_data; + additional_data.SetCStringWithLength(close_bracket_position+1, var_name_end-close_bracket_position-1); + special_directions_writer.Printf("${%svar%s}", + do_deref_pointer ? "*" : "", + additional_data.GetCString()); + special_directions = special_directions_writer.GetData(); } // let us display items index_lower thru index_higher of this array @@ -1127,13 +1122,24 @@ Debugger::FormatPrompt for (;index_lower<=index_higher;index_lower++) { - Error error; - ValueObject* item = ExpandIndexedExpression(vobj, + ValueObject* item = ExpandIndexedExpression(target, index_lower, exe_ctx->frame, - error).get(); + false).get(); - IFERROR_PRINT_IT + if (!item) + { +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("ERROR\n"); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + } +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + else + { + printf("special_directions: %s\n",special_directions); + } +#endif //VERBOSE_FORMATPROMPT_OUTPUT + if (!special_directions) var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format); else diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 918be0923c3..1c8a7051217 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -1366,6 +1366,412 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp } } +lldb::ValueObjectSP +ValueObject::GetValueForExpressionPath(const char* expression, + const char** first_unparsed, + ExpressionPathScanEndReason* reason_to_stop, + ExpressionPathEndResultType* final_value_type, + const GetValueForExpressionPathOptions& options, + ExpressionPathAftermath* final_task_on_target) +{ + + const char* dummy_first_unparsed; + ExpressionPathScanEndReason dummy_reason_to_stop; + ExpressionPathEndResultType dummy_final_value_type; + ExpressionPathAftermath dummy_final_task_on_target = ValueObject::eNothing; + + ValueObjectSP ret_val = GetValueForExpressionPath_Impl(expression, + first_unparsed ? first_unparsed : &dummy_first_unparsed, + reason_to_stop ? reason_to_stop : &dummy_reason_to_stop, + final_value_type ? final_value_type : &dummy_final_value_type, + options, + final_task_on_target ? final_task_on_target : &dummy_final_task_on_target); + + if (!final_task_on_target || *final_task_on_target == ValueObject::eNothing) + { + return ret_val; + } + if (ret_val.get() && *final_value_type == ePlain) // I can only deref and takeaddress of plain objects + { + if (*final_task_on_target == ValueObject::eDereference) + { + Error error; + ValueObjectSP final_value = ret_val->Dereference(error); + if (error.Fail() || !final_value.get()) + { + *reason_to_stop = ValueObject::eDereferencingFailed; + *final_value_type = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *final_task_on_target = ValueObject::eNothing; + return final_value; + } + } + if (*final_task_on_target == ValueObject::eTakeAddress) + { + Error error; + ValueObjectSP final_value = ret_val->AddressOf(error); + if (error.Fail() || !final_value.get()) + { + *reason_to_stop = ValueObject::eTakingAddressFailed; + *final_value_type = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *final_task_on_target = ValueObject::eNothing; + return final_value; + } + } + } + return ret_val; // final_task_on_target will still have its original value, so you know I did not do it +} + +lldb::ValueObjectSP +ValueObject::GetValueForExpressionPath_Impl(const char* expression_cstr, + const char** first_unparsed, + ExpressionPathScanEndReason* reason_to_stop, + ExpressionPathEndResultType* final_result, + const GetValueForExpressionPathOptions& options, + ExpressionPathAftermath* what_next) +{ + ValueObjectSP root = GetSP(); + + if (!root.get()) + return ValueObjectSP(); + + *first_unparsed = expression_cstr; + + while (true) + { + + const char* expression_cstr = *first_unparsed; // hide the top level expression_cstr + + lldb::clang_type_t root_clang_type = root->GetClangType(); + + if (!expression_cstr || *expression_cstr == '\0') + { + *reason_to_stop = ValueObject::eEndOfString; + return root; + } + + switch (*expression_cstr) + { + case '-': + { + if (options.m_check_dot_vs_arrow_syntax && + !ClangASTContext::IsPointerType(root_clang_type)) // if you are trying to use -> on a non-pointer and I must catch the error + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eArrowInsteadOfDot; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + const uint32_t pointer_type_flags = ClangASTContext::GetTypeInfo (root_clang_type, NULL, NULL); + if ((pointer_type_flags & ClangASTContext::eTypeIsObjC) && // if yo are trying to extract an ObjC IVar when this is forbidden + (pointer_type_flags & ClangASTContext::eTypeIsPointer) && + options.m_no_fragile_ivar) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eFragileIVarNotAllowed; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + if (expression_cstr[1] != '>') + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eUnexpectedSymbol; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + expression_cstr++; // skip the - + } + case '.': // or fallthrough from -> + { + if (options.m_check_dot_vs_arrow_syntax && *expression_cstr == '.' && + ClangASTContext::IsPointerType(root_clang_type)) // if you are trying to use . on a pointer and I must catch the error + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eDotInsteadOfArrow; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + expression_cstr++; // skip . + const char *next_separator = strpbrk(expression_cstr+1,"-.["); + ConstString child_name; + if (!next_separator) // if no other separator just expand this last layer + { + child_name.SetCString (expression_cstr); + root = root->GetChildMemberWithName(child_name, true); + if (root.get()) // we know we are done, so just return + { + *first_unparsed = '\0'; + *reason_to_stop = ValueObject::eEndOfString; + *final_result = ValueObject::ePlain; + return root; + } + else + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eNoSuchChild; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + } + else // other layers do expand + { + child_name.SetCStringWithLength(expression_cstr, next_separator - expression_cstr); + root = root->GetChildMemberWithName(child_name, true); + if (root.get()) // store the new root and move on + { + *first_unparsed = next_separator; + *final_result = ValueObject::ePlain; + continue; + } + else + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eNoSuchChild; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + } + break; + } + case '[': + { + if (!ClangASTContext::IsArrayType(root_clang_type) && !ClangASTContext::IsPointerType(root_clang_type)) // if this is not a T[] nor a T* + { + if (!ClangASTContext::IsScalarType(root_clang_type)) // if this is not even a scalar, this syntax is just plain wrong! + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eRangeOperatorInvalid; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else if (!options.m_allow_bitfields_syntax) // if this is a scalar, check that we can expand bitfields + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eRangeOperatorNotAllowed; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + } + if (*(expression_cstr+1) == ']') // if this is an unbounded range it only works for arrays + { + if (!ClangASTContext::IsArrayType(root_clang_type)) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eEmptyRangeNotAllowed; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else // even if something follows, we cannot expand unbounded ranges, just let the caller do it + { + *first_unparsed = expression_cstr+2; + *reason_to_stop = ValueObject::eArrayRangeOperatorMet; + *final_result = ValueObject::eUnboundedRange; + return root; + } + } + const char *separator_position = ::strchr(expression_cstr+1,'-'); + const char *close_bracket_position = ::strchr(expression_cstr+1,']'); + if (!close_bracket_position) // if there is no ], this is a syntax error + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eUnexpectedSymbol; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + if (!separator_position || separator_position > close_bracket_position) // if no separator, this is either [] or [N] + { + char *end = NULL; + unsigned long index = ::strtoul (expression_cstr+1, &end, 0); + if (!end || end != close_bracket_position) // if something weird is in our way return an error + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eUnexpectedSymbol; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + if (end - expression_cstr == 1) // if this is [], only return a valid value for arrays + { + if (ClangASTContext::IsArrayType(root_clang_type)) + { + *first_unparsed = expression_cstr+2; + *reason_to_stop = ValueObject::eArrayRangeOperatorMet; + *final_result = ValueObject::eUnboundedRange; + return root; + } + else + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eEmptyRangeNotAllowed; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + } + // from here on we do have a valid index + if (ClangASTContext::IsArrayType(root_clang_type)) + { + root = root->GetChildAtIndex(index, true); + if (!root.get()) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eNoSuchChild; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *first_unparsed = end+1; // skip ] + *final_result = ValueObject::ePlain; + continue; + } + } + else if (ClangASTContext::IsPointerType(root_clang_type)) + { + if (*what_next == ValueObject::eDereference && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield + ClangASTContext::IsScalarType(clang::QualType::getFromOpaquePtr(root_clang_type).getTypePtr()->getPointeeType().getAsOpaquePtr())) + { + Error error; + root = root->Dereference(error); + if (error.Fail() || !root.get()) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eDereferencingFailed; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *what_next = eNothing; + continue; + } + } + else + { + root = root->GetSyntheticArrayMemberFromPointer(index, true); + if (!root.get()) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eNoSuchChild; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *first_unparsed = end+1; // skip ] + *final_result = ValueObject::ePlain; + continue; + } + } + } + else /*if (ClangASTContext::IsScalarType(root_clang_type))*/ + { + root = root->GetSyntheticBitFieldChild(index, index, true); + if (!root.get()) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eNoSuchChild; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else // we do not know how to expand members of bitfields, so we just return and let the caller do any further processing + { + *first_unparsed = end+1; // skip ] + *reason_to_stop = ValueObject::eBitfieldRangeOperatorMet; + *final_result = ValueObject::eBitfield; + return root; + } + } + } + else // we have a low and a high index + { + char *end = NULL; + unsigned long index_lower = ::strtoul (expression_cstr+1, &end, 0); + if (!end || end != separator_position) // if something weird is in our way return an error + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eUnexpectedSymbol; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + unsigned long index_higher = ::strtoul (separator_position+1, &end, 0); + if (!end || end != close_bracket_position) // if something weird is in our way return an error + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eUnexpectedSymbol; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + if (index_lower > index_higher) // swap indices if required + { + unsigned long temp = index_lower; + index_lower = index_higher; + index_higher = temp; + } + if (ClangASTContext::IsScalarType(root_clang_type)) // expansion only works for scalars + { + root = root->GetSyntheticBitFieldChild(index_lower, index_higher, true); + if (!root.get()) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eNoSuchChild; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *first_unparsed = end+1; // skip ] + *reason_to_stop = ValueObject::eBitfieldRangeOperatorMet; + *final_result = ValueObject::eBitfield; + return root; + } + } + else if (ClangASTContext::IsPointerType(root_clang_type) && // if this is a ptr-to-scalar, I am accessing it by index and I would have deref'ed anyway, then do it now and use this as a bitfield + *what_next == ValueObject::eDereference && + ClangASTContext::IsScalarType(clang::QualType::getFromOpaquePtr(root_clang_type).getTypePtr()->getPointeeType().getAsOpaquePtr())) + { + Error error; + root = root->Dereference(error); + if (error.Fail() || !root.get()) + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eDereferencingFailed; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + } + else + { + *what_next = ValueObject::eNothing; + continue; + } + } + else + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eArrayRangeOperatorMet; + *final_result = ValueObject::eBoundedRange; + return root; + } + } + break; + } + default: // some non-separator is in the way + { + *first_unparsed = expression_cstr; + *reason_to_stop = ValueObject::eUnexpectedSymbol; + *final_result = ValueObject::eInvalid; + return ValueObjectSP(); + break; + } + } + } +} + void ValueObject::DumpValueObject ( diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp index 95c0ad689e4..4449007db6f 100644 --- a/lldb/source/Interpreter/CommandObject.cpp +++ b/lldb/source/Interpreter/CommandObject.cpp @@ -469,9 +469,9 @@ CommandObject::GetArgumentHelp (Stream &str, CommandArgumentType arg_type, Comma StreamString name_str; name_str.Printf ("<%s>", entry->arg_name); - if (entry->help_function.help_callback) + if (entry->help_function) { - const char* help_text = (*entry->help_function.help_callback)(); + const char* help_text = entry->help_function(); if (!entry->help_function.self_formatting) { interpreter.OutputFormattedHelpText (str, name_str.GetData(), "--", help_text, 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 9184b7c45cc..6c91fc47140 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-advanced/TestDataFormatterAdv.py @@ -159,6 +159,19 @@ class DataFormatterTestCase(TestBase): substrs = ['0x', '7']) + self.runCmd("type summary clear") + + self.runCmd("type summary add -f \"${*var[].x[0-3]%hex} is a bitfield on a set of integers\" -x \"SimpleWithPointers \[[0-9]\]\"") + self.runCmd("type summary add -f \"${*var.sp.x[0-2]} are low bits of integer ${*var.sp.x}. If I pretend it is an array I get ${var.sp.x[0-5]}\" Couple") + + self.expect("frame variable couple", + substrs = ['1 are low bits of integer 9.', + 'If I pretend it is an array I get [9,']) + + self.expect("frame variable sparray", + substrs = ['[0x0000000f,0x0000000c,0x00000009]']) + + 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 da11fafff15..28b544dc741 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp +++ b/lldb/test/functionalities/data-formatter/data-formatter-advanced/main.cpp @@ -41,6 +41,38 @@ struct IWrapPointers IWrapPointers() : int_pointer(new int(4)), float_pointer(new float(1.111)) {} }; +struct Simple +{ + int x; + float y; + char z; + Simple(int X, float Y, char Z) : + x(X), + y(Y), + z(Z) + {} +}; + +struct SimpleWithPointers +{ + int *x; + float *y; + char *z; + SimpleWithPointers(int X, float Y, char Z) : + x(new int (X)), + y(new float (Y)), + z(new char (Z)) + {} +}; + +struct Couple +{ + SimpleWithPointers sp; + Simple* s; + Couple(int X, float Y, char Z) : sp(X,Y,Z), + s(new Simple(X,Y,Z)) {} +}; + int main (int argc, const char * argv[]) { @@ -66,6 +98,13 @@ int main (int argc, const char * argv[]) int* pointer = &cool_array[4].integer; IWrapPointers *wrap_pointer = &wrapper; - + + Couple couple(9,9.99,'X'); + + SimpleWithPointers sparray[] = + {SimpleWithPointers(-1,-2,'3'), + SimpleWithPointers(-4,-5,'6'), + SimpleWithPointers(-7,-8,'9')}; + 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 9f7e00ed905..68eab1897bd 100644 --- a/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py +++ b/lldb/test/functionalities/data-formatter/data-formatter-cpp/TestDataFormatterCpp.py @@ -99,6 +99,12 @@ class DataFormatterTestCase(TestBase): self.expect("frame variable iAmSomewhere", substrs = ['y=0x']) + + self.runCmd("type summary add -f \"y=${var.y},x=${var.x}\" Point") + + self.expect("frame variable iAmSomewhere", + substrs = ['y=6', + 'x=4']) self.runCmd("type summary add -f \"hello\" Point -e") diff --git a/lldb/www/varformats.html b/lldb/www/varformats.html index 13d7839df5a..dadc7c73a46 100755 --- a/lldb/www/varformats.html +++ b/lldb/www/varformats.html @@ -1,576 +1,717 @@ -<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
-<link href="style.css" rel="stylesheet" type="text/css" />
-<title>LLDB Homepage</title>
-</head>
-
-<body>
- <div class="www_title">
- The <strong>LLDB</strong> Debugger
- </div>
-
-<div id="container">
- <div id="content">
- <!--#include virtual="sidebar.incl"-->
-
- <div id="middle">
- <div class="post">
- <h1 class ="postheader">Variable display</h1>
- <div class="postcontent">
- <p>LLDB was recently modified to allow users to define the
- format of the variables display on a per-type basis.</p>
-
- <p>Usually, when you type <code>frame
- variable</code> or run some <code>expression</code>
- LLDB will automatically choose the <i>best</i> way
- to display your results according to its own
- logic:</p> <p> <code> (SimpleWithPointers [3])
- sparray = {<br/> (SimpleWithPointers) [0] = {<br/>
- (int *) x = 0x00000001001000f0<br/> (float *) y =
- 0x0000000100100100<br/> (char *) z =
- 0x0000000100100110 "3"<br/>
- }<br/>
- (SimpleWithPointers) [1] = {<br/> (int *) x =
- 0x0000000100100120<br/> (float *) y =
- 0x0000000100100130<br/> (char *) z =
- 0x0000000100100140 "6"<br/>
- }<br/>
- (SimpleWithPointers) [2] = {<br/> (int *) x =
- 0x0000000100100150<br/> (float *) y =
- 0x0000000100100160<br/> (char *) z =
- 0x0000000100100170 "9"<br/>
- }<br/>
- }<br/>
- </code> </p>
-
- <p>However, there are cases in which your idea of
- <i>best</i> is different from LLDB's. Now there are two
- new commands that enable you to give hints to the debugger
- as to how datatypes should be displayed.</p>
-
- <p>Using them you can obtain a format like this one for
- <code>sparray</code>, instead of the default shown above:
- </p>
-
- <p>
- <code>
- (SimpleWithPointers [3]) sparray = {<br/>
- [0] = (x=0x00000001001000f0 -> -1, y=0x0000000100100100 -> -2, z="3")<br/>
- [1] = (x=0x0000000100100120 -> -4, y=0x0000000100100130 -> -5, z="6")<br/>
- [2] = (x=0x0000000100100150 -> -7, y=0x0000000100100160 -> -8, z="9")<br/>
-}<br/>
-</code>
-</p>
- <p>Variable formatting can be set using the <b>type</b> commands:</p>
- <p><code>type format</code></p>
- <p><code>type summary</code></p>
- <p>Each of these commands has four subcommands:</p>
- <p><code>add</code>: adds a new entry</p>
- <p><code>delete</code>: deletes an existing entry</p>
- <p><code>list</code>: provides a listing of all entries</p>
- <p><code>clear</code>: deletes all entries</p>
-
- </div>
- <div class="postfooter"></div>
- </div>
-
- <div class="post">
- <h1 class ="postheader">type format</h1>
- <div class="postcontent">
-
- <p>Type formats enable you to quickly override the default format for displaying primitive types (the usual basic C/C++/ObjC types: int, float, char, ...).</p>
- <p>LLDB has a list of formatting options available out of which you can pick:</p>
-
- <table border="1">
- <tr valign=top><td width=23%><b>Format name</b></td><td><b>Abbreviation</b></td><td><b>Description</b></td></tr>
- <tr valign=top><td><b>default</b></td><td></td><td>the default LLDB algorithm is used to pick a format</td></tr>
- <tr valign=top><td><b>boolean</b></td><td>B</td><td>show this as a true/false boolean, using the customary rule that 0 is false and everything else is true</td></tr>
- <tr valign=top><td><b>binary</b></td><td>b</td><td>show this as a sequence of bits</td></tr>
- <tr valign=top><td><b>bytes</b></td><td>y</td><td>show the bytes one after the other<br/>e.g. <code>(int) s.x = 07 00 00 00</code></td></tr>
- <tr valign=top><td><b>bytes with ASCII</b></td><td>Y</td><td>show the bytes, but try to print them as ASCII characters<br/>e.g. <code>(int *) c.sp.x = 50 f8 bf 5f ff 7f 00 00 P.._....</code></td></tr>
- <tr valign=top><td><b>character</b></td><td>c</td><td>show the bytes printed as ASCII characters<br/>e.g. <code>(int *) c.sp.x = P\xf8\xbf_\xff\x7f\0\0</code></td></tr>
- <tr valign=top><td><b>printable character</b></td><td>C</td><td>show the bytes printed as printable ASCII characters<br/> e.g. <code>(int *) c.sp.x = P.._....</code></td></tr>
- <tr valign=top><td><b>complex float</b></td><td>F</td><td>interpret this value as the real and imaginary part of a complex floating-point number<br/>e.g. <code>(int *) c.sp.x = 2.76658e+19 + 4.59163e-41i</code></td></tr>
- <tr valign=top><td><b>c-string</b></td><td>s</td><td>show this as a 0-terminated C string</td></tr>
- <tr valign=top><td><b>signed decimal</b></td><td>i</td><td>show this as a signed integer number (this does not perform a cast, it simply shows the bytes as signed integer)</td></tr>
- <tr valign=top><td><b>enumeration</b></td><td>E</td><td>show this as an enumeration, printing the value's name if available or the integer value otherwise<br/>e.g. <code>(enum enumType) val_type = eValue2</code></td></tr>
- <tr valign=top><td><b>hex</b></td><td>x</td><td>show this as in hexadecimal notation (this does not perform a cast, it simply shows the bytes as hex)</td></tr>
- <tr valign=top><td><b>float</b></td><td>f</td><td>show this as a floating-point number (this does not perform a cast, it simply interprets the bytes as an IEEE754 floating-point value)</td></tr>
- <tr valign=top><td><b>octal</b></td><td>o</td><td>show this in octal notation</td></tr>
- <tr valign=top><td><b>OSType</b></td><td>O</td><td>show this as a MacOS OSType<br/>e.g. <code>(float) *c.sp.y = '\n\x1f\xd7\n'</code></td></tr>
- <tr valign=top><td><b>unicode16</b></td><td>U</td><td>show this as UTF-16 characters<br/> e.g. <code>(float) *c.sp.y = 0xd70a 0x411f</code></td></tr>
- <tr valign=top><td><b>unicode32</b></td><td></td><td>show this as UTF-32 characters<br/> e.g. <code>(float) *c.sp.y = 0x411fd70a</code></td></tr>
- <tr valign=top><td><b>unsigned decimal</b></td><td>u</td><td>show this as an unsigned integer number (this does not perform a cast, it simply shows the bytes as unsigned integer)</td></tr>
- <tr valign=top><td><b>pointer</b></td><td>p</td><td>show this as a native pointer (unless this is really a pointer, the resulting address will probably be invalid)</td></tr>
- <tr valign=top><td><b>char[]</b></td><td></td><td>show this as an array of characters<br/>e.g. <code>(char) *c.sp.z = {X}</code></td></tr>
- <tr valign=top><td><b>int8_t[], uint8_t[]<br/>int16_t[], uint16_t[]<br/>int32_t[], uint32_t[]<br/>int64_t[], uint64_t[]<br>uint128_t[]</b></td><td></td><td>show this as an array of the corresponding integer type<br/>e.g.<br/><code>(int) sarray[0].x = {1 0 0 0}</code><br/><code>(int) sarray[0].x = {0x00000001}</code></td></tr>
- <tr valign=top><td><b>float32[], float64[]</b></td><td></td><td>show this as an array of the corresponding floating-point type<br/>e.g. <code>(int *) pointer = {1.46991e-39 1.4013e-45}</code></td></tr>
- <tr valign=top><td><b>complex integer</b></td><td>I</td><td>interpret this value as the real and imaginary part of a complex integer number<br/> e.g. <code>(int *) pointer = 1048960 + 1i</code></td></tr>
- <tr valign=top><td><b>character array</b></td><td>a</td><td>show this as a character array<br/>e.g. <code>(int *) pointer = \x80\x01\x10\0\x01\0\0\0</code></td></tr>
- </table>
-
- <p>Some of the examples shown are willingfully
- unnatural ways to print some values, and meant to
- show that there is no casting or data-loss occurring
- when you change the format of a type. All that lldb
- does when you ask it to change format is reinterpret
- the bytes for display, leaving the original value
- unaltered.</p>
-
- <p>There are two ways to modify the format, one is
- temporary and per-variable, the other is permanent
- and per-type.</p> <p>In the first case you can simply
- use the <code>-f</code> option to <b><code>frame
- variable</code></b>, passing it one of the format
- names or abbreviations in the previous table:</p>
- <p><code>frame variable counter -f hex</code></p>
- <p>This has the effect of displaying the value of
- <code>counter</code> as an hexadecimal number, and
- will keep showing it this way until you either pick a
- different format or a subsequent stoppoint is
- hit.</p> <p>Obviously, if you have two
- <code>int</code> variables, and you format one as
- hex, the other will be left untouched. If for some
- reason, you want all <code>int</code> variables to
- print out as hex, you must add a format to the
- <code>int</code> type.</p> <p>This is done by typing
- <code>type format add -f hex int</code> at the LLDB
- command line.</p> <p>The <code>-f</code> option
- accepts one of the format names or abbreviations, and
- after that you can give out a list of names to which
- you want the new format applied.</p> <p>A frequent
- scenario is that your program has a
- <code>typedef</code> for a numeric type that you know
- represents something that must be printed in a
- certain way. Again, you can add a format just to that
- typedef by using <code>type format add</code> with
- the name alias.</p> <p>But things can quickly get
- hierarchical. Let's say you have a situation like the
- following:</p> <p><code>typedef int A;<br/>typedef A
- B;<br/>typedef B C;<br/>typedef C D;</code></p>
- <p>and you want to show all <code>A</code>s as hex,
- all <code>C</code>s as pointers and leave the
- defaults 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/> values
- of type <code>B</code> will be shown as hex and
- values of type <code>D</code> as pointers.</p>
- <p>This is because by default LLDB <i>cascades</i>
- formats through typedef chains. In order to avoid
- that 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> <p>Two additional options
- that you will want to look at are <code>-p</code> and
- <code>-r</code>. These two options prevent LLDB from
- applying a format for type <code>T</code> to values
- of type <code>T*</code> and <code>T&</code>
- respectively.</p>
- <p>
- <code>
- <b>(lldb)</b> type format add -f float32[] int<br/>
- <b>(lldb)</b> fr var pointer *pointer -T<br/>
- (int *) pointer = {1.46991e-39 1.4013e-45}<br/>
- (int) *pointer = {1.53302e-42}<br/>
- <b>(lldb)</b> type format add -f float32[] int -p<br/>
- <b>(lldb)</b> fr var pointer *pointer -T<br/>
- (int *) pointer = 0x0000000100100180<br/>
- (int) *pointer = {1.53302e-42}<br/>
- </code>
- </p>
- <p>As the previous example highlights, you will most
- probably want to use <code>-p</code> for your
- formats.</p> <p>If you need to delete a custom format
- simply type <code>type format delete</code> followed
- by the name of the type to which the format applies.
- To delete ALL formats, use <code>type format
- clear</code>. To see all the formats defined, type
- <code>type format list</code>.</p>
-
- </div> <div class="postfooter"></div> </div>
-
- <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>
- <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/>
- }<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 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>
-
- </div>
- <div class="postfooter"></div>
- </div>
-
- <div class="post">
- <h1 class ="postheader">Summary Strings</h1>
- <div class="postcontent">
-
- <p>So what is the format of the summary strings?
- Summary strings can contain plain text, control
- characters and special symbols that have access to
- information about the current object and the overall
- program state.</p>
-
- <p>Normal characters are any text that doesn't
- contain a <code><b>'{'</b></code>,
- <code><b>'}'</b></code>, <code><b>'$'</b></code>, or
- <code><b>'\'</b></code> character.</p>
-
- <p>Variable names are found in between a
- <code><b>"${"</b></code> prefix, and end with a
- <code><b>"}"</b></code> suffix. In other words, a
- variable looks like
- <code>"<b>${frame.pc}</b>"</code>.</p>
-
- <p>Basically, all the variables described in <a
- href="formats.html">Frame and Thread Formatting</a>
- are accepted. Also acceptable are the control
- characters and scoping features described in that
- page. Additionally, <code>${var</code> and
- <code>${*var</code> become acceptable symbols in this
- scenario.</p> <p>The simplest thing you can do is
- grab a member variable of a class or structure by
- typing its <i>expression path</i>. In the previous
- example, the expression path for the floating member
- is simply <code>.floating</code>, because all you
- have to do to get at it given an object of type
- <code>i_am_cool</code> is access it straight away.
- Thus, to ask the summary string to display
- <code>floating</code> you would type
- <code>${var.floating}</code> (<code>${var</code> is a
- placeholder token replaced with whatever variable is
- being displayed).</p> <p>If you have code like the
- following: <br/> <code> struct A {<br/> int x;<br/>
- int y;<br/>
- };<br/>
- struct B {<br/> A x;<br/> A y;<br/> int z;<br/>
- };<br/>
- </code> the expression path for the <code>y</code>
- member of the <code>x</code> member of an object of
- type <code>B</code> would be <code>.x.y</code> and
- you would type <code>${var.x.y}</code> to display it
- in a summary string for type <code>B</code>. </p>
- <p>As you could be using a summary string for both
- displaying objects of type <code>T</code> or
- <code>T*</code> (unless <code>-p</code> is used to
- prevent this), the expression paths do not
- differentiate between <code>.</code> and
- <code>-></code>, and the above expression path
- <code>.x.y</code> would be just as good if you were
- displaying a <code>B*</code>, or even if the actual
- definition of <code>B</code> were:
- <code><br/>
- struct B {<br/>
- A *x;<br/>
- A y;<br/>
- int z;<br/>
- };<br/>
- </code>
- </p>
- <p>This is unlike the behaviour of <code>frame
- variable</code> which, on the contrary, will enforce
- the distinction. As hinted above, the rationale for
- this choice is that waiving this distinction enables
- one to write a summary string once for type
- <code>T</code> and use it for both <code>T</code> and
- <code>T*</code> instances. As a summary string is
- mostly about extracting nested members' information,
- a pointer to an object is just as good as the object
- itself for the purpose.</p>
-
- <p>Of course, you can have multiple entries in one
- summary string. For instance, the command used to
- produce the above summary string for i_am_cool was:
- <br/><code>type summary add -f "int = ${var.integer},
- float = ${var.floating}, char = ${var.character%u}"
- i_am_cool </code> </p> <p>As you can see, the last
- expression path also contains a <code>%u</code>
- symbol which is nowhere to be found in the actual
- member variable name. The symbol is reminding of a
- <code>printf()</code> format symbol, and in fact it
- has a similar effect. If you add a % sign followed by
- any one format name or abbreviation from the above
- table after an expression path, the resulting object
- will be displyed using exactly that format instead of
- the LLDB default one.
- </p>
- <p>There are two more special format symbols that you
- can use only as part of a summary string:
- <code>%V</code> and <code>%@</code>. The first one
- tells LLDB to ignore summary strings for the type of
- the object referred by the expression path and
- instead print the object's value. The second is only
- applicable to Objective-C classes, and tells LLDB to
- get the object's description from the Objective-C
- runtime. By default, if no format is provided, LLDB
- will try to get the object's summary, and if empty
- the object's value. If neither can be obtained,
- nothing will be displayed.</p>
- <p>As previously said, pointers and values are
- treated the same way when getting to their members in
- an expression path. However, if your expression path
- leads to a pointer, LLDB will not automatically
- dereference it. In order to obtain The deferenced
- value for a pointer, your expression path must start
- with <code>${*var</code> instead of
- <code>${var</code>. Because there is no need to
- dereference pointers along your way, the
- dereferencing symbol only applies to the result of
- the whole expression path traversing.
- <br/>
- e.g.
- <code>
- <br/>
- <b>(lldb)</b> fr var -T c<br/>
-(Couple) c = {<br/>
- (SimpleWithPointers) sp = {<br/>
- (int *) x = 0x00000001001000b0<br/>
- (float *) y = 0x00000001001000c0<br/>
- (char *) z = 0x00000001001000d0 "X"<br/>
- }<br/>
- (Simple *) s = 0x00000001001000e0<br/>
-}<br/>
-<b>(lldb)</b> type summary add -f "int = ${*var.sp.x}, float = ${*var.sp.y}, char = ${*var.sp.z%u}, Simple = ${*var.s}" Couple<br/>
-<b>(lldb)</b> type summary add -c -p Simple<br/>
-<b>(lldb)</b> fr var c<br/>
-(Couple) c = int = 9, float = 9.99, char = 88, Simple = (x=9, y=9.99, z='X')<br/>
- </code>
- </p>
- <p>Option <code>-c</code> to <code>type summary
- add</code> tells LLDB not to look for a summary
- string, but instead to just print a listing of all
- the object's children on one line, lay out as in the
- previous example. The <code>-p</code> flag is used as
- a trick to show that aggregate types can be
- dereferenced as well as primitive ones. The above
- output would be shown even by typing <code>type
- summary add -f "int = ${*var.sp.x}, float =
- ${*var.sp.y}, char = ${*var.sp.z%u}, Simple =
- ${var.s}" Couple</code> if one took away the
- <code>-p</code> flag from the summary for type
- <code>Simple</code>. </p>
-
- </div>
- <div class="postfooter"></div>
- </div>
-
- <div class="post">
- <h1 class ="postheader">More on summary strings</h1>
- <div class="postcontent">
-
- <p>What was described above are the main features
- that you can use in summary strings. However, there
- are three more features to them.</p> <p>Sometimes, a
- basic type's value actually represents several
- different values packed together in a bitfield. With
- the classical view, there is no way to look at them.
- Hexadecimal display can help, but if the bits
- actually span byte boundaries, the help is limited.
- Binary view would show it all without ambiguity, but
- is often too detailed and hard to read for real-life
- scenarios. To cope with the issue, LLDB supports
- native bitfield formatting in summary strings. If
- your expression paths leads to a so-called <i>scalar
- type</i> (the usual int, float, char, double, short,
- long, long long, double, long double and unsigned
- variants), you can ask LLDB to only grab some bits
- out of the value and display them in any format you
- like. The syntax is similar to that used for arrays,
- just you can also give a pair of indices separated by
- a <code>-</code>. <br/>
- e.g.
- <br/>
- <code>
- <b>(lldb)</b> fr var float_point<br/>
-(float) float_point = -3.14159<br/>
-<b>(lldb)</b> type summary add -f "Sign: ${var[31]%B} Exponent: ${var[30-23]%x} Mantissa: ${var[0-22]%u}" float<br/>
-<b>(lldb)</b> fr var float_point<br/>
-(float) float_point = -3.14159 Sign: true Exponent: 0x00000080 Mantissa: 4788184<br/>
- </code>
- In this example, LLDB shows the internal
- representation of a <code>float</code> variable by
- extracting bitfields out of a float object. If you
- give a single index, only that one bit will be
- extracted. If you give a pair of indices, all the
- bits in the range (extremes included) will be
- extracted. Ranges can be specified either by giving
- the lower index first, or higher index first (as is
- often customary in describing packed data-type
- formats). </p>
- <p>The second additional feature allows you to
- display array members inside a summary string. For
- instance, you may want to display all arrays of a
- given type using a more compact notation than the
- default, and then just delve into individual array
- members that prove interesting to your debugging
- task. You can use a similar syntax to the one used
- for bitfields to tell LLDB to format arrays in
- special ways.
- <br/>
- e.g.
- <br/>
- <code>
- <b>(lldb)</b> fr var sarray<br/>
-(Simple [3]) sarray = {<br/>
- [0] = {<br/>
- x = 1<br/>
- y = 2<br/>
- z = '\x03'<br/>
- }<br/>
- [1] = {<br/>
- x = 4<br/>
- y = 5<br/>
- z = '\x06'<br/>
- }<br/>
- [2] = {<br/>
- x = 7<br/>
- y = 8<br/>
- z = '\t'<br/>
- }<br/>
-}<br/>
-<b>(lldb)</b> type summary add -f "${var[].x}" "Simple [3]"<br/>
-<b>(lldb)</b> fr var sarray<br/>
-(Simple [3]) sarray = [1,4,7]<br/>
- </code>
- The <code>[]</code> symbol amounts to: <i>if
- <code>var</code> is an array and I knows its size,
- apply this summary string to every element of the
- array</i>. Here, we are asking LLDB to display
- <code>.x</code> for every element of the array, and
- in fact this is what happens. If you find some of
- those integers anomalous, you can then inspect that
- one item in greater detail, without the array format
- getting in the way:
- <br/>
- <code>
- <b>(lldb)</b> fr var sarray[1]<br/>
-(Simple) sarray[1] = {<br/>
- x = 4<br/>
- y = 5<br/>
- z = '\x06'<br/>
-}<br/>
- </code>
- </p>
- <p>You can also ask LLDB to only print a subset of
- the array range by using the same syntax used to
- extract bit for bitfields.</p> <p>The same logic
- works if you are printing a pointer instead of an
- array, however in this latter case, <code>[]</code>
- cannot be used and you need to give exact range
- limits.</p> <p>The third, and last, additional
- feature does not directly apply to the summary
- strings themselves, but is an additional option to
- the <code>type summary add</code> command:
- <code>-x</code></p> <p>As you noticed, in order to
- associate the custom summary string to the array
- types, one must give the array size as part of the
- typename. This can long become tiresome when using
- arrays of different sizes, <code>Simple [3]</code>,
- <code>Simple [9]</code>, <code>Simple [12]</code>,
- ...</p> <p>If you use the <code>-x</code> option,
- type names are treated as regular expressions instead
- of type names. This would let you rephrase the above
- example as:
- <br/>
- <code>
-<b>(lldb)</b> type summary add -f "${var[].x}" -x "Simple \[[0-9]+\]"<br/>
-<b>(lldb)</b> fr var sarray<br/>
-(Simple [3]) sarray = [1,4,7]<br/>
- </code>
- The above scenario works for <code>Simple [3]</code>
- as well as for any other array of
- <code>Simple</code> objects. </p> <p>While this
- feature is mostly useful for arrays, you could also
- use regular expressions to catch other type sets
- grouped by name. However, as regular expression
- matching is slower than normal name matching, LLDB
- will first try to match by name in any way it can,
- and only when this fails, will it resort to regular
- expression matching. Thus, if your type has a base
- class with a cascading summary, this will be
- preferred over any regular expression match for your
- type itself.</p>
-
- </div> <div class="postfooter"></div> </div>
-
- <div class="post"> <h1 class ="postheader">Finding
- summaries 101</h1> <div class="postcontent">
-
- <p>While the rules for finding an appropriate
- format for a type are relatively simple (just go
- through typedef hierarchies), summaries follow a
- more complicated process in finding the right
- summary string for a variable. Namely, what
- happens is:</p> <ul> <li>If there is a summary for
- the type of the variable, use it</li> <li>If this
- object is a pointer, and there is a summary for
- the pointee type that does not skip pointers, use
- it</li> <li>If this object is a reference, and
- there is a summary for the pointee type that does
- not skip references, use it</li> <li>If this
- object is an Objective-C class with a parent
- class, look at the parent class (and parent of
- parent, ...)</li> <li>If this object is a C++
- class with base classes, look at base classes (and
- bases of bases, ...)</li> <li>If this object is a
- C++ class with virtual base 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> <li>If
- everything has failed, repeat the above search,
- looking for regular expressions instead of exact
- matches</li> </ul> </div> <div
- class="postfooter"></div> </div>
-
- <div class="post"> <h1 class ="postheader">TODOs</h1>
- <div class="postcontent">
-
- <ul> <li>There's no way to do multiple dereferencing,
- and you need to be careful what the dereferencing
- operation is binding to in complicated scenarios</li>
- <li>There is no way to call functions inside summary
- strings, not even <code>const</code> ones</li>
- <li><code>type format add</code> does not support the
- <code>-x</code> option</li> <li>Object location cannot
- be printed in the summary string</li> </ul>
- </div>
- <div class="postfooter"></div>
- </div>
-
- </div>
- </div>
-</div>
-</body>
-</html>
\ No newline at end of file +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <meta http-equiv="Content-Type" content="text/html; + charset=ISO-8859-1"> + <link href="style.css" rel="stylesheet" type="text/css"> + <title>LLDB Homepage</title> + </head> + <body> + <div class="www_title"> The <strong>LLDB</strong> Debugger </div> + <div id="container"> + <div id="content"> + <!--#include virtual="sidebar.incl"--> + <div id="middle"> + <div class="post"> + <h1 class="postheader">Variable display</h1> + <div class="postcontent"> + + <p>LLDB was recently modified to allow users to define custom + formatting options for the variables display.</p> + + <p>Usually, when you type <code>frame variable</code> or + run some <code>expression</code> LLDB will + automatically choose a format to display your results on + a per-type basis, as in the following example:</p> + + <p> <code> <b>(lldb)</b> frame variable -T sp<br> + (SimpleWithPointers) sp = {<br> + (int *) x = 0x0000000100100120<br> + (float *) y = + 0x0000000100100130<br> + (char *) z = + 0x0000000100100140 "6"<br> + }<br> + </code> </p> + + <p>However, in certain cases, you may want to associate a + different format to the display for certain datatypes. + To do so, you need to give hints to the debugger as to + how datatypes should be displayed.<br> + A new <b>type</b> command has been introduced in LLDB + which allows to do just that.<br> + </p> + + <p>Using it you can obtain a format like this one for <code>sp</code>, + instead of the default shown above: </p> + + <p> <code> <b>(lldb)</b> frame variable sp<br> + (SimpleWithPointers) sp = + (x=0x0000000100100120 -> -1, y=0x0000000100100130 + -> -2, z="3")<br> + </code> </p> + + <p>There are two kinds of printing options: <span + style="font-style: italic;">summary</span> and <span + style="font-style: italic;">format</span>. While a + detailed description of both will be given below, one + can briefly say that a summary is mainly used for + aggregate types, while a format is attached to primitive + types.</p> + + <p>To reflect this, the the <b>type</b> command has two + subcommands:<br> + </p> + + <p><code>type format</code></p> + <p><code>type summary</code></p> + + <p>These commands are meant to bind printing options to + types. When variables are printed, LLDB will first check + if custom printing options have been associated to a + variable's type and, if so, use them instead of picking + the default choices.<br> + </p> + + <p>The two commands <code>type format</code> and <code>type + summary</code> each have four subcommands:<br> + </p> + <p><code>add</code>: associates a new printing option to one + or more types</p> + <p><code>delete</code>: deletes an existing association</p> + <p><code>list</code>: provides a listing of all + associations</p> + <p><code>clear</code>: deletes all associations</p> + </div> + </div> + + <div class="post"> + <h1 class="postheader">type format</h1> + <div class="postcontent"> + + <p>Type formats enable you to quickly override the default + format for displaying primitive types (the usual basic + C/C++/ObjC types: int, float, char, ...).</p> + + <p>If for some reason you want all <code>int</code> + 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>The <code>-f</code> option accepts a <a + href="#formatstable">format name</a>, and a list of + types to which you want the new format applied.</p> + + <p>A frequent scenario is that your program has a <code>typedef</code> + for a numeric type that you know represents something + that must be printed in a certain way. Again, you can + add a format just to that typedef by using <code>type + format add</code> with the name alias.</p> + + <p>But things can quickly get hierarchical. Let's say you + have a situation like the following:</p> + + <p><code>typedef int A;<br> + typedef A B;<br> + typedef B C;<br> + typedef C D;<br> + </code></p> + + <p>and you want to show all <code>A</code>'s as hex, all + <code>C'</code>s as pointers and leave the defaults + 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> + <br> + values of type <code>B</code> will be shown as hex + and values of type <code>D</code> as pointers.</p> + + <p>This is because by default LLDB <i>cascades</i> + formats through typedef chains. In order to avoid that + 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> + + <p>Two additional options that you will want to look at + are <code>-p</code> and <code>-r</code>. These two + options prevent LLDB from applying a format for type <code>T</code> + to values of type <code>T*</code> and <code>T&</code> + respectively.</p> + + <p> <code> <b>(lldb)</b> type format add -f float32[] + int<br> + <b>(lldb)</b> fr var pointer *pointer -T<br> + (int *) pointer = {1.46991e-39 1.4013e-45}<br> + (int) *pointer = {1.53302e-42}<br> + <b>(lldb)</b> type format add -f float32[] int -p<br> + <b>(lldb)</b> fr var pointer *pointer -T<br> + (int *) pointer = 0x0000000100100180<br> + (int) *pointer = {1.53302e-42}<br> + </code> </p> + + <p>As the previous example highlights, you will most + probably want to use <code>-p</code> for your formats.</p> + + <p>If you need to delete a custom format simply type <code>type + format delete</code> followed by the name of the type + to which the format applies. To delete ALL formats, use + <code>type format clear</code>. To see all the formats + defined, type <code>type format list</code>.<br> + </p> + + <p>If all you need to do, however, is display one variable + 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> + + <p>This has the effect of displaying the value of <code>counter</code> + as an hexadecimal number, and will keep showing it this + way until you either pick a different format or till you + let your program run again.</p> + + <p>Finally, this is a list of formatting options available + out of + which you can pick:</p><a name="formatstable"></a> + <table border="1"> + <tbody> + <tr valign="top"> + <td width="23%"><b>Format name</b></td> + <td><b>Abbreviation</b></td> + <td><b>Description</b></td> + </tr> + <tr valign="top"> + <td><b>default</b></td> + <td><br> + </td> + <td>the default LLDB algorithm is used to pick a + format</td> + </tr> + <tr valign="top"> + <td><b>boolean</b></td> + <td>B</td> + <td>show this as a true/false boolean, using the + customary rule that 0 is false and everything else + is true</td> + </tr> + <tr valign="top"> + <td><b>binary</b></td> + <td>b</td> + <td>show this as a sequence of bits</td> + </tr> + <tr valign="top"> + <td><b>bytes</b></td> + <td>y</td> + <td>show the bytes one after the other<br> + e.g. <code>(int) s.x = 07 00 00 00</code></td> + </tr> + <tr valign="top"> + <td><b>bytes with ASCII</b></td> + <td>Y</td> + <td>show the bytes, but try to print them as ASCII + characters<br> + e.g. <code>(int *) c.sp.x = 50 f8 bf 5f ff 7f 00 + 00 P.._....</code></td> + </tr> + <tr valign="top"> + <td><b>character</b></td> + <td>c</td> + <td>show the bytes printed as ASCII characters<br> + e.g. <code>(int *) c.sp.x = + P\xf8\xbf_\xff\x7f\0\0</code></td> + </tr> + <tr valign="top"> + <td><b>printable character</b></td> + <td>C</td> + <td>show the bytes printed as printable ASCII + characters<br> + e.g. <code>(int *) c.sp.x = P.._....</code></td> + </tr> + <tr valign="top"> + <td><b>complex float</b></td> + <td>F</td> + <td>interpret this value as the real and imaginary + part of a complex floating-point number<br> + e.g. <code>(int *) c.sp.x = 2.76658e+19 + + 4.59163e-41i</code></td> + </tr> + <tr valign="top"> + <td><b>c-string</b></td> + <td>s</td> + <td>show this as a 0-terminated C string</td> + </tr> + <tr valign="top"> + <td><b>signed decimal</b></td> + <td>i</td> + <td>show this as a signed integer number (this does + not perform a cast, it simply shows the bytes as + signed integer)</td> + </tr> + <tr valign="top"> + <td><b>enumeration</b></td> + <td>E</td> + <td>show this as an enumeration, printing the + value's name if available or the integer value + otherwise<br> + e.g. <code>(enum enumType) val_type = eValue2</code></td> + </tr> + <tr valign="top"> + <td><b>hex</b></td> + <td>x</td> + <td>show this as in hexadecimal notation (this does + not perform a cast, it simply shows the bytes as + hex)</td> + </tr> + <tr valign="top"> + <td><b>float</b></td> + <td>f</td> + <td>show this as a floating-point number (this does + not perform a cast, it simply interprets the bytes + as an IEEE754 floating-point value)</td> + </tr> + <tr valign="top"> + <td><b>octal</b></td> + <td>o</td> + <td>show this in octal notation</td> + </tr> + <tr valign="top"> + <td><b>OSType</b></td> + <td>O</td> + <td>show this as a MacOS OSType<br> + e.g. <code>(float) *c.sp.y = '\n\x1f\xd7\n'</code></td> + </tr> + <tr valign="top"> + <td><b>unicode16</b></td> + <td>U</td> + <td>show this as UTF-16 characters<br> + e.g. <code>(float) *c.sp.y = 0xd70a 0x411f</code></td> + </tr> + <tr valign="top"> + <td><b>unicode32</b></td> + <td><br> + </td> + <td>show this as UTF-32 characters<br> + e.g. <code>(float) *c.sp.y = 0x411fd70a</code></td> + </tr> + <tr valign="top"> + <td><b>unsigned decimal</b></td> + <td>u</td> + <td>show this as an unsigned integer number (this + does not perform a cast, it simply shows the bytes + as unsigned integer)</td> + </tr> + <tr valign="top"> + <td><b>pointer</b></td> + <td>p</td> + <td>show this as a native pointer (unless this is + really a pointer, the resulting address will + probably be invalid)</td> + </tr> + <tr valign="top"> + <td><b>char[]</b></td> + <td><br> + </td> + <td>show this as an array of characters<br> + e.g. <code>(char) *c.sp.z = {X}</code></td> + </tr> + <tr valign="top"> + <td><b>int8_t[], uint8_t[]<br> + int16_t[], uint16_t[]<br> + int32_t[], uint32_t[]<br> + int64_t[], uint64_t[]<br> + uint128_t[]</b></td> + <td><br> + </td> + <td>show this as an array of the corresponding + integer type<br> + e.g.<br> + <code>(int) sarray[0].x = {1 0 0 0}</code><br> + <code>(int) sarray[0].x = {0x00000001}</code></td> + </tr> + <tr valign="top"> + <td><b>float32[], float64[]</b></td> + <td><br> + </td> + <td>show this as an array of the corresponding + floating-point type<br> + e.g. <code>(int *) pointer = {1.46991e-39 + 1.4013e-45}</code></td> + </tr> + <tr valign="top"> + <td><b>complex integer</b></td> + <td>I</td> + <td>interpret this value as the real and imaginary + part of a complex integer number<br> + e.g. <code>(int *) pointer = 1048960 + 1i</code></td> + </tr> + <tr valign="top"> + <td><b>character array</b></td> + <td>a</td> + <td>show this as a character array<br> + e.g. <code>(int *) pointer = + \x80\x01\x10\0\x01\0\0\0</code></td> + </tr> + </tbody> + </table> + </div> + </div> + + <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> <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> + }<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 + 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> + </div> + </div> + <div class="post"> + <h1 class="postheader">Summary Strings</h1> + <div class="postcontent"> + <p>So what is the format of the summary strings? Summary + strings can contain plain text, control characters and + special symbols that have access to information about + the current object and the overall program state.</p> + <p>Normal characters are any text that doesn't contain a <code><b>'{'</b></code>, + <code><b>'}'</b></code>, <code><b>'$'</b></code>, or <code><b>'\'</b></code> + character.</p> + <p>Variable names are found in between a <code><b>"${"</b></code> + prefix, and end with a <code><b>"}"</b></code> suffix. + In other words, a variable looks like <code>"<b>${frame.pc}</b>"</code>.</p> + <p>Basically, all the variables described in <a + href="formats.html">Frame and Thread Formatting</a> + are accepted. Also acceptable are the control characters + and scoping features described in that page. + Additionally, <code>${var</code> and <code>${*var</code> + become acceptable symbols in this scenario.</p> + <p>The simplest thing you can do is grab a member variable + of a class or structure by typing its <i>expression + path</i>. In the previous example, the expression path + for the floating member is simply <code>.floating</code>, + because all you have to do to get at it given an object + of type <code>i_am_cool</code> is access it straight + away. Thus, to ask the summary string to display <code>floating</code> + you would type <code>${var.floating}</code> (<code>${var</code> + is a placeholder token replaced with whatever variable + is being displayed).</p> + <p>If you have code like the following: <br> + <code> struct A {<br> + int x;<br> + int y;<br> + };<br> + struct B {<br> + A x;<br> + A y;<br> + int z;<br> + };<br> + </code> the expression path for the <code>y</code> + member of the <code>x</code> member of an object of + type <code>B</code> would be <code>.x.y</code> and you + would type <code>${var.x.y}</code> to display it in a + summary string for type <code>B</code>. </p> + <p>As you could be using a summary string for both + displaying objects of type <code>T</code> or <code>T*</code> + (unless <code>-p</code> is used to prevent this), the + expression paths do not differentiate between <code>.</code> + and <code>-></code>, and the above expression path <code>.x.y</code> + would be just as good if you were displaying a <code>B*</code>, + or even if the actual definition of <code>B</code> + were: <code><br> + struct B {<br> + A *x;<br> + A y;<br> + int z;<br> + };<br> + </code> </p> + <p>This is unlike the behaviour of <code>frame variable</code> + which, on the contrary, will enforce the distinction. As + hinted above, the rationale for this choice is that + waiving this distinction enables one to write a summary + string once for type <code>T</code> and use it for both + <code>T</code> and <code>T*</code> instances. As a + summary string is mostly about extracting nested + members' information, a pointer to an object is just as + good as the object itself for the purpose.</p> + <p>Of course, you can have multiple entries in one summary + string. For instance, the command used to produce the + above summary string for i_am_cool was: <br> + <code>type summary add -f "int = ${var.integer}, float = + ${var.floating}, char = ${var.character%u}" i_am_cool + </code> </p> + <p>As you can see, the last expression path also contains + a <code>%u</code> symbol which is nowhere to be found + in the actual member variable name. The symbol is + reminding of a <code>printf()</code> format symbol, and + in fact it has a similar effect. If you add a % sign + followed by any one format name or abbreviation from the + above table after an expression path, the resulting + object will be displyed using exactly that format + instead of the LLDB default one. </p> + <p>There are two more special format symbols that you can + use only as part of a summary string: <code>%V</code> + and <code>%@</code>. The first one tells LLDB to ignore + summary strings for the type of the object referred by + the expression path and instead print the object's + value. The second is only applicable to Objective-C + classes, and tells LLDB to get the object's description + from the Objective-C runtime. By default, if no format + is provided, LLDB will try to get the object's summary, + and if empty the object's value. If neither can be + obtained, nothing will be displayed.</p> + <p>As previously said, pointers and values are treated the + same way when getting to their members in an expression + path. However, if your expression path leads to a + pointer, LLDB will not automatically dereference it. In + order to obtain The deferenced value for a pointer, your + expression path must start with <code>${*var</code> + instead of <code>${var</code>. Because there is no need + to dereference pointers along your way, the + dereferencing symbol only applies to the result of the + whole expression path traversing. <br> + e.g. <code> <br> + <b>(lldb)</b> fr var -T c<br> + (Couple) c = {<br> + (SimpleWithPointers) sp = {<br> + (int *) x = 0x00000001001000b0<br> + (float *) y = 0x00000001001000c0<br> + (char *) z = 0x00000001001000d0 "X"<br> + }<br> + (Simple *) s = 0x00000001001000e0<br> + }<br> + <b>(lldb)</b> type summary add -f "int = ${*var.sp.x}, + float = ${*var.sp.y}, char = ${*var.sp.z%u}, Simple = + ${*var.s}" Couple<br> + <b>(lldb)</b> type summary add -c -p Simple<br> + <b>(lldb)</b> fr var c<br> + (Couple) c = int = 9, float = 9.99, char = 88, Simple + = (x=9, y=9.99, z='X')<br> + </code> </p> + <p>Option <code>-c</code> to <code>type summary add</code> + tells LLDB not to look for a summary string, but instead + to just print a listing of all the object's children on + one line, lay out as in the previous example. The <code>-p</code> + flag is used as a trick to show that aggregate types can + be dereferenced as well as primitive ones. The above + output would be shown even by typing <code>type summary + add -f "int = ${*var.sp.x}, float = ${*var.sp.y}, char + = ${*var.sp.z%u}, Simple = ${var.s}" Couple</code> if + one took away the <code>-p</code> flag from the summary + for type <code>Simple</code>. </p> + </div> + </div> + <div class="post"> + <h1 class="postheader">More on summary strings</h1> + <div class="postcontent"> + <p>What was described above are the main features that you + can use in summary strings. However, there are three + more features to them.</p> + <p>Sometimes, a basic type's value actually represents + several different values packed together in a bitfield. + With the classical view, there is no way to look at + them. Hexadecimal display can help, but if the bits + actually span byte boundaries, the help is limited. + Binary view would show it all without ambiguity, but is + often too detailed and hard to read for real-life + scenarios. To cope with the issue, LLDB supports native + bitfield formatting in summary strings. If your + expression paths leads to a so-called <i>scalar type</i> + (the usual int, float, char, double, short, long, long + long, double, long double and unsigned variants), you + can ask LLDB to only grab some bits out of the value and + display them in any format you like. The syntax is + similar to that used for arrays, just you can also give + a pair of indices separated by a <code>-</code>. <br> + e.g. <br> + <code> <b>(lldb)</b> fr var float_point<br> + (float) float_point = -3.14159<br> + <b>(lldb)</b> type summary add -f "Sign: ${var[31]%B} + Exponent: ${var[30-23]%x} Mantissa: ${var[0-22]%u}" + float<br> + <b>(lldb)</b> fr var float_point<br> + (float) float_point = -3.14159 Sign: true Exponent: + 0x00000080 Mantissa: 4788184<br> + </code> In this example, LLDB shows the internal + representation of a <code>float</code> variable by + extracting bitfields out of a float object. If you give + a single index, only that one bit will be extracted. If + you give a pair of indices, all the bits in the range + (extremes included) will be extracted. Ranges can be + specified either by giving the lower index first, or + higher index first (as is often customary in describing + packed data-type formats). </p> + <p>The second additional feature allows you to display + array members inside a summary string. For instance, you + may want to display all arrays of a given type using a + more compact notation than the default, and then just + delve into individual array members that prove + interesting to your debugging task. You can use a + similar syntax to the one used for bitfields to tell + LLDB to format arrays in special ways. <br> + e.g. <br> + <code> <b>(lldb)</b> fr var sarray<br> + (Simple [3]) sarray = {<br> + [0] = {<br> + x = 1<br> + y = 2<br> + z = '\x03'<br> + }<br> + [1] = {<br> + x = 4<br> + y = 5<br> + z = '\x06'<br> + }<br> + [2] = {<br> + x = 7<br> + y = 8<br> + z = '\t'<br> + }<br> + }<br> + <b>(lldb)</b> type summary add -f "${var[].x}" "Simple + [3]"<br> + <b>(lldb)</b> fr var sarray<br> + (Simple [3]) sarray = [1,4,7]<br> + </code> The <code>[]</code> symbol amounts to: <i>if <code>var</code> + is an array and I knows its size, apply this summary + string to every element of the array</i>. Here, we are + asking LLDB to display <code>.x</code> for every + element of the array, and in fact this is what happens. + If you find some of those integers anomalous, you can + then inspect that one item in greater detail, without + the array format getting in the way: <br> + <code> <b>(lldb)</b> fr var sarray[1]<br> + (Simple) sarray[1] = {<br> + x = 4<br> + y = 5<br> + z = '\x06'<br> + }<br> + </code> </p> + <p>You can also ask LLDB to only print a subset of the + array range by using the same syntax used to extract bit + for bitfields.</p> + <p>The same logic works if you are printing a pointer + instead of an array, however in this latter case, <code>[]</code> + cannot be used and you need to give exact range limits.</p> + <p>The third, and last, additional feature does not + directly apply to the summary strings themselves, but is + an additional option to the <code>type summary add</code> + command: <code>-x</code></p> + <p>As you noticed, in order to associate the custom + summary string to the array types, one must give the + array size as part of the typename. This can long become + tiresome when using arrays of different sizes, <code>Simple + + [3]</code>, <code>Simple [9]</code>, <code>Simple + [12]</code>, ...</p> + <p>If you use the <code>-x</code> option, type names are + treated as regular expressions instead of type names. + This would let you rephrase the above example as: <br> + <code> <b>(lldb)</b> type summary add -f "${var[].x}" + -x "Simple \[[0-9]+\]"<br> + <b>(lldb)</b> fr var sarray<br> + (Simple [3]) sarray = [1,4,7]<br> + </code> The above scenario works for <code>Simple [3]</code> + as well as for any other array of <code>Simple</code> + objects. </p> + <p>While this feature is mostly useful for arrays, you + could also use regular expressions to catch other type + sets grouped by name. However, as regular expression + matching is slower than normal name matching, LLDB will + first try to match by name in any way it can, and only + when this fails, will it resort to regular expression + matching. Thus, if your type has a base class with a + cascading summary, this will be preferred over any + regular expression match for your type itself.</p> + </div> + </div> + <div class="post"> + <h1 class="postheader">Finding summaries 101</h1> + <div class="postcontent"> + <p>While the rules for finding an appropriate format for a + type are relatively simple (just go through typedef + hierarchies), summaries follow a more complicated + process in finding the right summary string for a + variable. Namely, what happens is:</p> + <ul> + <li>If there is a summary for the type of the variable, + use it</li> + <li>If this object is a pointer, and there is a summary + for the pointee type that does not skip pointers, use + it</li> + <li>If this object is a reference, and there is a + summary for the pointee type that does not skip + references, use it</li> + <li>If this object is an Objective-C class with a parent + class, look at the parent class (and parent of parent, + ...)</li> + <li>If this object is a C++ class with base classes, + look at base classes (and bases of bases, ...)</li> + <li>If this object is a C++ class with virtual base + 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> + <li>If everything has failed, repeat the above search, + looking for regular expressions instead of exact + matches</li> + </ul> + </div> + </div> + <div class="post"> + <h1 class="postheader">TODOs</h1> + <div class="postcontent"> + <ul> + <li>There's no way to do multiple dereferencing, and you + need to be careful what the dereferencing operation is + binding to in complicated scenarios</li> + <li>There is no way to call functions inside summary + strings, not even <code>const</code> ones</li> + <li><code>type format add</code> does not support the <code>-x</code> + option</li> + <li>Object location cannot be printed in the summary + string</li> + </ul> + </div> + </div> + </div> + </div> + </div> + </body> +</html> |