diff options
author | Enrico Granata <granata.enrico@gmail.com> | 2011-07-08 02:51:01 +0000 |
---|---|---|
committer | Enrico Granata <granata.enrico@gmail.com> | 2011-07-08 02:51:01 +0000 |
commit | fc7a7f3b75f988b628672a4cb50cbdc8be9405bf (patch) | |
tree | 3a462016bcc43bb52b2c512849aaa9599a1d2ccb /lldb/source | |
parent | 4d1ca96bfc439cc6d97242c81803f69b39a65e10 (diff) | |
download | bcm5719-llvm-fc7a7f3b75f988b628672a4cb50cbdc8be9405bf.tar.gz bcm5719-llvm-fc7a7f3b75f988b628672a4cb50cbdc8be9405bf.zip |
final fix for the global constructors issue
new GetValueForExpressionPath() method in ValueObject to navigate expression paths in a more bitfield vs slices aware way
changes to the varformats.html document (WIP)
llvm-svn: 134679
Diffstat (limited to 'lldb/source')
-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 |
3 files changed, 507 insertions, 95 deletions
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, |