Add support for "dynamic values" for C++ classes. This currently only works for "frame var" and for the
expressions that are simple enough to get passed to the "frame var" underpinnings. The parser code will
have to be changed to also query for the dynamic types & offsets as it is looking up variables.
The behavior of "frame var" is controlled in two ways. You can pass "-d {true/false} to the frame var
command to get the dynamic or static value of the variables you are printing.
There's also a general setting:
target.prefer-dynamic-value (boolean) = 'true'
which is consulted if you call "frame var" without supplying a value for the -d option.
git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@129623 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/API/SBFrame.cpp b/source/API/SBFrame.cpp
index e51c2ec..93c5410 100644
--- a/source/API/SBFrame.cpp
+++ b/source/API/SBFrame.cpp
@@ -343,6 +343,13 @@
SBValue
SBFrame::FindVariable (const char *name)
{
+ bool use_dynamic = m_opaque_sp->CalculateTarget()->GetPreferDynamicValue();
+ return FindVariable (name, use_dynamic);
+}
+
+SBValue
+SBFrame::FindVariable (const char *name, bool use_dynamic)
+{
VariableSP var_sp;
if (m_opaque_sp && name && name[0])
{
@@ -369,7 +376,7 @@
SBValue sb_value;
if (var_sp)
- *sb_value = ValueObjectSP (new ValueObjectVariable (m_opaque_sp.get(), var_sp));
+ *sb_value = ValueObjectSP (m_opaque_sp->GetValueObjectForFrameVariable(var_sp, use_dynamic));
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
@@ -382,6 +389,13 @@
SBValue
SBFrame::FindValue (const char *name, ValueType value_type)
{
+ bool use_dynamic = m_opaque_sp->CalculateTarget()->GetPreferDynamicValue();
+ return FindValue (name, value_type, use_dynamic);
+}
+
+SBValue
+SBFrame::FindValue (const char *name, ValueType value_type, bool use_dynamic)
+{
SBValue sb_value;
if (m_opaque_sp && name && name[0])
{
@@ -416,7 +430,8 @@
variable_sp->GetScope() == value_type &&
variable_sp->GetName() == const_name)
{
- *sb_value = ValueObjectSP (new ValueObjectVariable (m_opaque_sp.get(), variable_sp));
+ *sb_value = ValueObjectSP (m_opaque_sp->GetValueObjectForFrameVariable(variable_sp,
+ use_dynamic));
break;
}
}
@@ -564,6 +579,17 @@
bool statics,
bool in_scope_only)
{
+ bool use_dynamic = m_opaque_sp->CalculateTarget()->GetPreferDynamicValue();
+ return GetVariables (arguments, locals, statics, in_scope_only, use_dynamic);
+}
+
+SBValueList
+SBFrame::GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only,
+ bool use_dynamic)
+{
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
@@ -619,7 +645,7 @@
if (in_scope_only && !variable_sp->IsInScope(m_opaque_sp.get()))
continue;
- value_list.Append(m_opaque_sp->GetValueObjectForFrameVariable (variable_sp));
+ value_list.Append(m_opaque_sp->GetValueObjectForFrameVariable (variable_sp, use_dynamic));
}
}
}
@@ -680,6 +706,13 @@
SBValue
SBFrame::EvaluateExpression (const char *expr)
{
+ bool use_dynamic = m_opaque_sp->CalculateTarget()->GetPreferDynamicValue();
+ return EvaluateExpression (expr, use_dynamic);
+}
+
+SBValue
+SBFrame::EvaluateExpression (const char *expr, bool fetch_dynamic_value)
+{
Mutex::Locker api_locker (m_opaque_sp->GetThread().GetProcess().GetTarget().GetAPIMutex());
LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
@@ -696,14 +729,23 @@
const bool unwind_on_error = true;
const bool keep_in_memory = false;
- exe_results = m_opaque_sp->GetThread().GetProcess().GetTarget().EvaluateExpression(expr, m_opaque_sp.get(), unwind_on_error, keep_in_memory, *expr_result);
+ exe_results = m_opaque_sp->GetThread().GetProcess().GetTarget().EvaluateExpression(expr,
+ m_opaque_sp.get(),
+ unwind_on_error,
+ fetch_dynamic_value,
+ keep_in_memory,
+ *expr_result);
}
if (expr_log)
- expr_log->Printf("** [SBFrame::EvaluateExpression] Expression result is %s, summary %s **", expr_result.GetValue(*this), expr_result.GetSummary(*this));
+ expr_log->Printf("** [SBFrame::EvaluateExpression] Expression result is %s, summary %s **",
+ expr_result.GetValue(*this),
+ expr_result.GetSummary(*this));
if (log)
- log->Printf ("SBFrame(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p)", m_opaque_sp.get(), expr, expr_result.get());
+ log->Printf ("SBFrame(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p)", m_opaque_sp.get(),
+ expr,
+ expr_result.get());
return expr_result;
}
diff --git a/source/API/SBValue.cpp b/source/API/SBValue.cpp
index a607841..6401178 100644
--- a/source/API/SBValue.cpp
+++ b/source/API/SBValue.cpp
@@ -339,6 +339,13 @@
SBValue
SBValue::GetChildAtIndex (uint32_t idx)
{
+ bool use_dynamic_value = m_opaque_sp->GetUpdatePoint().GetTarget()->GetPreferDynamicValue();
+ return GetChildAtIndex (idx, use_dynamic_value);
+}
+
+SBValue
+SBValue::GetChildAtIndex (uint32_t idx, bool use_dynamic_value)
+{
lldb::ValueObjectSP child_sp;
if (m_opaque_sp)
@@ -346,6 +353,16 @@
child_sp = m_opaque_sp->GetChildAtIndex (idx, true);
}
+ if (use_dynamic_value)
+ {
+ if (child_sp)
+ {
+ lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue(true, child_sp);
+ if (dynamic_sp)
+ child_sp = dynamic_sp;
+ }
+ }
+
SBValue sb_value (child_sp);
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
if (log)
@@ -374,6 +391,13 @@
SBValue
SBValue::GetChildMemberWithName (const char *name)
{
+ bool use_dynamic_value = m_opaque_sp->GetUpdatePoint().GetTarget()->GetPreferDynamicValue();
+ return GetChildMemberWithName (name, use_dynamic_value);
+}
+
+SBValue
+SBValue::GetChildMemberWithName (const char *name, bool use_dynamic_value)
+{
lldb::ValueObjectSP child_sp;
const ConstString str_name (name);
@@ -382,6 +406,16 @@
child_sp = m_opaque_sp->GetChildMemberWithName (str_name, true);
}
+ if (use_dynamic_value)
+ {
+ if (child_sp)
+ {
+ lldb::ValueObjectSP dynamic_sp = child_sp->GetDynamicValue(true, child_sp);
+ if (dynamic_sp)
+ child_sp = dynamic_sp;
+ }
+ }
+
SBValue sb_value (child_sp);
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API));
diff --git a/source/Commands/CommandObjectExpression.cpp b/source/Commands/CommandObjectExpression.cpp
index 7b9f01c..82d2197 100644
--- a/source/Commands/CommandObjectExpression.cpp
+++ b/source/Commands/CommandObjectExpression.cpp
@@ -77,6 +77,23 @@
print_object = true;
break;
+ case 'd':
+ {
+ bool success;
+ bool result;
+ result = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid dynamic value setting: \"%s\".\n", option_arg);
+ else
+ {
+ if (result)
+ use_dynamic = eLazyBoolYes;
+ else
+ use_dynamic = eLazyBoolNo;
+ }
+ }
+ break;
+
case 'u':
bool success;
unwind_on_error = Args::StringToBoolean(option_arg, true, &success);
@@ -99,6 +116,7 @@
debug = false;
format = eFormatDefault;
print_object = false;
+ use_dynamic = eLazyBoolCalculate;
unwind_on_error = true;
show_types = true;
show_summary = true;
@@ -239,8 +257,27 @@
ExecutionResults exe_results;
bool keep_in_memory = true;
+ bool use_dynamic;
+ // If use dynamic is not set, get it from the target:
+ switch (m_options.use_dynamic)
+ {
+ case eLazyBoolCalculate:
+ {
+ if (m_exe_ctx.target->GetPreferDynamicValue())
+ use_dynamic = true;
+ else
+ use_dynamic = false;
+ }
+ break;
+ case eLazyBoolYes:
+ use_dynamic = true;
+ break;
+ case eLazyBoolNo:
+ use_dynamic = false;
+ break;
+ }
- exe_results = m_exe_ctx.target->EvaluateExpression(expr, m_exe_ctx.frame, m_options.unwind_on_error, keep_in_memory, result_valobj_sp);
+ exe_results = m_exe_ctx.target->EvaluateExpression(expr, m_exe_ctx.frame, m_options.unwind_on_error, use_dynamic, keep_in_memory, result_valobj_sp);
if (exe_results == eExecutionInterrupted && !m_options.unwind_on_error)
{
@@ -266,6 +303,7 @@
m_options.show_types, // Show types when dumping?
false, // Show locations of variables, no since this is a host address which we don't care to see
m_options.print_object, // Print the objective C object?
+ use_dynamic,
true, // Scope is already checked. Const results are always in scope.
false); // Don't flatten output
if (result)
@@ -389,6 +427,7 @@
//{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]", "Specify the format that the expression output should use."},
{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the expression output should use."},
{ LLDB_OPT_SET_2, false, "object-description", 'o', no_argument, NULL, 0, eArgTypeNone, "Print the object description of the value resulting from the expression."},
+{ LLDB_OPT_SET_2, false, "dynamic-value", 'd', required_argument, NULL, 0, eArgTypeBoolean, "Upcast the value resulting from the expression to its dynamic type if available."},
{ LLDB_OPT_SET_ALL, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, breakpoint hit or signal."},
{ LLDB_OPT_SET_ALL, false, "debug", 'g', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug logging of the expression parsing and evaluation."},
{ LLDB_OPT_SET_ALL, false, "use-ir", 'i', no_argument, NULL, 0, eArgTypeNone, "[Temporary] Instructs the expression evaluator to use IR instead of ASTs."},
diff --git a/source/Commands/CommandObjectExpression.h b/source/Commands/CommandObjectExpression.h
index 6eff72c..71eb9bf 100644
--- a/source/Commands/CommandObjectExpression.h
+++ b/source/Commands/CommandObjectExpression.h
@@ -51,6 +51,7 @@
lldb::Format format;
bool debug;
bool print_object;
+ LazyBool use_dynamic;
bool unwind_on_error;
bool show_types;
bool show_summary;
diff --git a/source/Commands/CommandObjectFrame.cpp b/source/Commands/CommandObjectFrame.cpp
index 51299c2..bdcd703 100644
--- a/source/Commands/CommandObjectFrame.cpp
+++ b/source/Commands/CommandObjectFrame.cpp
@@ -310,6 +310,22 @@
switch (short_option)
{
case 'o': use_objc = true; break;
+ case 'd':
+ {
+ bool success;
+ bool result;
+ result = Args::StringToBoolean(option_arg, true, &success);
+ if (!success)
+ error.SetErrorStringWithFormat("Invalid dynamic value setting: \"%s\".\n", option_arg);
+ else
+ {
+ if (result)
+ use_dynamic = eLazyBoolYes;
+ else
+ use_dynamic = eLazyBoolNo;
+ }
+ }
+ break;
case 'r': use_regex = true; break;
case 'a': show_args = false; break;
case 'l': show_locals = false; break;
@@ -321,7 +337,7 @@
case 'D': debug = true; break;
case 'f': error = Args::StringToFormat(option_arg, format); break;
case 'F': flat_output = true; break;
- case 'd':
+ case 'A':
max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid max depth '%s'.\n", option_arg);
@@ -364,6 +380,7 @@
show_decl = false;
debug = false;
flat_output = false;
+ use_dynamic = eLazyBoolCalculate;
max_depth = UINT32_MAX;
ptr_depth = 0;
format = eFormatDefault;
@@ -391,6 +408,7 @@
show_decl:1,
debug:1,
flat_output:1;
+ LazyBool use_dynamic;
uint32_t max_depth; // The depth to print when dumping concrete (not pointers) aggreate values
uint32_t ptr_depth; // The default depth that is dumped when we find pointers
lldb::Format format; // The format to use when dumping variables or children of variables
@@ -461,7 +479,28 @@
VariableSP var_sp;
ValueObjectSP valobj_sp;
- //ValueObjectList &valobj_list = exe_ctx.frame->GetValueObjectList();
+
+ bool use_dynamic;
+
+ // If use dynamic is not set, get it from the target:
+ switch (m_options.use_dynamic)
+ {
+ case eLazyBoolCalculate:
+ {
+ if (exe_ctx.target->GetPreferDynamicValue())
+ use_dynamic = true;
+ else
+ use_dynamic = false;
+ }
+ break;
+ case eLazyBoolYes:
+ use_dynamic = true;
+ break;
+ case eLazyBoolNo:
+ use_dynamic = false;
+ break;
+ }
+
const char *name_cstr = NULL;
size_t idx;
if (!m_options.globals.empty())
@@ -473,12 +512,17 @@
for (idx = 0; idx < num_globals; ++idx)
{
VariableList global_var_list;
- const uint32_t num_matching_globals = exe_ctx.target->GetImages().FindGlobalVariables (m_options.globals[idx], true, UINT32_MAX, global_var_list);
+ const uint32_t num_matching_globals
+ = exe_ctx.target->GetImages().FindGlobalVariables (m_options.globals[idx],
+ true,
+ UINT32_MAX,
+ global_var_list);
if (num_matching_globals == 0)
{
++fail_count;
- result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", m_options.globals[idx].AsCString());
+ result.GetErrorStream().Printf ("error: can't find global variable '%s'\n",
+ m_options.globals[idx].AsCString());
}
else
{
@@ -487,9 +531,9 @@
var_sp = global_var_list.GetVariableAtIndex(global_idx);
if (var_sp)
{
- valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
+ valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (!valobj_sp)
- valobj_sp = exe_ctx.frame->TrackGlobalVariable (var_sp);
+ valobj_sp = exe_ctx.frame->TrackGlobalVariable (var_sp, use_dynamic);
if (valobj_sp)
{
@@ -501,7 +545,7 @@
var_sp->GetDeclaration ().DumpStopContext (&s, false);
s.PutCString (": ");
}
-
+
ValueObject::DumpValueObject (result.GetOutputStream(),
valobj_sp.get(),
name_cstr,
@@ -510,7 +554,8 @@
m_options.max_depth,
m_options.show_types,
m_options.show_location,
- m_options.use_objc,
+ m_options.use_objc,
+ use_dynamic,
false,
m_options.flat_output);
}
@@ -541,7 +586,9 @@
if (regex.Compile(name_cstr))
{
size_t num_matches = 0;
- const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, regex_var_list, num_matches);
+ const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
+ regex_var_list,
+ num_matches);
if (num_new_regex_vars > 0)
{
for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
@@ -551,9 +598,9 @@
var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
if (var_sp)
{
- valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
+ valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (valobj_sp)
- {
+ {
if (m_options.format != eFormatDefault)
valobj_sp->SetFormat (m_options.format);
@@ -571,7 +618,8 @@
m_options.max_depth,
m_options.show_types,
m_options.show_location,
- m_options.use_objc,
+ m_options.use_objc,
+ use_dynamic,
false,
m_options.flat_output);
}
@@ -595,10 +643,20 @@
else
{
Error error;
- const uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
+ uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
+ if (use_dynamic)
+ expr_path_options |= StackFrame::eExpressionPathOptionsDynamicValue;
+
valobj_sp = exe_ctx.frame->GetValueForVariableExpressionPath (name_cstr, expr_path_options, error);
if (valobj_sp)
{
+// if (use_dynamic)
+// {
+// lldb::ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(true, valobj_sp);
+// if (dynamic_sp != NULL)
+// valobj_sp = dynamic_sp;
+// }
+//
if (m_options.format != eFormatDefault)
valobj_sp->SetFormat (m_options.format);
@@ -615,7 +673,8 @@
m_options.max_depth,
m_options.show_types,
m_options.show_location,
- m_options.use_objc,
+ m_options.use_objc,
+ use_dynamic,
false,
m_options.flat_output);
}
@@ -639,6 +698,7 @@
for (uint32_t i=0; i<num_variables; i++)
{
var_sp = variable_list->GetVariableAtIndex(i);
+
bool dump_variable = true;
switch (var_sp->GetScope())
@@ -677,7 +737,7 @@
// Use the variable object code to make sure we are
// using the same APIs as the the public API will be
// using...
- valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
+ valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (valobj_sp)
{
if (m_options.format != eFormatDefault)
@@ -700,7 +760,8 @@
m_options.max_depth,
m_options.show_types,
m_options.show_location,
- m_options.use_objc,
+ m_options.use_objc,
+ use_dynamic,
false,
m_options.flat_output);
}
@@ -722,22 +783,23 @@
OptionDefinition
CommandObjectFrameVariable::CommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug information."},
-{ LLDB_OPT_SET_1, false, "depth", 'd', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
-{ LLDB_OPT_SET_1, false, "show-globals",'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
-{ LLDB_OPT_SET_1, false, "find-global",'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
-{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
-{ LLDB_OPT_SET_1, false, "show-declaration", 'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
-{ LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
-{ LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
-{ LLDB_OPT_SET_1, false, "show-types", 't', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
-{ LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
-{ LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
-{ LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, eArgTypeNone, "When looking up a variable by name, print as an Objective-C object."},
-{ LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
-{ LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
-{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
-{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the variable output should use."},
+{ LLDB_OPT_SET_1, false, "aggregate-depth", 'A', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
+{ LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
+{ LLDB_OPT_SET_1, false, "show-declaration",'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
+{ LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug information."},
+{ LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, NULL, 0, eArgTypeBoolean, "Show the object as its full dynamic type, not its static type, if available."},
+{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the variable output should use."},
+{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
+{ LLDB_OPT_SET_1, false, "show-globals", 'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
+{ LLDB_OPT_SET_1, false, "find-global", 'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
+{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
+{ LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
+{ LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, eArgTypeNone, "When looking up a variable by name, print as an Objective-C object."},
+{ LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
+{ LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
+{ LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
+{ LLDB_OPT_SET_1, false, "show-types", 't', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
+{ LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
{ 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
};
#pragma mark CommandObjectMultiwordFrame
diff --git a/source/Core/ValueObject.cpp b/source/Core/ValueObject.cpp
index eeb3ac0..d95806c 100644
--- a/source/Core/ValueObject.cpp
+++ b/source/Core/ValueObject.cpp
@@ -22,6 +22,7 @@
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObjectChild.h"
#include "lldb/Core/ValueObjectConstResult.h"
+#include "lldb/Core/ValueObjectDynamicValue.h"
#include "lldb/Core/ValueObjectList.h"
#include "lldb/Host/Endian.h"
@@ -159,15 +160,10 @@
return m_error.Success();
}
-const DataExtractor &
-ValueObject::GetDataExtractor () const
-{
- return m_data;
-}
-
DataExtractor &
ValueObject::GetDataExtractor ()
{
+ UpdateValueIfNeeded();
return m_data;
}
@@ -281,17 +277,20 @@
ValueObject::GetChildAtIndex (uint32_t idx, bool can_create)
{
ValueObjectSP child_sp;
- if (idx < GetNumChildren())
+ if (UpdateValueIfNeeded())
{
- // Check if we have already made the child value object?
- if (can_create && m_children[idx].get() == NULL)
+ if (idx < GetNumChildren())
{
- // No we haven't created the child at this index, so lets have our
- // subclass do it and cache the result for quick future access.
- m_children[idx] = CreateChildAtIndex (idx, false, 0);
- }
+ // Check if we have already made the child value object?
+ if (can_create && m_children[idx].get() == NULL)
+ {
+ // No we haven't created the child at this index, so lets have our
+ // subclass do it and cache the result for quick future access.
+ m_children[idx] = CreateChildAtIndex (idx, false, 0);
+ }
- child_sp = m_children[idx];
+ child_sp = m_children[idx];
+ }
}
return child_sp;
}
@@ -312,34 +311,38 @@
// when getting a child by name, it could be buried inside some base
// classes (which really aren't part of the expression path), so we
// need a vector of indexes that can get us down to the correct child
- std::vector<uint32_t> child_indexes;
- clang::ASTContext *clang_ast = GetClangAST();
- void *clang_type = GetClangType();
- bool omit_empty_base_classes = true;
- const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast,
- clang_type,
- name.GetCString(),
- omit_empty_base_classes,
- child_indexes);
ValueObjectSP child_sp;
- if (num_child_indexes > 0)
+
+ if (UpdateValueIfNeeded())
{
- std::vector<uint32_t>::const_iterator pos = child_indexes.begin ();
- std::vector<uint32_t>::const_iterator end = child_indexes.end ();
-
- child_sp = GetChildAtIndex(*pos, can_create);
- for (++pos; pos != end; ++pos)
+ std::vector<uint32_t> child_indexes;
+ clang::ASTContext *clang_ast = GetClangAST();
+ void *clang_type = GetClangType();
+ bool omit_empty_base_classes = true;
+ const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast,
+ clang_type,
+ name.GetCString(),
+ omit_empty_base_classes,
+ child_indexes);
+ if (num_child_indexes > 0)
{
- if (child_sp)
- {
- ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create));
- child_sp = new_child_sp;
- }
- else
- {
- child_sp.reset();
- }
+ std::vector<uint32_t>::const_iterator pos = child_indexes.begin ();
+ std::vector<uint32_t>::const_iterator end = child_indexes.end ();
+ child_sp = GetChildAtIndex(*pos, can_create);
+ for (++pos; pos != end; ++pos)
+ {
+ if (child_sp)
+ {
+ ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create));
+ child_sp = new_child_sp;
+ }
+ else
+ {
+ child_sp.reset();
+ }
+
+ }
}
}
return child_sp;
@@ -378,55 +381,60 @@
ValueObject::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index)
{
ValueObjectSP valobj_sp;
- bool omit_empty_base_classes = true;
-
- std::string child_name_str;
- uint32_t child_byte_size = 0;
- int32_t child_byte_offset = 0;
- uint32_t child_bitfield_bit_size = 0;
- uint32_t child_bitfield_bit_offset = 0;
- bool child_is_base_class = false;
- bool child_is_deref_of_parent = false;
-
- const bool transparent_pointers = synthetic_array_member == false;
- clang::ASTContext *clang_ast = GetClangAST();
- clang_type_t clang_type = GetClangType();
- clang_type_t child_clang_type;
- child_clang_type = ClangASTContext::GetChildClangTypeAtIndex (clang_ast,
- GetName().GetCString(),
- clang_type,
- idx,
- transparent_pointers,
- omit_empty_base_classes,
- child_name_str,
- child_byte_size,
- child_byte_offset,
- child_bitfield_bit_size,
- child_bitfield_bit_offset,
- child_is_base_class,
- child_is_deref_of_parent);
- if (child_clang_type && child_byte_size)
+
+ if (UpdateValueIfNeeded())
{
- if (synthetic_index)
- child_byte_offset += child_byte_size * synthetic_index;
+ bool omit_empty_base_classes = true;
- ConstString child_name;
- if (!child_name_str.empty())
- child_name.SetCString (child_name_str.c_str());
+ std::string child_name_str;
+ uint32_t child_byte_size = 0;
+ int32_t child_byte_offset = 0;
+ uint32_t child_bitfield_bit_size = 0;
+ uint32_t child_bitfield_bit_offset = 0;
+ bool child_is_base_class = false;
+ bool child_is_deref_of_parent = false;
- valobj_sp.reset (new ValueObjectChild (*this,
- clang_ast,
- child_clang_type,
- child_name,
- child_byte_size,
- child_byte_offset,
- child_bitfield_bit_size,
- child_bitfield_bit_offset,
- child_is_base_class,
- child_is_deref_of_parent));
- if (m_pointers_point_to_load_addrs)
- valobj_sp->SetPointersPointToLoadAddrs (m_pointers_point_to_load_addrs);
+ const bool transparent_pointers = synthetic_array_member == false;
+ clang::ASTContext *clang_ast = GetClangAST();
+ clang_type_t clang_type = GetClangType();
+ clang_type_t child_clang_type;
+ child_clang_type = ClangASTContext::GetChildClangTypeAtIndex (clang_ast,
+ GetName().GetCString(),
+ clang_type,
+ idx,
+ transparent_pointers,
+ omit_empty_base_classes,
+ child_name_str,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent);
+ if (child_clang_type && child_byte_size)
+ {
+ if (synthetic_index)
+ child_byte_offset += child_byte_size * synthetic_index;
+
+ ConstString child_name;
+ if (!child_name_str.empty())
+ child_name.SetCString (child_name_str.c_str());
+
+ valobj_sp.reset (new ValueObjectChild (*this,
+ clang_ast,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent));
+ if (m_pointers_point_to_load_addrs)
+ valobj_sp->SetPointersPointToLoadAddrs (m_pointers_point_to_load_addrs);
+ }
}
+
return valobj_sp;
}
@@ -710,6 +718,9 @@
addr_t
ValueObject::GetAddressOf (AddressType &address_type, bool scalar_is_load_address)
{
+ if (!UpdateValueIfNeeded())
+ return LLDB_INVALID_ADDRESS;
+
switch (m_value.GetValueType())
{
case Value::eValueTypeScalar:
@@ -738,6 +749,10 @@
{
lldb::addr_t address = LLDB_INVALID_ADDRESS;
address_type = eAddressTypeInvalid;
+
+ if (!UpdateValueIfNeeded())
+ return address;
+
switch (m_value.GetValueType())
{
case Value::eValueTypeScalar:
@@ -957,16 +972,66 @@
return synthetic_child_sp;
}
-bool
-ValueObject::SetDynamicValue ()
+void
+ValueObject::CalculateDynamicValue ()
{
- if (!IsPointerOrReferenceType())
- return false;
+ if (!m_dynamic_value_sp && !IsDynamic())
+ {
+ Process *process = m_update_point.GetProcess();
+ bool worth_having_dynamic_value = false;
- // Check that the runtime class is correct for determining the most specific class.
- // If it is a C++ class, see if it is dynamic:
-
- return true;
+
+ // FIXME: Process should have some kind of "map over Runtimes" so we don't have to
+ // hard code this everywhere.
+ lldb::LanguageType known_type = GetObjectRuntimeLanguage();
+ if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC)
+ {
+ LanguageRuntime *runtime = process->GetLanguageRuntime (known_type);
+ if (runtime)
+ worth_having_dynamic_value = runtime->CouldHaveDynamicValue(*this);
+ }
+ else
+ {
+ LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
+ if (cpp_runtime)
+ worth_having_dynamic_value = cpp_runtime->CouldHaveDynamicValue(*this);
+
+ if (!worth_having_dynamic_value)
+ {
+ LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
+ if (objc_runtime)
+ worth_having_dynamic_value = cpp_runtime->CouldHaveDynamicValue(*this);
+ }
+ }
+
+ if (worth_having_dynamic_value)
+ m_dynamic_value_sp.reset (new ValueObjectDynamicValue (*this));
+ }
+}
+
+lldb::ValueObjectSP
+ValueObject::GetDynamicValue (bool can_create)
+{
+ if (!IsDynamic() && m_dynamic_value_sp == NULL && can_create)
+ {
+ CalculateDynamicValue();
+ }
+ return m_dynamic_value_sp;
+}
+
+lldb::ValueObjectSP
+ValueObject::GetDynamicValue (bool can_create, lldb::ValueObjectSP &owning_valobj_sp)
+{
+ if (!IsDynamic() && m_dynamic_value_sp == NULL && can_create)
+ {
+ CalculateDynamicValue();
+ if (m_dynamic_value_sp)
+ {
+ ValueObjectDynamicValue *as_dynamic_value = static_cast<ValueObjectDynamicValue *>(m_dynamic_value_sp.get());
+ as_dynamic_value->SetOwningSP (owning_valobj_sp);
+ }
+ }
+ return m_dynamic_value_sp;
}
bool
@@ -974,7 +1039,7 @@
{
if (IsBaseClass())
{
- bool parent_had_base_class = m_parent && m_parent->GetBaseClassPath (s);
+ bool parent_had_base_class = GetParent() && GetParent()->GetBaseClassPath (s);
clang_type_t clang_type = GetClangType();
std::string cxx_class_name;
bool this_had_base_class = ClangASTContext::GetCXXClassName (clang_type, cxx_class_name);
@@ -993,12 +1058,12 @@
ValueObject *
ValueObject::GetNonBaseClassParent()
{
- if (m_parent)
+ if (GetParent())
{
- if (m_parent->IsBaseClass())
- return m_parent->GetNonBaseClassParent();
+ if (GetParent()->IsBaseClass())
+ return GetParent()->GetNonBaseClassParent();
else
- return m_parent;
+ return GetParent();
}
return NULL;
}
@@ -1011,8 +1076,8 @@
if (is_deref_of_parent)
s.PutCString("*(");
- if (m_parent)
- m_parent->GetExpressionPath (s, qualify_cxx_base_classes);
+ if (GetParent())
+ GetParent()->GetExpressionPath (s, qualify_cxx_base_classes);
if (!IsBaseClass())
{
@@ -1067,12 +1132,20 @@
bool show_types,
bool show_location,
bool use_objc,
+ bool use_dynamic,
bool scope_already_checked,
bool flat_output
)
{
if (valobj && valobj->UpdateValueIfNeeded ())
{
+ if (use_dynamic)
+ {
+ ValueObject *dynamic_value = valobj->GetDynamicValue(true).get();
+ if (dynamic_value)
+ valobj = dynamic_value;
+ }
+
clang_type_t clang_type = valobj->GetClangType();
const Flags type_flags (ClangASTContext::GetTypeInfo (clang_type, NULL, NULL));
@@ -1216,6 +1289,7 @@
show_types,
show_location,
false,
+ use_dynamic,
true,
flat_output);
}
@@ -1296,7 +1370,9 @@
lldb::ValueObjectSP
ValueObject::Dereference (Error &error)
{
- lldb::ValueObjectSP valobj_sp;
+ if (m_deref_valobj_sp)
+ return m_deref_valobj_sp;
+
const bool is_pointer_type = IsPointerType();
if (is_pointer_type)
{
@@ -1332,20 +1408,20 @@
if (!child_name_str.empty())
child_name.SetCString (child_name_str.c_str());
- valobj_sp.reset (new ValueObjectChild (*this,
- clang_ast,
- child_clang_type,
- child_name,
- child_byte_size,
- child_byte_offset,
- child_bitfield_bit_size,
- child_bitfield_bit_offset,
- child_is_base_class,
- child_is_deref_of_parent));
+ m_deref_valobj_sp.reset (new ValueObjectChild (*this,
+ clang_ast,
+ child_clang_type,
+ child_name,
+ child_byte_size,
+ child_byte_offset,
+ child_bitfield_bit_size,
+ child_bitfield_bit_offset,
+ child_is_base_class,
+ child_is_deref_of_parent));
}
}
- if (valobj_sp)
+ if (m_deref_valobj_sp)
{
error.Clear();
}
@@ -1360,13 +1436,15 @@
error.SetErrorStringWithFormat("not a pointer type: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str());
}
- return valobj_sp;
+ return m_deref_valobj_sp;
}
- lldb::ValueObjectSP
+lldb::ValueObjectSP
ValueObject::AddressOf (Error &error)
{
- lldb::ValueObjectSP valobj_sp;
+ if (m_addr_of_valobj_sp)
+ return m_addr_of_valobj_sp;
+
AddressType address_type = eAddressTypeInvalid;
const bool scalar_is_load_address = false;
lldb::addr_t addr = GetAddressOf (address_type, scalar_is_load_address);
@@ -1394,19 +1472,19 @@
{
std::string name (1, '&');
name.append (m_name.AsCString(""));
- valobj_sp.reset (new ValueObjectConstResult (GetExecutionContextScope(),
- ast,
- ClangASTContext::CreatePointerType (ast, clang_type),
- ConstString (name.c_str()),
- addr,
- eAddressTypeInvalid,
- m_data.GetAddressByteSize()));
+ m_addr_of_valobj_sp.reset (new ValueObjectConstResult (GetExecutionContextScope(),
+ ast,
+ ClangASTContext::CreatePointerType (ast, clang_type),
+ ConstString (name.c_str()),
+ addr,
+ eAddressTypeInvalid,
+ m_data.GetAddressByteSize()));
}
}
break;
}
}
- return valobj_sp;
+ return m_addr_of_valobj_sp;
}
ValueObject::EvaluationPoint::EvaluationPoint () :
@@ -1523,10 +1601,16 @@
return false;
// If our stop id is the current stop ID, nothing has changed:
- if (m_stop_id == m_process_sp->GetStopID())
+ uint32_t cur_stop_id = m_process_sp->GetStopID();
+ if (m_stop_id == cur_stop_id)
return false;
- m_stop_id = m_process_sp->GetStopID();
+ // If the current stop id is 0, either we haven't run yet, or the process state has been cleared.
+ // In either case, we aren't going to be able to sync with the process state.
+ if (cur_stop_id == 0)
+ return false;
+
+ m_stop_id = cur_stop_id;
m_needs_update = true;
m_exe_scope = m_process_sp.get();
diff --git a/source/Core/ValueObjectChild.cpp b/source/Core/ValueObjectChild.cpp
index fc5f6c8..509852f 100644
--- a/source/Core/ValueObjectChild.cpp
+++ b/source/Core/ValueObjectChild.cpp
@@ -97,7 +97,7 @@
ValueObject* parent = m_parent;
if (parent)
{
- if (parent->UpdateValue())
+ if (parent->UpdateValueIfNeeded())
{
m_value.SetContext(Value::eContextTypeClangType, m_clang_type);
diff --git a/source/Core/ValueObjectDynamicValue.cpp b/source/Core/ValueObjectDynamicValue.cpp
new file mode 100644
index 0000000..2b80ae5
--- /dev/null
+++ b/source/Core/ValueObjectDynamicValue.cpp
@@ -0,0 +1,254 @@
+//===-- ValueObjectDynamicValue.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/ValueObjectDynamicValue.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/LanguageRuntime.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb_private;
+
+ValueObjectDynamicValue::ValueObjectDynamicValue (ValueObject &parent) :
+ ValueObject(parent),
+ m_address (),
+ m_type_sp()
+{
+ // THINK ABOUT: It looks ugly to doctor up the name like this. But if
+ // people find it confusing to tell the difference, we may want to do something...
+
+// std::string dynamic_name ("<dynamic value for \"");
+// dynamic_name.append(parent.GetName().AsCString());
+// dynamic_name.append("\">");
+//
+// SetName (dynamic_name.c_str());
+ SetName (parent.GetName().AsCString());
+}
+
+ValueObjectDynamicValue::~ValueObjectDynamicValue()
+{
+ m_owning_valobj_sp.reset();
+}
+
+lldb::clang_type_t
+ValueObjectDynamicValue::GetClangType ()
+{
+ if (m_type_sp)
+ return m_value.GetClangType();
+ else
+ return m_parent->GetClangType();
+}
+
+ConstString
+ValueObjectDynamicValue::GetTypeName()
+{
+ // FIXME: Maybe cache the name, but have to clear it out if the type changes...
+ if (!UpdateValueIfNeeded())
+ return ConstString("<unknown type>");
+
+ if (m_type_sp)
+ return ClangASTType::GetClangTypeName (GetClangType());
+ else
+ return m_parent->GetTypeName();
+}
+
+uint32_t
+ValueObjectDynamicValue::CalculateNumChildren()
+{
+ if (!UpdateValueIfNeeded())
+ return 0;
+
+ if (m_type_sp)
+ return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true);
+ else
+ return m_parent->GetNumChildren();
+}
+
+clang::ASTContext *
+ValueObjectDynamicValue::GetClangAST ()
+{
+ if (!UpdateValueIfNeeded())
+ return NULL;
+
+ if (m_type_sp)
+ return m_type_sp->GetClangAST();
+ else
+ return m_parent->GetClangAST ();
+}
+
+size_t
+ValueObjectDynamicValue::GetByteSize()
+{
+ if (!UpdateValueIfNeeded())
+ return 0;
+
+ if (m_type_sp)
+ return m_value.GetValueByteSize(GetClangAST(), NULL);
+ else
+ return m_parent->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectDynamicValue::GetValueType() const
+{
+ return m_parent->GetValueType();
+}
+
+bool
+ValueObjectDynamicValue::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ if (!m_parent->UpdateValueIfNeeded())
+ {
+ return false;
+ }
+
+ ExecutionContext exe_ctx (GetExecutionContextScope());
+
+ if (exe_ctx.target)
+ {
+ m_data.SetByteOrder(exe_ctx.target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(exe_ctx.target->GetArchitecture().GetAddressByteSize());
+ }
+
+ // First make sure our Type and/or Address haven't changed:
+ Process *process = m_update_point.GetProcess();
+ if (!process)
+ return false;
+
+ lldb::TypeSP dynamic_type_sp;
+ Address dynamic_address;
+ bool found_dynamic_type = false;
+
+ lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
+ if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC)
+ {
+ LanguageRuntime *runtime = process->GetLanguageRuntime (known_type);
+ if (runtime)
+ found_dynamic_type = runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
+ }
+ else
+ {
+ LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
+ if (cpp_runtime)
+ found_dynamic_type = cpp_runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
+
+ if (!found_dynamic_type)
+ {
+ LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
+ if (objc_runtime)
+ found_dynamic_type = cpp_runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
+ }
+ }
+
+ // If we don't have a dynamic type, then make ourselves just a echo of our parent.
+ // Or we could return false, and make ourselves an echo of our parent?
+ if (!found_dynamic_type)
+ {
+ if (m_type_sp)
+ SetValueDidChange(true);
+ m_value = m_parent->GetValue();
+ m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0);
+ return m_error.Success();
+ }
+
+ Value old_value(m_value);
+
+ if (!m_type_sp)
+ {
+ m_type_sp = dynamic_type_sp;
+ }
+ else if (dynamic_type_sp != m_type_sp)
+ {
+ // We are another type, we need to tear down our children...
+ m_type_sp = dynamic_type_sp;
+ SetValueDidChange (true);
+ }
+
+ if (!m_address.IsValid() || m_address != dynamic_address)
+ {
+ if (m_address.IsValid())
+ SetValueDidChange (true);
+
+ // We've moved, so we should be fine...
+ m_address = dynamic_address;
+ lldb::addr_t load_address = m_address.GetLoadAddress(m_update_point.GetTarget());
+ m_value.GetScalar() = load_address;
+ }
+
+ // The type will always be the type of the dynamic object. If our parent's type was a pointer,
+ // then our type should be a pointer to the type of the dynamic object. If a reference, then the original type
+ // should be okay...
+ lldb::clang_type_t orig_type = m_type_sp->GetClangForwardType();
+ lldb::clang_type_t corrected_type = orig_type;
+ if (m_parent->IsPointerType())
+ corrected_type = ClangASTContext::CreatePointerType (m_type_sp->GetClangAST(), orig_type);
+ else if (m_parent->IsPointerOrReferenceType())
+ corrected_type = ClangASTContext::CreateLValueReferenceType (m_type_sp->GetClangAST(), orig_type);
+
+ m_value.SetContext (Value::eContextTypeClangType, corrected_type);
+
+ // Our address is the location of the dynamic type stored in memory. It isn't a load address,
+ // because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us...
+ m_value.SetValueType(Value::eValueTypeScalar);
+
+ if (m_address.IsValid() && m_type_sp)
+ {
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0);
+ if (m_error.Success())
+ {
+ if (ClangASTContext::IsAggregateType (GetClangType()))
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+
+ SetValueIsValid (true);
+ return true;
+ }
+ }
+
+ // We get here if we've failed above...
+ SetValueIsValid (false);
+ return false;
+}
+
+
+
+bool
+ValueObjectDynamicValue::IsInScope ()
+{
+ return m_parent->IsInScope();
+}
+
diff --git a/source/Core/ValueObjectMemory.cpp b/source/Core/ValueObjectMemory.cpp
new file mode 100644
index 0000000..d399848
--- /dev/null
+++ b/source/Core/ValueObjectMemory.cpp
@@ -0,0 +1,196 @@
+//===-- ValueObjectMemory.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/ValueObjectMemory.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Module.h"
+#include "lldb/Core/ValueObjectList.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Core/ValueObject.h"
+
+#include "lldb/Symbol/ObjectFile.h"
+#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Symbol/Type.h"
+#include "lldb/Symbol/Variable.h"
+
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/Thread.h"
+
+
+using namespace lldb_private;
+
+ValueObjectMemory::ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp) :
+ ValueObject(exe_scope),
+ m_address (address),
+ m_type_sp(type_sp)
+{
+ // Do not attempt to construct one of these objects with no variable!
+ assert (m_type_sp.get() != NULL);
+ SetName (name);
+ m_value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
+ lldb::addr_t load_address = m_address.GetLoadAddress(m_update_point.GetTarget());
+ if (load_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_address;
+ }
+ else
+ {
+ lldb::addr_t file_address = m_address.GetFileAddress();
+ if (file_address != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeFileAddress);
+ m_value.GetScalar() = file_address;
+ }
+ else
+ {
+ m_value.GetScalar() = m_address.GetOffset();
+ m_value.SetValueType (Value::eValueTypeScalar);
+ }
+ }
+}
+
+ValueObjectMemory::~ValueObjectMemory()
+{
+}
+
+lldb::clang_type_t
+ValueObjectMemory::GetClangType ()
+{
+ return m_type_sp->GetClangForwardType();
+}
+
+ConstString
+ValueObjectMemory::GetTypeName()
+{
+ return m_type_sp->GetName();
+}
+
+uint32_t
+ValueObjectMemory::CalculateNumChildren()
+{
+ return m_type_sp->GetNumChildren(true);
+}
+
+clang::ASTContext *
+ValueObjectMemory::GetClangAST ()
+{
+ return m_type_sp->GetClangAST();
+}
+
+size_t
+ValueObjectMemory::GetByteSize()
+{
+ return m_type_sp->GetByteSize();
+}
+
+lldb::ValueType
+ValueObjectMemory::GetValueType() const
+{
+ // RETHINK: Should this be inherited from somewhere?
+ return lldb::eValueTypeVariableGlobal;
+}
+
+bool
+ValueObjectMemory::UpdateValue ()
+{
+ SetValueIsValid (false);
+ m_error.Clear();
+
+ ExecutionContext exe_ctx (GetExecutionContextScope());
+
+ if (exe_ctx.target)
+ {
+ m_data.SetByteOrder(exe_ctx.target->GetArchitecture().GetByteOrder());
+ m_data.SetAddressByteSize(exe_ctx.target->GetArchitecture().GetAddressByteSize());
+ }
+
+ Value old_value(m_value);
+ if (m_address.IsValid())
+ {
+ Value::ValueType value_type = m_value.GetValueType();
+
+ switch (value_type)
+ {
+ default:
+ assert(!"Unhandled expression result value kind...");
+ break;
+
+ case Value::eValueTypeScalar:
+ // The variable value is in the Scalar value inside the m_value.
+ // We can point our m_data right to it.
+ m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0);
+ break;
+
+ case Value::eValueTypeFileAddress:
+ case Value::eValueTypeLoadAddress:
+ case Value::eValueTypeHostAddress:
+ // The DWARF expression result was an address in the inferior
+ // process. If this variable is an aggregate type, we just need
+ // the address as the main value as all child variable objects
+ // will rely upon this location and add an offset and then read
+ // their own values as needed. If this variable is a simple
+ // type, we read all data for it into m_data.
+ // Make sure this type has a value before we try and read it
+
+ // If we have a file address, convert it to a load address if we can.
+ if (value_type == Value::eValueTypeFileAddress && exe_ctx.process)
+ {
+ lldb::addr_t load_addr = m_address.GetLoadAddress(exe_ctx.target);
+ if (load_addr != LLDB_INVALID_ADDRESS)
+ {
+ m_value.SetValueType(Value::eValueTypeLoadAddress);
+ m_value.GetScalar() = load_addr;
+ }
+ }
+
+ if (ClangASTContext::IsAggregateType (GetClangType()))
+ {
+ // this value object represents an aggregate type whose
+ // children have values, but this object does not. So we
+ // say we are changed if our location has changed.
+ SetValueDidChange (value_type != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
+ }
+ else
+ {
+ // Copy the Value and set the context to use our Variable
+ // so it can extract read its value into m_data appropriately
+ Value value(m_value);
+ value.SetContext(Value::eContextTypeLLDBType, m_type_sp.get());
+ m_error = value.GetValueAsData(&exe_ctx, GetClangAST(), m_data, 0);
+ }
+ break;
+ }
+
+ SetValueIsValid (m_error.Success());
+ }
+ return m_error.Success();
+}
+
+
+
+bool
+ValueObjectMemory::IsInScope ()
+{
+ // FIXME: Maybe try to read the memory address, and if that works, then
+ // we are in scope?
+ return true;
+}
+
diff --git a/source/Expression/ClangExpressionDeclMap.cpp b/source/Expression/ClangExpressionDeclMap.cpp
index 99f0e60..0054a03 100644
--- a/source/Expression/ClangExpressionDeclMap.cpp
+++ b/source/Expression/ClangExpressionDeclMap.cpp
@@ -848,7 +848,6 @@
// with with a '$' character...
if (member_sp->GetName().AsCString ("!")[0] == '$' && persistent_vars.ContainsVariable(member_sp))
{
- bool keep_this_in_memory = false;
if (member_sp->GetName() == m_struct_vars->m_result_name)
{
@@ -858,7 +857,6 @@
if (result_sp_ptr)
*result_sp_ptr = member_sp;
- keep_this_in_memory = m_keep_result_in_memory;
}
if (!DoMaterializeOnePersistentVariable (dematerialize,
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index b0f7733..fb4c98d 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -15,6 +15,8 @@
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Scalar.h"
+#include "lldb/Core/ValueObject.h"
+#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -30,12 +32,134 @@
static const char *pluginName = "ItaniumABILanguageRuntime";
static const char *pluginDesc = "Itanium ABI for the C++ language";
static const char *pluginShort = "language.itanium";
+static const char *vtable_demangled_prefix = "vtable for ";
-lldb::ValueObjectSP
-ItaniumABILanguageRuntime::GetDynamicValue (ValueObjectSP in_value)
+bool
+ItaniumABILanguageRuntime::CouldHaveDynamicValue (ValueObject &in_value)
{
- ValueObjectSP ret_sp;
- return ret_sp;
+ return in_value.IsPointerOrReferenceType();
+}
+
+bool
+ItaniumABILanguageRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &dynamic_type_sp, Address &dynamic_address)
+{
+ // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0
+ // in the object. That will point to the "address point" within the vtable (not the beginning of the
+ // vtable.) We can then look up the symbol containing this "address point" and that symbol's name
+ // demangled will contain the full class name.
+ // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the
+ // start of the value object which holds the dynamic type.
+ //
+
+ // Only a pointer or reference type can have a different dynamic and static type:
+ if (CouldHaveDynamicValue (in_value))
+ {
+ // FIXME: Can we get the Clang Type and ask it if the thing is really virtual? That would avoid false positives,
+ // at the cost of not looking for the dynamic type of objects if DWARF->Clang gets it wrong.
+
+ // First job, pull out the address at 0 offset from the object.
+ AddressType address_type;
+ lldb::addr_t original_ptr = in_value.GetPointerValue(address_type, true);
+ if (original_ptr == LLDB_INVALID_ADDRESS)
+ return false;
+
+ Target *target = in_value.GetUpdatePoint().GetTarget();
+ Process *process = in_value.GetUpdatePoint().GetProcess();
+
+ char memory_buffer[16];
+ DataExtractor data(memory_buffer, sizeof(memory_buffer),
+ process->GetByteOrder(),
+ process->GetAddressByteSize());
+ size_t address_byte_size = process->GetAddressByteSize();
+ Error error;
+ size_t bytes_read = process->ReadMemory (original_ptr,
+ memory_buffer,
+ address_byte_size,
+ error);
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ uint32_t offset_ptr = 0;
+ lldb::addr_t vtable_address_point = data.GetAddress (&offset_ptr);
+
+ if (offset_ptr == 0)
+ return false;
+
+ // Now find the symbol that contains this address:
+
+ SymbolContext sc;
+ Address address_point_address;
+ if (target && !target->GetSectionLoadList().IsEmpty())
+ {
+ if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address))
+ {
+ target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc);
+ Symbol *symbol = sc.symbol;
+ if (symbol != NULL)
+ {
+ const char *name = symbol->GetMangled().GetDemangledName().AsCString();
+ if (strstr(name, vtable_demangled_prefix) == name)
+ {
+ // We are a C++ class, that's good. Get the class name and look it up:
+ const char *class_name = name + strlen(vtable_demangled_prefix);
+ TypeList class_types;
+ uint32_t num_matches = target->GetImages().FindTypes (sc,
+ ConstString(class_name),
+ true,
+ UINT32_MAX,
+ class_types);
+ if (num_matches == 1)
+ {
+ dynamic_type_sp = class_types.GetTypeAtIndex(0);
+ }
+ else if (num_matches > 1)
+ {
+ // How to sort out which of the type matches to pick?
+ }
+
+ if (!dynamic_type_sp)
+ return false;
+
+ // The offset_to_top is two pointers above the address.
+ Address offset_to_top_address = address_point_address;
+ int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize());
+ offset_to_top_address.Slide (slide);
+
+ Error error;
+ lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target);
+
+ size_t bytes_read = process->ReadMemory (offset_to_top_location,
+ memory_buffer,
+ address_byte_size,
+ error);
+
+ if (!error.Success() || (bytes_read != address_byte_size))
+ {
+ return false;
+ }
+
+ offset_ptr = 0;
+ int64_t offset_to_top = data.GetMaxS64(&offset_ptr, process->GetAddressByteSize());
+
+ // So the dynamic type is a value that starts at offset_to_top
+ // above the original address.
+ lldb::addr_t dynamic_addr = original_ptr + offset_to_top;
+ if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address))
+ {
+ dynamic_address.SetOffset(dynamic_addr);
+ dynamic_address.SetSection(NULL);
+ }
+ return true;
+ }
+ }
+ }
+ }
+
+ }
+
+ return false;
}
bool
diff --git a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
index d7ac04a..421ac12 100644
--- a/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
+++ b/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -30,9 +30,12 @@
virtual bool
IsVTableName (const char *name);
- virtual lldb::ValueObjectSP
- GetDynamicValue (lldb::ValueObjectSP in_value);
-
+ virtual bool
+ GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
+
+ virtual bool
+ CouldHaveDynamicValue (ValueObject &in_value);
+
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index 392abee..08af0b6 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -191,11 +191,16 @@
return m_PrintForDebugger_addr.get();
}
-lldb::ValueObjectSP
-AppleObjCRuntime::GetDynamicValue (lldb::ValueObjectSP in_value)
+bool
+AppleObjCRuntime::CouldHaveDynamicValue (ValueObject &in_value)
{
- lldb::ValueObjectSP ret_sp;
- return ret_sp;
+ return in_value.IsPointerType();
+}
+
+bool
+AppleObjCRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
+{
+ return false;
}
bool
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
index 1c500e3..e7e0f71 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -37,8 +37,11 @@
virtual bool
GetObjectDescription (Stream &str, ValueObject &object);
- virtual lldb::ValueObjectSP
- GetDynamicValue (lldb::ValueObjectSP in_value);
+ virtual bool
+ CouldHaveDynamicValue (ValueObject &in_value);
+
+ virtual bool
+ GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
// These are the ObjC specific functions.
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 4674757..000f14e 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -40,11 +40,10 @@
static const char *pluginDesc = "Apple Objective C Language Runtime - Version 1";
static const char *pluginShort = "language.apple.objc.v1";
-lldb::ValueObjectSP
-AppleObjCRuntimeV1::GetDynamicValue (lldb::ValueObjectSP in_value)
+bool
+AppleObjCRuntimeV1::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
{
- lldb::ValueObjectSP ret_sp;
- return ret_sp;
+ return false;
}
//------------------------------------------------------------------
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
index 2b815b1..975c018 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
@@ -31,8 +31,8 @@
~AppleObjCRuntimeV1() { }
// These are generic runtime functions:
- virtual lldb::ValueObjectSP
- GetDynamicValue (lldb::ValueObjectSP in_value);
+ virtual bool
+ GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
virtual ClangUtilityFunction *
CreateObjectChecker (const char *);
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 5d276dc..c6e3533 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -46,11 +46,10 @@
m_has_object_getClass = (objc_module_sp->FindFirstSymbolWithNameAndType(ConstString("gdb_object_getClass")) != NULL);
}
-lldb::ValueObjectSP
-AppleObjCRuntimeV2::GetDynamicValue (lldb::ValueObjectSP in_value)
+bool
+AppleObjCRuntimeV2::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
{
- lldb::ValueObjectSP ret_sp;
- return ret_sp;
+ return false;
}
//------------------------------------------------------------------
diff --git a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index d2bd414..0015dd2 100644
--- a/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -31,8 +31,8 @@
~AppleObjCRuntimeV2() { }
// These are generic runtime functions:
- virtual lldb::ValueObjectSP
- GetDynamicValue (lldb::ValueObjectSP in_value);
+ virtual bool
+ GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
virtual ClangUtilityFunction *
CreateObjectChecker (const char *);
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 26d84b9..a492e47 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -1902,6 +1902,12 @@
if (buf == NULL || size == 0)
return 0;
+
+ // Need to bump the stop ID after writing so that ValueObjects will know to re-read themselves.
+ // FUTURE: Doing this should be okay, but if anybody else gets upset about the stop_id changing when
+ // the target hasn't run, then we will need to add a "memory generation" as well as a stop_id...
+ m_stop_id++;
+
// We need to write any data that would go where any current software traps
// (enabled software breakpoints) any software traps (breakpoints) that we
// may have placed in our tasks memory.
@@ -1962,7 +1968,7 @@
ubuf + bytes_written,
size - bytes_written,
error);
-
+
return bytes_written;
}
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index 0d0c0e8..a5df928 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -493,6 +493,7 @@
{
const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0;
const bool no_fragile_ivar = (options & eExpressionPathOptionsNoFragileObjcIvar) != 0;
+ const bool dynamic_value = (options & eExpressionPathOptionsDynamicValue) != 0;
error.Clear();
bool deref = false;
bool address_of = false;
@@ -528,8 +529,10 @@
VariableSP var_sp (variable_list->FindVariable(name_const_string));
if (var_sp)
{
- valobj_sp = GetValueObjectForFrameVariable (var_sp);
-
+ valobj_sp = GetValueObjectForFrameVariable (var_sp, dynamic_value);
+ if (!valobj_sp)
+ return valobj_sp;
+
var_path.erase (0, name_const_string.GetLength ());
// We are dumping at least one child
while (separator_idx != std::string::npos)
@@ -600,7 +603,6 @@
return ValueObjectSP();
}
}
-
child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
if (!child_valobj_sp)
{
@@ -624,6 +626,12 @@
}
// Remove the child name from the path
var_path.erase(0, child_name.GetLength());
+ if (dynamic_value)
+ {
+ ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(true, child_valobj_sp));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
+ }
}
break;
@@ -650,6 +658,8 @@
}
else if (ClangASTContext::IsArrayType (valobj_sp->GetClangType(), NULL, NULL))
{
+ // Pass false to dynamic_value here so we can tell the difference between
+ // no dynamic value and no member of this type...
child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true);
if (!child_valobj_sp)
{
@@ -678,7 +688,12 @@
// %i is the array index
var_path.erase(0, (end - var_path.c_str()) + 1);
separator_idx = var_path.find_first_of(".-[");
-
+ if (dynamic_value)
+ {
+ ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(true, child_valobj_sp));
+ 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;
@@ -794,7 +809,7 @@
ValueObjectSP
-StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp)
+StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, bool use_dynamic)
{
ValueObjectSP valobj_sp;
VariableList *var_list = GetVariableList (true);
@@ -815,14 +830,20 @@
}
}
}
+ if (use_dynamic && valobj_sp)
+ {
+ ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue (true, valobj_sp);
+ if (dynamic_sp)
+ return dynamic_sp;
+ }
return valobj_sp;
}
ValueObjectSP
-StackFrame::TrackGlobalVariable (const VariableSP &variable_sp)
+StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, bool use_dynamic)
{
// Check to make sure we aren't already tracking this variable?
- ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp));
+ ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp, use_dynamic));
if (!valobj_sp)
{
// We aren't already tracking this global
@@ -835,7 +856,7 @@
m_variable_list_sp->AddVariable (variable_sp);
// Now make a value object for it so we can track its changes
- valobj_sp = GetValueObjectForFrameVariable (variable_sp);
+ valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic);
}
return valobj_sp;
}
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index 2ade9e6..d08a0fe 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -887,6 +887,7 @@
StackFrame *frame,
bool unwind_on_error,
bool keep_in_memory,
+ bool fetch_dynamic_value,
lldb::ValueObjectSP &result_valobj_sp
)
{
@@ -927,7 +928,16 @@
const_valobj_sp->SetName (persistent_variable_name);
}
else
+ {
+ if (fetch_dynamic_value)
+ {
+ ValueObjectSP dynamic_sp = result_valobj_sp->GetDynamicValue(true, result_valobj_sp);
+ if (dynamic_sp)
+ result_valobj_sp = dynamic_sp;
+ }
+
const_valobj_sp = result_valobj_sp->CreateConstantValue (persistent_variable_name);
+ }
lldb::ValueObjectSP live_valobj_sp = result_valobj_sp;
@@ -1277,11 +1287,12 @@
}
-#define TSC_DEFAULT_ARCH "default-arch"
-#define TSC_EXPR_PREFIX "expr-prefix"
-#define TSC_EXEC_LEVEL "execution-level"
-#define TSC_EXEC_MODE "execution-mode"
-#define TSC_EXEC_OS_TYPE "execution-os-type"
+#define TSC_DEFAULT_ARCH "default-arch"
+#define TSC_EXPR_PREFIX "expr-prefix"
+#define TSC_EXEC_LEVEL "execution-level"
+#define TSC_EXEC_MODE "execution-mode"
+#define TSC_EXEC_OS_TYPE "execution-os-type"
+#define TSC_PREFER_DYNAMIC "prefer-dynamic-value"
static const ConstString &
@@ -1320,6 +1331,13 @@
return g_const_string;
}
+static const ConstString &
+GetSettingNameForPreferDynamicValue ()
+{
+ static ConstString g_const_string (TSC_PREFER_DYNAMIC);
+ return g_const_string;
+}
+
bool
Target::SettingsController::SetGlobalVariable (const ConstString &var_name,
@@ -1369,7 +1387,8 @@
) :
InstanceSettings (owner, name ? name : InstanceSettings::InvalidName().AsCString(), live_instance),
m_expr_prefix_path (),
- m_expr_prefix_contents ()
+ m_expr_prefix_contents (),
+ m_prefer_dynamic_value (true)
{
// CopyInstanceSettings is a pure virtual function in InstanceSettings; it therefore cannot be called
// until the vtables for TargetInstanceSettings are properly set up, i.e. AFTER all the initializers.
@@ -1467,6 +1486,39 @@
return;
}
}
+ else if (var_name == GetSettingNameForPreferDynamicValue())
+ {
+ switch (op)
+ {
+ default:
+ err.SetErrorToGenericError ();
+ err.SetErrorString ("Unrecognized operation. Cannot update value.\n");
+ return;
+ case eVarSetOperationAssign:
+ {
+ bool success;
+ bool result = Args::StringToBoolean(value, false, &success);
+
+ if (success)
+ {
+ m_prefer_dynamic_value = result;
+ }
+ else
+ {
+ err.SetErrorStringWithFormat ("Bad value \"%s\" for %s, should be Boolean.",
+ value,
+ GetSettingNameForPreferDynamicValue().AsCString());
+ }
+ return;
+ }
+ case eVarSetOperationClear:
+ m_prefer_dynamic_value = true;
+ case eVarSetOperationAppend:
+ err.SetErrorToGenericError ();
+ err.SetErrorString ("Cannot append to a bool.\n");
+ return;
+ }
+ }
}
void
@@ -1479,6 +1531,7 @@
m_expr_prefix_path = new_settings_ptr->m_expr_prefix_path;
m_expr_prefix_contents = new_settings_ptr->m_expr_prefix_contents;
+ m_prefer_dynamic_value = new_settings_ptr->m_prefer_dynamic_value;
}
bool
@@ -1491,6 +1544,13 @@
{
value.AppendString (m_expr_prefix_path.c_str(), m_expr_prefix_path.size());
}
+ else if (var_name == GetSettingNameForPreferDynamicValue())
+ {
+ if (m_prefer_dynamic_value)
+ value.AppendString ("true");
+ else
+ value.AppendString ("false");
+ }
else
{
if (err)
@@ -1533,5 +1593,6 @@
// var-name var-type default enum init'd hidden help-text
// ================= ================== =========== ==== ====== ====== =========================================================================
{ TSC_EXPR_PREFIX , eSetVarTypeString , NULL , NULL, false, false, "Path to a file containing expressions to be prepended to all expressions." },
+ { TSC_PREFER_DYNAMIC, eSetVarTypeBoolean ,"true" , NULL, false, false, "Should printed values be shown as their dynamic value." },
{ NULL , eSetVarTypeNone , NULL , NULL, false, false, NULL }
};
diff --git a/source/Target/ThreadPlanTestCondition.cpp b/source/Target/ThreadPlanTestCondition.cpp
index 9facfdc..1349e9e 100644
--- a/source/Target/ThreadPlanTestCondition.cpp
+++ b/source/Target/ThreadPlanTestCondition.cpp
@@ -84,8 +84,8 @@
if (result_sp)
{
// FIXME: This is not the right answer, we should have a "GetValueAsBoolean..."
- Scalar scalar_value = result_sp->GetValue().ResolveValue (&m_exe_ctx, result_sp->GetClangAST());
- if (scalar_value.IsValid())
+ Scalar scalar_value;
+ if (result_sp->ResolveValue (scalar_value))
{
if (scalar_value.ULongLong(1) == 0)
m_did_stop = false;