diff options
author | Enrico Granata <granata.enrico@gmail.com> | 2011-07-06 02:13:41 +0000 |
---|---|---|
committer | Enrico Granata <granata.enrico@gmail.com> | 2011-07-06 02:13:41 +0000 |
commit | 9762e10787a7efc2f0d822590cab42ca23d5e4f9 (patch) | |
tree | 3ea76021b69cbb667cfd35d3be1706d9d38e177e /source | |
parent | 2ded5ed80f3f4c794a2323b68a5da11fad61b6f2 (diff) | |
download | lldb-9762e10787a7efc2f0d822590cab42ca23d5e4f9.tar.gz |
new syntax for summary strings:
- ${*expr} now simply means to dereference expr before actually using it
- bitfields, array ranges and pointer ranges now work in a (hopefully) more natural and language-compliant way
a new class TypeHierarchyNavigator replicates the behavior of the FormatManager in going through type hierarchies
when one-lining summary strings, children's summaries can be used as well as values
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@134458 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'source')
-rw-r--r-- | source/Core/DataExtractor.cpp | 4 | ||||
-rw-r--r-- | source/Core/Debugger.cpp | 739 | ||||
-rw-r--r-- | source/Core/ValueObject.cpp | 85 | ||||
-rw-r--r-- | source/Symbol/ClangASTContext.cpp | 34 | ||||
-rw-r--r-- | source/Symbol/TypeHierarchyNavigator.cpp | 121 | ||||
-rw-r--r-- | source/Target/StackFrame.cpp | 146 |
6 files changed, 671 insertions, 458 deletions
diff --git a/source/Core/DataExtractor.cpp b/source/Core/DataExtractor.cpp index 9d6657355..4cc98f31a 100644 --- a/source/Core/DataExtractor.cpp +++ b/source/Core/DataExtractor.cpp @@ -753,7 +753,9 @@ DataExtractor::GetMaxU64Bitfield (uint32_t *offset_ptr, uint32_t size, uint32_t { if (bitfield_bit_offset > 0) uval64 >>= bitfield_bit_offset; - uint64_t bitfield_mask = ((1 << bitfield_bit_size) - 1); + uint64_t bitfield_mask = ((1ul << bitfield_bit_size) - 1); + if(!bitfield_mask && bitfield_bit_offset == 0 && bitfield_bit_size == 64) + return uval64; uval64 &= bitfield_mask; } return uval64; diff --git a/source/Core/Debugger.cpp b/source/Core/Debugger.cpp index 21d45cde1..18e88f6b7 100644 --- a/source/Core/Debugger.cpp +++ b/source/Core/Debugger.cpp @@ -694,6 +694,176 @@ TestPromptFormats (StackFrame *frame) } } +// #define VERBOSE_FORMATPROMPT_OUTPUT +#ifdef VERBOSE_FORMATPROMPT_OUTPUT +#define IFERROR_PRINT_IT if (error.Fail()) \ +{ \ + printf("ERROR: %s\n",error.AsCString("unknown")); \ + break; \ +} +#else // IFERROR_PRINT_IT +#define IFERROR_PRINT_IT if (error.Fail()) \ +break; +#endif // IFERROR_PRINT_IT + +static bool +ScanFormatDescriptor(const char* var_name_begin, + const char* var_name_end, + const char** var_name_final, + const char** percent_position, + lldb::Format* custom_format, + ValueObject::ValueObjectRepresentationStyle* val_obj_display) +{ + *percent_position = ::strchr(var_name_begin,'%'); + if(!*percent_position || *percent_position > var_name_end) + *var_name_final = var_name_end; + else + { + *var_name_final = *percent_position; + char* format_name = new char[var_name_end-*var_name_final]; format_name[var_name_end-*var_name_final-1] = '\0'; + memcpy(format_name, *var_name_final+1, var_name_end-*var_name_final-1); + if ( !FormatManager::GetFormatFromCString(format_name, + true, + *custom_format) ) + { + // if this is an @ sign, print ObjC description + if(*format_name == '@') + *val_obj_display = ValueObject::eDisplayLanguageSpecific; + // if this is a V, print the value using the default format + if(*format_name == 'V') + *val_obj_display = ValueObject::eDisplayValue; + } + // a good custom format tells us to print the value using it + else + *val_obj_display = ValueObject::eDisplayValue; + delete format_name; + } + return true; +} + +static bool +ScanBracketedRange(const char* var_name_begin, + const char* var_name_end, + const char* var_name_final, + const char** open_bracket_position, + const char** separator_position, + const char** close_bracket_position, + const char** var_name_final_if_array_range, + int64_t* index_lower, + int64_t* index_higher) +{ + *open_bracket_position = ::strchr(var_name_begin,'['); + if(*open_bracket_position && *open_bracket_position < var_name_final) + { + *separator_position = ::strchr(*open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield + *close_bracket_position = ::strchr(*open_bracket_position,']'); + // as usual, we assume that [] will come before % + //printf("trying to expand a []\n"); + *var_name_final_if_array_range = *open_bracket_position; + if(*close_bracket_position - *open_bracket_position == 1) + { + *index_lower = 0; + } + else if (*separator_position == NULL || *separator_position > var_name_end) + { + char *end = NULL; + *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); + *index_higher = *index_lower; + //printf("got to read low=%d high same\n",bitfield_lower); + } + else if(*close_bracket_position && *close_bracket_position < var_name_end) + { + char *end = NULL; + *index_lower = ::strtoul (*open_bracket_position+1, &end, 0); + *index_higher = ::strtoul (*separator_position+1, &end, 0); + //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher); + } + else + return false; + if (*index_lower > *index_higher && *index_higher > 0) + { + int temp = *index_lower; + *index_lower = *index_higher; + *index_higher = temp; + } + } + return true; +} + + +static ValueObjectSP +ExpandExpressionPath(ValueObject* vobj, + StackFrame* frame, + bool* do_deref_pointer, + const char* var_name_begin, + const char* var_name_final, + Error& error) +{ + + StreamString sstring; + VariableSP var_sp; + + if(*do_deref_pointer) + sstring.PutChar('*'); + else if(vobj->IsDereferenceOfParent() && ClangASTContext::IsPointerType(vobj->GetParent()->GetClangType()) && !vobj->IsArrayItemForPointer()) + { + sstring.PutChar('*'); + *do_deref_pointer = true; + } + + vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers); +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("name to expand in phase 0: %s\n",sstring.GetData()); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3); +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("name to expand in phase 1: %s\n",sstring.GetData()); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + std::string name = std::string(sstring.GetData()); + ValueObjectSP target = frame->GetValueForVariableExpressionPath (name.c_str(), + eNoDynamicValues, + 0, + var_sp, + error); + return target; +} + +static ValueObjectSP +ExpandIndexedExpression(ValueObject* vobj, + uint32_t index, + StackFrame* frame, + Error error) +{ + ValueObjectSP item; + bool is_array = ClangASTContext::IsArrayType(vobj->GetClangType()); + + if(is_array) + return vobj->GetChildAtIndex(index, true); + else + { + const char* ptr_deref_format = "%s[%d]"; + char* ptr_deref_buffer = new char[1024]; + StreamString expr_path_string; + vobj->GetExpressionPath(expr_path_string, true, ValueObject::eHonorPointers); + const char* expr_path = expr_path_string.GetData(); +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("name to deref in phase 0: %s\n",expr_path); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + ::sprintf(ptr_deref_buffer, ptr_deref_format, expr_path, index); +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("name to deref in phase 1: %s\n",ptr_deref_buffer); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + lldb::VariableSP var_sp; + item = frame->GetValueForVariableExpressionPath (ptr_deref_buffer, + eNoDynamicValues, + 0, + var_sp, + error); + delete ptr_deref_buffer; + } + return item; +} + bool Debugger::FormatPrompt ( @@ -783,6 +953,7 @@ Debugger::FormatPrompt FileSpec format_file_spec; const RegisterInfo *reg_info = NULL; RegisterContext *reg_ctx = NULL; + bool do_deref_pointer = false; // Each variable must set success to true below... bool var_success = false; @@ -791,270 +962,19 @@ Debugger::FormatPrompt case '*': { if (!vobj) break; - lldb::clang_type_t pointer_clang_type = vobj->GetClangType(); - clang_type_t elem_or_pointee_clang_type; - const Flags type_flags (ClangASTContext::GetTypeInfo (pointer_clang_type, - vobj->GetClangAST(), - &elem_or_pointee_clang_type)); - bool is_pointer = type_flags.Test (ClangASTContext::eTypeIsPointer), - is_array = type_flags.Test (ClangASTContext::eTypeIsArray); - if ( is_array || - ( is_pointer && ::strchr(var_name_begin,'[') && ::strchr(var_name_begin,'[') < var_name_end ) - ) - { - const char* var_name_final; - const char* close_bracket_position = NULL; - const char* percent_position = NULL; - const char* targetvalue; - lldb::Format custom_format = eFormatInvalid; - int index_lower = -1; - int index_higher = -1; - ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary; - { - percent_position = ::strchr(var_name_begin,'%'); - if(!percent_position || percent_position > var_name_end) - var_name_final = var_name_end; - else - { - var_name_final = percent_position; - char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0'; - memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1); - if ( !FormatManager::GetFormatFromCString(format_name, - true, - custom_format) ) - { - // if this is an @ sign, print ObjC description - if(*format_name == '@') - val_obj_display = ValueObject::eDisplayLanguageSpecific; - // if this is a V, print the value using the default format - if(*format_name == 'V') - val_obj_display = ValueObject::eDisplayValue; - } - // a good custom format tells us to print the value using it - else - val_obj_display = ValueObject::eDisplayValue; - } - } - - { - const char* open_bracket_position = ::strchr(var_name_begin,'['); - if(open_bracket_position && open_bracket_position < var_name_final) - { - // TODO: pick a way to say "all entries". this will make more sense once - // regex typenames are in place. now, you need to be size-aware anyways - const char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield - close_bracket_position = ::strchr(open_bracket_position,']'); - // as usual, we assume that [] will come before % - //printf("trying to expand a []\n"); - var_name_final = open_bracket_position; - if(close_bracket_position - open_bracket_position == 1) - { - if(is_array) - { - index_lower = 0; - index_higher = vobj->GetNumChildren() - 1; - } - else - break; // cannot auto-determine size for pointers - } - else if (separator_position == NULL || separator_position > var_name_end) - { - char *end = NULL; - index_lower = ::strtoul (open_bracket_position+1, &end, 0); - index_higher = index_lower; - //printf("got to read low=%d high same\n",bitfield_lower); - } - else if(close_bracket_position && close_bracket_position < var_name_end) - { - char *end = NULL; - index_lower = ::strtoul (open_bracket_position+1, &end, 0); - index_higher = ::strtoul (separator_position+1, &end, 0); - //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher); - } - else - break; - if (index_lower > index_higher) - { - int temp = index_lower; - index_lower = index_higher; - index_higher = temp; - } - //*((char*)open_bracket_position) = '\0'; - //printf("variable name is %s\n",var_name_begin); - //*((char*)open_bracket_position) = '['; - } - } - - // if you just type a range, lldb will do the "right thing" in picking - // a reasonable display for the array entries. you can override this by - // giving other input (e.g. ${*var[1-3].member1%uint8_t[]}) and they - // will be honored - char* special_directions = NULL; - if (close_bracket_position && (var_name_end-close_bracket_position > 1)) - { - int base_len = var_name_end-close_bracket_position; - special_directions = new char[8+base_len]; - special_directions[0] = '$'; - special_directions[1] = '{'; - special_directions[2] = 'v'; - special_directions[3] = 'a'; - special_directions[4] = 'r'; - memcpy(special_directions+5, close_bracket_position+1, base_len); - special_directions[base_len+7] = '\0'; - printf("%s\n",special_directions); - } - - // let us display items index_lower thru index_higher of this array - s.PutChar('['); - var_success = true; - const char* expr_path = NULL; - const char* ptr_deref_format = "%s[%d]"; - char* ptr_deref_buffer = new char[1024]; - StreamString expr_path_string; - - if(is_pointer) - { - vobj->GetExpressionPath(expr_path_string, true, ValueObject::eHonorPointers); - expr_path = expr_path_string.GetData(); - } - - for(;index_lower<=index_higher;index_lower++) - { - ValueObject* item; - - if(is_array) - item = vobj->GetChildAtIndex(index_lower, true).get(); - else - { -#ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("name to deref in phase 0: %s\n",expr_path); -#endif //VERBOSE_FORMATPROMPT_OUTPUT - ::sprintf(ptr_deref_buffer, ptr_deref_format, expr_path, index_lower); -#ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("name to deref in phase 1: %s\n",ptr_deref_buffer); -#endif //VERBOSE_FORMATPROMPT_OUTPUT - lldb::VariableSP var_sp; - Error error; - item = exe_ctx->frame->GetValueForVariableExpressionPath (ptr_deref_buffer, - eNoDynamicValues, - 0, - var_sp, - error).get(); - if (error.Fail()) - { -#ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("ERROR: %s\n",error.AsCString("unknown")); -#endif //VERBOSE_FORMATPROMPT_OUTPUT - break; - } - } - - if (!special_directions) - { - targetvalue = item->GetPrintableRepresentation(val_obj_display, custom_format); - if(targetvalue) - s.PutCString(targetvalue); - var_success &= (targetvalue != NULL); - if(custom_format != eFormatInvalid) - item->SetFormat(eFormatDefault); - } - else - { - var_success &= FormatPrompt(special_directions, sc, exe_ctx, addr, s, NULL, item); - } - - if(index_lower < index_higher) - s.PutChar(','); - } - s.PutChar(']'); - break; - - } - else if (is_pointer) - { - var_name_begin++; - uint32_t offset = 0; - DataExtractor read_for_null = vobj->GetDataExtractor(); - if (read_for_null.GetPointer(&offset) == 0) - break; - if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type) ) - { - Error error; - realvobj = vobj; - vobj = vobj->Dereference(error).get(); - if(!vobj || error.Fail()) - break; - } - else if (ClangASTContext::IsCharType (elem_or_pointee_clang_type)) - { - StreamString sstr; - ExecutionContextScope *exe_scope = vobj->GetExecutionContextScope(); - Process *process = exe_scope->CalculateProcess(); - if(!process) break; - lldb::addr_t cstr_address = LLDB_INVALID_ADDRESS; - AddressType cstr_address_type = eAddressTypeInvalid; - DataExtractor data; - size_t bytes_read = 0; - std::vector<char> data_buffer; - Error error; - cstr_address = vobj->GetPointerValue (cstr_address_type, true); - { - const size_t k_max_buf_size = 256; - data_buffer.resize (k_max_buf_size + 1); - // NULL terminate in case we don't get the entire C string - data_buffer.back() = '\0'; - - sstr << '"'; - - data.SetData (&data_buffer.front(), data_buffer.size(), endian::InlHostByteOrder()); - while ((bytes_read = process->ReadMemory (cstr_address, &data_buffer.front(), k_max_buf_size, error)) > 0) - { - size_t len = strlen(&data_buffer.front()); - if (len == 0) - break; - if (len > bytes_read) - len = bytes_read; - - data.Dump (&sstr, - 0, // Start offset in "data" - eFormatCharArray, // Print as characters - 1, // Size of item (1 byte for a char!) - len, // How many bytes to print? - UINT32_MAX, // num per line - LLDB_INVALID_ADDRESS,// base address - 0, // bitfield bit size - 0); // bitfield bit offset - - if (len < k_max_buf_size) - break; - cstr_address += k_max_buf_size; - } - sstr << '"'; - s.PutCString(sstr.GetData()); - var_success = true; - break; - } - } - else /*some other pointer type*/ - { - Error error; - realvobj = vobj; - vobj = vobj->Dereference(error).get(); - if(!vobj || error.Fail()) - break; - } - } - else - break; + do_deref_pointer = true; + var_name_begin++; } case 'v': { - const char* targetvalue; ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary; ValueObject* target; lldb::Format custom_format = eFormatInvalid; - int bitfield_lower = -1; - int bitfield_higher = -1; + const char* var_name_final; + const char* var_name_final_if_array_range = NULL; + const char* close_bracket_position; + int64_t index_lower = -1, index_higher = -1; + bool is_array_range = false; if (!vobj) break; // simplest case ${var}, just print vobj's value if (::strncmp (var_name_begin, "var}", strlen("var}")) == 0) @@ -1065,217 +985,140 @@ Debugger::FormatPrompt else if (::strncmp(var_name_begin,"var%",strlen("var%")) == 0) { // this is a variable with some custom format applied to it - const char* var_name_final; + const char* percent_position; target = vobj; val_obj_display = ValueObject::eDisplayValue; - { - const char* percent_position = ::strchr(var_name_begin,'%'); // TODO: make this a constant - //if(!percent_position || percent_position > var_name_end) - // var_name_final = var_name_end; - //else - //{ - var_name_final = percent_position; - char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0'; - memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1); - if ( !FormatManager::GetFormatFromCString(format_name, - true, - custom_format) ) - { - // if this is an @ sign, print ObjC description - if(*format_name == '@') - val_obj_display = ValueObject::eDisplayLanguageSpecific; - } - delete format_name; - //} - } - } - else if (::strncmp(var_name_begin,"var[",strlen("var[")) == 0) - { - // this is a bitfield variable - const char *var_name_final; - target = vobj; - val_obj_display = ValueObject::eDisplayValue; - { - const char* percent_position = ::strchr(var_name_begin,'%'); - if(!percent_position || percent_position > var_name_end) - var_name_final = var_name_end; - else - { - var_name_final = percent_position; - char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0'; - memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1); - if ( !FormatManager::GetFormatFromCString(format_name, - true, - custom_format) ) - { - delete format_name; - break; - } - else - delete format_name; - } - } - - { - // code here might be simpler than in the case below - const char* open_bracket_position = ::strchr(var_name_begin,'['); - if(open_bracket_position && open_bracket_position < var_name_final) - { - const char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield - const char* close_bracket_position = ::strchr(open_bracket_position,']'); - // as usual, we assume that [] will come before % - //printf("trying to expand a []\n"); - var_name_final = open_bracket_position; - if (separator_position == NULL || separator_position > var_name_end) - { - char *end = NULL; - bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0); - bitfield_higher = bitfield_lower; - //printf("got to read low=%d high same\n",bitfield_lower); - } - else if(close_bracket_position && close_bracket_position < var_name_end) - { - char *end = NULL; - bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0); - bitfield_higher = ::strtoul (separator_position+1, &end, 0); - //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher); - } - else - break; - if(bitfield_lower > bitfield_higher) - { - int temp = bitfield_lower; - bitfield_lower = bitfield_higher; - bitfield_higher = temp; - } - } - } + ScanFormatDescriptor(var_name_begin, + var_name_end, + &var_name_final, + &percent_position, + &custom_format, + &val_obj_display); } // this is ${var.something} or multiple .something nested else if (::strncmp (var_name_begin, "var", strlen("var")) == 0) { - // check for custom format string - - // we need this because we might have ${var.something%format}. in this case var_name_end - // still points to the closing }, but we must extract the variable name only up to - // before the %. var_name_final will point to that % sign position - const char* var_name_final; - - { - const char* percent_position = ::strchr(var_name_begin,'%'); - if(!percent_position || percent_position > var_name_end) - var_name_final = var_name_end; - else - { - var_name_final = percent_position; - char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0'; - memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1); - if ( !FormatManager::GetFormatFromCString(format_name, - true, - custom_format) ) - { - // if this is an @ sign, print ObjC description - if(*format_name == '@') - val_obj_display = ValueObject::eDisplayLanguageSpecific; - // if this is a V, print the value using the default format - if(*format_name == 'V') - val_obj_display = ValueObject::eDisplayValue; - } - // a good custom format tells us to print the value using it - else - val_obj_display = ValueObject::eDisplayValue; - } - } - - { - const char* open_bracket_position = ::strchr(var_name_begin,'['); - if(open_bracket_position && open_bracket_position < var_name_final) - { - const char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield - const char* close_bracket_position = ::strchr(open_bracket_position,']'); - // as usual, we assume that [] will come before % - //printf("trying to expand a []\n"); - var_name_final = open_bracket_position; - if (separator_position == NULL || separator_position > var_name_end) - { - char *end = NULL; - bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0); - bitfield_higher = bitfield_lower; - //printf("got to read low=%d high same\n",bitfield_lower); - } - else if(close_bracket_position && close_bracket_position < var_name_end) - { - char *end = NULL; - bitfield_lower = ::strtoul (open_bracket_position+1, &end, 0); - bitfield_higher = ::strtoul (separator_position+1, &end, 0); - //printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher); - } - else - break; - if(bitfield_lower > bitfield_higher) - { - int temp = bitfield_lower; - bitfield_lower = bitfield_higher; - bitfield_higher = temp; - } - //*((char*)open_bracket_position) = '\0'; - //printf("variable name is %s\n",var_name_begin); - //*((char*)open_bracket_position) = '['; - } - } + const char* percent_position; + ScanFormatDescriptor(var_name_begin, + var_name_end, + &var_name_final, + &percent_position, + &custom_format, + &val_obj_display); + + const char* open_bracket_position; + const char* separator_position; + ScanBracketedRange(var_name_begin, + var_name_end, + var_name_final, + &open_bracket_position, + &separator_position, + &close_bracket_position, + &var_name_final_if_array_range, + &index_lower, + &index_higher); + Error error; - lldb::VariableSP var_sp; - StreamString sstring; - vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers); -#ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("name to expand in phase 0: %s\n",sstring.GetData()); -#endif //VERBOSE_FORMATPROMPT_OUTPUT - sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3); -#ifdef VERBOSE_FORMATPROMPT_OUTPUT - printf("name to expand in phase 1: %s\n",sstring.GetData()); -#endif //VERBOSE_FORMATPROMPT_OUTPUT - std::string name = std::string(sstring.GetData()); - target = exe_ctx->frame->GetValueForVariableExpressionPath (name.c_str(), - eNoDynamicValues, - 0, - var_sp, - error).get(); - if (error.Fail()) + target = ExpandExpressionPath(vobj, + exe_ctx->frame, + &do_deref_pointer, + var_name_begin, + var_name_final, + error).get(); + + if (error.Fail() || !target) { #ifdef VERBOSE_FORMATPROMPT_OUTPUT printf("ERROR: %s\n",error.AsCString("unknown")); #endif //VERBOSE_FORMATPROMPT_OUTPUT - break; + if (var_name_final_if_array_range) + { + target = ExpandExpressionPath(vobj, + exe_ctx->frame, + &do_deref_pointer, + var_name_begin, + var_name_final_if_array_range, + error).get(); + } + + IFERROR_PRINT_IT + else + is_array_range = true; } + + do_deref_pointer = false; // I have honored the request to deref + } else break; - if (bitfield_lower >= 0) + + if(do_deref_pointer) { - //printf("trying to print a []\n"); - // format this as a bitfield - DataExtractor extractor = target->GetDataExtractor(); - uint32_t item_byte_size = ClangASTType::GetTypeByteSize(target->GetClangAST(), target->GetClangType()); - if(custom_format == eFormatInvalid) - custom_format = eFormatHex; - var_success = - extractor.Dump(&s, 0, custom_format, item_byte_size, 1, 1, LLDB_INVALID_ADDRESS, bitfield_higher-bitfield_lower+1, bitfield_lower) > 0; - //printf("var_success = %s\n",var_success ? "true" : "false"); + // I have not deref-ed yet, let's do it + // this happens when we are not going through GetValueForVariableExpressionPath + // to get to the target ValueObject + Error error; + target = target->Dereference(error).get(); + IFERROR_PRINT_IT + do_deref_pointer = false; } + + if(!is_array_range) + var_success = target->DumpPrintableRepresentation(s,val_obj_display, custom_format); else { - // format this as usual - targetvalue = target->GetPrintableRepresentation(val_obj_display, custom_format); - if(targetvalue) - s.PutCString(targetvalue); - var_success = targetvalue; - //printf("here I come 4 : %s\n",var_success ? "good" : "bad"); - if(custom_format != eFormatInvalid) - target->SetFormat(eFormatDefault); - //printf("here I come 5\n"); + bool is_array = ClangASTContext::IsArrayType(vobj->GetClangType()); + bool is_pointer = ClangASTContext::IsPointerType(vobj->GetClangType()); + + if(!is_array && !is_pointer) + break; + + char* special_directions = NULL; + if (close_bracket_position && (var_name_end-close_bracket_position > 1)) + { + int base_len = var_name_end-close_bracket_position; + special_directions = new char[8+base_len]; + special_directions[0] = '$'; + special_directions[1] = '{'; + special_directions[2] = 'v'; + special_directions[3] = 'a'; + special_directions[4] = 'r'; + memcpy(special_directions+5, close_bracket_position+1, base_len); + special_directions[base_len+7] = '\0'; +#ifdef VERBOSE_FORMATPROMPT_OUTPUT + printf("%s\n",special_directions); +#endif //VERBOSE_FORMATPROMPT_OUTPUT + } + + // let us display items index_lower thru index_higher of this array + s.PutChar('['); + var_success = true; + + if(index_higher < 0) + index_higher = vobj->GetNumChildren() - 1; + + for(;index_lower<=index_higher;index_lower++) + { + Error error; + ValueObject* item = ExpandIndexedExpression(vobj, + index_lower, + exe_ctx->frame, + error).get(); + + + IFERROR_PRINT_IT + if (!special_directions) + var_success &= item->DumpPrintableRepresentation(s,val_obj_display, custom_format); + else + var_success &= FormatPrompt(special_directions, sc, exe_ctx, addr, s, NULL, item); + + if(index_lower < index_higher) + s.PutChar(','); + } + s.PutChar(']'); } - break; + break; } case 'a': if (::strncmp (var_name_begin, "addr}", strlen("addr}")) == 0) diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp index a8696be3f..e08163097 100644 --- a/source/Core/ValueObject.cpp +++ b/source/Core/ValueObject.cpp @@ -74,6 +74,7 @@ ValueObject::ValueObject (ValueObject &parent) : m_pointers_point_to_load_addrs (false), m_is_deref_of_parent (false), m_is_array_item_for_pointer(false), + m_is_bitfield_for_scalar(false), m_last_format_mgr_revision(0), m_last_summary_format(), m_last_value_format() @@ -110,6 +111,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) : m_pointers_point_to_load_addrs (false), m_is_deref_of_parent (false), m_is_array_item_for_pointer(false), + m_is_bitfield_for_scalar(false), m_last_format_mgr_revision(0), m_last_summary_format(), m_last_value_format() @@ -515,7 +517,7 @@ ValueObject::GetSummaryAsCString () s.PutCString(", "); s.PutCString(child_sp.get()->GetName().AsCString()); s.PutChar('='); - s.PutCString(child_sp.get()->GetValueAsCString()); + s.PutCString(child_sp.get()->GetPrintableRepresentation()); } } @@ -768,7 +770,9 @@ ValueObject::GetValueAsCString () if (m_last_value_format) format = m_last_value_format->m_format; else - format = ClangASTType::GetFormat(clang_type); + // force the system into using unsigned integers for bitfields + format = (m_is_bitfield_for_scalar ? eFormatUnsigned : + ClangASTType::GetFormat(clang_type)); } if (ClangASTType::DumpTypeValue (GetClangAST(), // The clang AST @@ -844,13 +848,33 @@ ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_d break; } + if (!return_value) + { + // try to pick the other choice + if (val_obj_display == eDisplayValue) + return_value = GetSummaryAsCString(); + else if (val_obj_display == eDisplaySummary) + return_value = GetValueAsCString(); + else + return_value = ""; + } - // try to use the value if the user's choice failed - if(!return_value && val_obj_display != eDisplayValue) - return_value = GetValueAsCString(); - - return return_value; + return (return_value ? return_value : ""); + +} +bool +ValueObject::DumpPrintableRepresentation(Stream& s, + ValueObjectRepresentationStyle val_obj_display, + lldb::Format custom_format) +{ + const char *targetvalue = GetPrintableRepresentation(val_obj_display, custom_format); + if(targetvalue) + s.PutCString(targetvalue); + bool var_success = (targetvalue != NULL); + if(custom_format != eFormatInvalid) + SetFormat(eFormatDefault); + return var_success; } addr_t @@ -1073,6 +1097,12 @@ ValueObject::IsPointerType () } bool +ValueObject::IsScalarType () +{ + return ClangASTContext::IsScalarType (GetClangType()); +} + +bool ValueObject::IsIntegerType (bool &is_signed) { return ClangASTContext::IsIntegerType (GetClangType(), is_signed); @@ -1128,6 +1158,47 @@ ValueObject::GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create) return synthetic_child_sp; } +ValueObjectSP +ValueObject::GetSyntheticBitFieldChild (uint32_t from, uint32_t to, bool can_create) +{ + ValueObjectSP synthetic_child_sp; + if (IsScalarType ()) + { + char index_str[64]; + snprintf(index_str, sizeof(index_str), "[%i-%i]", from, to); + ConstString index_const_str(index_str); + // Check if we have already created a synthetic array member in this + // valid object. If we have we will re-use it. + synthetic_child_sp = GetSyntheticChild (index_const_str); + if (!synthetic_child_sp) + { + ValueObjectChild *synthetic_child; + // We haven't made a synthetic array member for INDEX yet, so + // lets make one and cache it for any future reference. + synthetic_child = new ValueObjectChild(*this, + GetClangAST(), + GetClangType(), + index_const_str, + GetByteSize(), + 0, + to-from+1, + from, + false, + false); + + // Cache the value if we got one back... + if (synthetic_child) + { + AddSyntheticChild(index_const_str, synthetic_child); + synthetic_child_sp = synthetic_child->GetSP(); + synthetic_child_sp->SetName(index_str); + synthetic_child_sp->m_is_bitfield_for_scalar = true; + } + } + } + return synthetic_child_sp; +} + void ValueObject::CalculateDynamicValue (lldb::DynamicValueType use_dynamic) { diff --git a/source/Symbol/ClangASTContext.cpp b/source/Symbol/ClangASTContext.cpp index dd297191b..5d2f0dd94 100644 --- a/source/Symbol/ClangASTContext.cpp +++ b/source/Symbol/ClangASTContext.cpp @@ -4464,6 +4464,40 @@ ClangASTContext::IsFloatingPointType (clang_type_t clang_type, uint32_t &count, return false; } +bool +ClangASTContext::IsScalarType (lldb::clang_type_t clang_type) +{ + bool is_signed; + if (ClangASTContext::IsIntegerType(clang_type, is_signed)) + return true; + + uint32_t count; + bool is_complex; + return ClangASTContext::IsFloatingPointType(clang_type, count, is_complex) && !is_complex; +} + +bool +ClangASTContext::IsPointerToScalarType (lldb::clang_type_t clang_type) +{ + if (!IsPointerType(clang_type)) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + lldb::clang_type_t pointee_type = qual_type.getTypePtr()->getPointeeType().getAsOpaquePtr(); + return IsScalarType(pointee_type); +} + +bool +ClangASTContext::IsArrayOfScalarType (lldb::clang_type_t clang_type) +{ + if (!IsArrayType(clang_type)) + return false; + + QualType qual_type (QualType::getFromOpaquePtr(clang_type)); + lldb::clang_type_t item_type = cast<ArrayType>(qual_type.getTypePtr())->getElementType().getAsOpaquePtr(); + return IsScalarType(item_type); +} + bool ClangASTContext::GetCXXClassName (clang_type_t clang_type, std::string &class_name) diff --git a/source/Symbol/TypeHierarchyNavigator.cpp b/source/Symbol/TypeHierarchyNavigator.cpp new file mode 100644 index 000000000..fdbe795be --- /dev/null +++ b/source/Symbol/TypeHierarchyNavigator.cpp @@ -0,0 +1,121 @@ +//===-- TypeHierarchyNavigator.cpp -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Error.h" +#include "lldb/Core/ValueObject.h" +#include "lldb/Symbol/ClangASTContext.h" +#include "lldb/Symbol/TypeHierarchyNavigator.h" + +using namespace lldb; +using namespace lldb_private; + +bool +TypeHierarchyNavigator::LoopThrough(TypeHierarchyNavigatorCallback callback, + void* callback_baton) +{ + return LoopThrough(m_root_type, + callback, + eRootType, + (callback_baton ? callback_baton : m_default_callback_baton)); +} + +bool +TypeHierarchyNavigator::LoopThrough(const clang::QualType& qual_type, + TypeHierarchyNavigatorCallback callback, + RelationshipToCurrentType reason_why_here, + void* callback_baton) +{ + if (qual_type.isNull()) + return true; + clang::QualType type = qual_type.getUnqualifiedType(); + type.removeLocalConst(); type.removeLocalVolatile(); type.removeLocalRestrict(); + const clang::Type* typePtr = type.getTypePtrOrNull(); + if (!typePtr) + return true; + if (!callback(type, reason_why_here, callback_baton)) + return false; + // look for a "base type", whatever that means + if (typePtr->isReferenceType()) + { + if (LoopThrough(type.getNonReferenceType(), callback, eStrippedReference, callback_baton) == false) + return false; + } + if (typePtr->isPointerType()) + { + if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false) + return false; + } + if (typePtr->isObjCObjectPointerType()) + { + /* + for some reason, C++ can quite easily obtain the type hierarchy for a ValueObject + even if the VO represent a pointer-to-class, as long as the typePtr is right + Objective-C on the other hand cannot really complete an @interface when + the VO refers to a pointer-to-@interface + */ + Error error; + ValueObject* target = m_value_object.Dereference(error).get(); + if(error.Fail() || !target) + return true; + if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false) + return false; + } + const clang::ObjCObjectType *objc_class_type = typePtr->getAs<clang::ObjCObjectType>(); + if (objc_class_type) + { + clang::ASTContext *ast = m_value_object.GetClangAST(); + if (ClangASTContext::GetCompleteType(ast, m_value_object.GetClangType()) && !objc_class_type->isObjCId()) + { + clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface(); + if(class_interface_decl) + { + clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass(); + if(superclass_interface_decl) + { + clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl)); + return LoopThrough(ivar_qual_type, callback, eObjCBaseClass, callback_baton); + } + } + } + } + // for C++ classes, navigate up the hierarchy + if (typePtr->isRecordType()) + { + clang::CXXRecordDecl* record = typePtr->getAsCXXRecordDecl(); + if (record) + { + if (!record->hasDefinition()) + ClangASTContext::GetCompleteType(m_value_object.GetClangAST(), m_value_object.GetClangType()); + if (record->hasDefinition()) + { + clang::CXXRecordDecl::base_class_iterator pos,end; + if( record->getNumBases() > 0) + { + end = record->bases_end(); + for (pos = record->bases_begin(); pos != end; pos++) + if (LoopThrough(pos->getType(), callback, eCXXBaseClass, callback_baton) == false) + return false; + } + if (record->getNumVBases() > 0) + { + end = record->vbases_end(); + for (pos = record->vbases_begin(); pos != end; pos++) + if (LoopThrough(pos->getType(), callback, eCXXVBaseClass, callback_baton) == false) + return false; + } + } + } + } + // try to strip typedef chains + const clang::TypedefType* type_tdef = type->getAs<clang::TypedefType>(); + if (type_tdef) + return LoopThrough(type_tdef->getDecl()->getUnderlyingType(), callback, eStrippedTypedef, callback_baton); + else + return true; +} diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp index efc2f3f56..ed50353fd 100644 --- a/source/Target/StackFrame.cpp +++ b/source/Target/StackFrame.cpp @@ -645,9 +645,47 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, { char *end = NULL; long child_index = ::strtol (&var_path[1], &end, 0); - if (end && *end == ']') + if (end && *end == ']' + && *(end-1) != '[') // this code forces an error in the case of arr[]. as bitfield[] is not a good syntax we're good to go { - + if (ClangASTContext::IsPointerToScalarType(valobj_sp->GetClangType()) && deref) + { + // what we have is *ptr[low]. the most similar C++ syntax is to deref ptr + // and extract bit low out of it. reading array item low + // would be done by saying ptr[low], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->Dereference(error)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + else if (ClangASTContext::IsArrayOfScalarType(valobj_sp->GetClangType()) && deref) + { + // what we have is *arr[low]. the most similar C++ syntax is to get arr[0] + // (an operation that is equivalent to deref-ing arr) + // and extract bit low out of it. reading array item low + // would be done by saying arr[low], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + if (valobj_sp->IsPointerType ()) { child_valobj_sp = valobj_sp->GetSyntheticArrayMemberFromPointer (child_index, true); @@ -674,6 +712,19 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, var_expr_path_strm.GetString().c_str()); } } + else if (ClangASTContext::IsScalarType(valobj_sp->GetClangType())) + { + // this is a bitfield asking to display just one bit + child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, child_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("bitfield range %i-%i is not valid for \"(%s) %s\"", + child_index, child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } else { valobj_sp->GetExpressionPath (var_expr_path_strm, false); @@ -702,6 +753,97 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, // able to find the child member break; } + else if(end && *end == '-') + { + // this is most probably a BitField, let's take a look + char *real_end = NULL; + long final_index = ::strtol (end+1, &real_end, 0); + if(real_end && *real_end == ']') + { + // if the format given is [high-low], swap range + if(child_index > final_index) + { + long temp = child_index; + child_index = final_index; + final_index = temp; + } + + if (ClangASTContext::IsPointerToScalarType(valobj_sp->GetClangType()) && deref) + { + // what we have is *ptr[low-high]. the most similar C++ syntax is to deref ptr + // and extract bits low thru high out of it. reading array items low thru high + // would be done by saying ptr[low-high], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->Dereference(error)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + else if (ClangASTContext::IsArrayOfScalarType(valobj_sp->GetClangType()) && deref) + { + // what we have is *arr[low-high]. the most similar C++ syntax is to get arr[0] + // (an operation that is equivalent to deref-ing arr) + // and extract bits low thru high out of it. reading array items low thru high + // would be done by saying arr[low-high], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true)); + if (error.Fail()) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + + child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true); + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, false); + error.SetErrorStringWithFormat ("bitfield range %i-%i is not valid for \"(%s) %s\"", + child_index, final_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + + if (!child_valobj_sp) + { + // Invalid bitfield range... + return ValueObjectSP(); + } + + // Erase the bitfield member specification '[%i-%i]' where + // %i is the index + var_path.erase(0, (real_end - var_path.c_str()) + 1); + separator_idx = var_path.find_first_of(".-["); + if (use_dynamic != lldb::eNoDynamicValues) + { + ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; + } + // Break out early from the switch since we were + // able to find the child member + break; + + } + } + else + { + error.SetErrorStringWithFormat("invalid square bracket encountered after \"%s\" in \"%s\"", + var_expr_path_strm.GetString().c_str(), + var_path.c_str()); } return ValueObjectSP(); |