aboutsummaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEnrico Granata <granata.enrico@gmail.com>2011-07-06 02:13:41 +0000
committerEnrico Granata <granata.enrico@gmail.com>2011-07-06 02:13:41 +0000
commit9762e10787a7efc2f0d822590cab42ca23d5e4f9 (patch)
tree3ea76021b69cbb667cfd35d3be1706d9d38e177e /source
parent2ded5ed80f3f4c794a2323b68a5da11fad61b6f2 (diff)
downloadlldb-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.cpp4
-rw-r--r--source/Core/Debugger.cpp739
-rw-r--r--source/Core/ValueObject.cpp85
-rw-r--r--source/Symbol/ClangASTContext.cpp34
-rw-r--r--source/Symbol/TypeHierarchyNavigator.cpp121
-rw-r--r--source/Target/StackFrame.cpp146
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();