summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/API/SBFrame.h21
-rw-r--r--lldb/include/lldb/API/SBValue.h8
-rw-r--r--lldb/include/lldb/Core/ValueObject.h42
-rw-r--r--lldb/include/lldb/Core/ValueObjectConstResult.h6
-rw-r--r--lldb/include/lldb/Core/ValueObjectDynamicValue.h105
-rw-r--r--lldb/include/lldb/Core/ValueObjectMemory.h73
-rw-r--r--lldb/include/lldb/Target/LanguageRuntime.h9
-rw-r--r--lldb/include/lldb/Target/StackFrame.h7
-rw-r--r--lldb/include/lldb/Target/Target.h8
-rw-r--r--lldb/lldb.xcodeproj/project.pbxproj22
-rw-r--r--lldb/source/API/SBFrame.cpp54
-rw-r--r--lldb/source/API/SBValue.cpp34
-rw-r--r--lldb/source/Commands/CommandObjectExpression.cpp41
-rw-r--r--lldb/source/Commands/CommandObjectExpression.h1
-rw-r--r--lldb/source/Commands/CommandObjectFrame.cpp126
-rw-r--r--lldb/source/Core/ValueObject.cpp332
-rw-r--r--lldb/source/Core/ValueObjectChild.cpp2
-rw-r--r--lldb/source/Core/ValueObjectDynamicValue.cpp254
-rw-r--r--lldb/source/Core/ValueObjectMemory.cpp196
-rw-r--r--lldb/source/Expression/ClangExpressionDeclMap.cpp2
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp132
-rw-r--r--lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h9
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp13
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h7
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp7
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h4
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp7
-rw-r--r--lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h4
-rw-r--r--lldb/source/Target/Process.cpp8
-rw-r--r--lldb/source/Target/StackFrame.cpp37
-rw-r--r--lldb/source/Target/Target.cpp73
-rw-r--r--lldb/source/Target/ThreadPlanTestCondition.cpp4
-rw-r--r--lldb/test/cpp/dynamic-value/Makefile5
-rw-r--r--lldb/test/cpp/dynamic-value/TestDynamicValue.py226
-rw-r--r--lldb/test/cpp/dynamic-value/pass-to-base.cpp62
-rw-r--r--lldb/test/lldbutil.py27
-rw-r--r--lldb/test/python_api/process/TestProcessAPI.py8
-rw-r--r--lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj3
38 files changed, 1740 insertions, 239 deletions
diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h
index acbbcba49ea..d3222e4c325 100644
--- a/lldb/include/lldb/API/SBFrame.h
+++ b/lldb/include/lldb/API/SBFrame.h
@@ -71,8 +71,12 @@ public:
lldb::SBBlock
GetBlock () const;
+ // The version that doesn't supply a "use_dynamic" value will use the target's default.
lldb::SBValue
- EvaluateExpression (const char *expr);
+ EvaluateExpression (const char *expr);
+
+ lldb::SBValue
+ EvaluateExpression (const char *expr, bool fetch_dynamic_value);
// Gets the lexical block that defines the stack frame. Another way to think
// of this is it will return the block that contains all of the variables
@@ -116,17 +120,32 @@ public:
bool statics,
bool in_scope_only);
+ // The version that doesn't supply a "use_dynamic" value will use the target's default.
+ lldb::SBValueList
+ GetVariables (bool arguments,
+ bool locals,
+ bool statics,
+ bool in_scope_only,
+ bool use_dynamic);
+
lldb::SBValueList
GetRegisters ();
+ // The version that doesn't supply a "use_dynamic" value will use the target's default.
lldb::SBValue
FindVariable (const char *var_name);
+ lldb::SBValue
+ FindVariable (const char *var_name, bool use_dynamic);
+
// Find variables, register sets, registers, or persistent variables using
// the frame as the scope
lldb::SBValue
FindValue (const char *name, ValueType value_type);
+ lldb::SBValue
+ FindValue (const char *name, ValueType value_type, bool use_dynamic);
+
bool
GetDescription (lldb::SBStream &description);
diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h
index 08ec657151f..b8ac830f675 100644
--- a/lldb/include/lldb/API/SBValue.h
+++ b/lldb/include/lldb/API/SBValue.h
@@ -99,6 +99,9 @@ public:
lldb::SBValue
GetChildAtIndex (uint32_t idx);
+ lldb::SBValue
+ GetChildAtIndex (uint32_t idx, bool use_dynamic);
+
// Matches children of this object only and will match base classes and
// member names if this is a clang typed object.
uint32_t
@@ -109,6 +112,11 @@ public:
lldb::SBValue
GetChildMemberWithName (const char *name);
+ // Matches child members of this object and child members of any base
+ // classes.
+ lldb::SBValue
+ GetChildMemberWithName (const char *name, bool use_dynamic);
+
uint32_t
GetNumChildren ();
diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h
index b0a8028fe27..6dcf6bdba91 100644
--- a/lldb/include/lldb/Core/ValueObject.h
+++ b/lldb/include/lldb/Core/ValueObject.h
@@ -306,7 +306,7 @@ public:
bool
ResolveValue (Scalar &scalar);
-
+
const char *
GetLocationAsCString ();
@@ -325,9 +325,6 @@ public:
bool
UpdateValueIfNeeded ();
- const DataExtractor &
- GetDataExtractor () const;
-
DataExtractor &
GetDataExtractor ();
@@ -345,10 +342,10 @@ public:
GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create);
lldb::ValueObjectSP
- GetDynamicValue ()
- {
- return m_dynamic_value_sp;
- }
+ GetDynamicValue (bool can_create);
+
+ lldb::ValueObjectSP
+ GetDynamicValue (bool can_create, lldb::ValueObjectSP &owning_valobj_sp);
virtual lldb::ValueObjectSP
CreateConstantValue (const ConstString &name);
@@ -369,8 +366,11 @@ public:
m_object_desc_str.clear();
}
- bool
- SetDynamicValue ();
+ virtual bool
+ IsDynamic ()
+ {
+ return false;
+ }
static void
DumpValueObject (Stream &s,
@@ -382,6 +382,7 @@ public:
bool show_types,
bool show_location,
bool use_objc,
+ bool use_dynamic,
bool scope_already_checked,
bool flat_output);
@@ -411,13 +412,16 @@ public:
m_format = format;
}
- ValueObject *
+ // Use GetParent for display purposes, but if you want to tell the parent to update itself
+ // then use m_parent. The ValueObjectDynamicValue's parent is not the correct parent for
+ // displaying, they are really siblings, so for display it needs to route through to its grandparent.
+ virtual ValueObject *
GetParent()
{
return m_parent;
}
- const ValueObject *
+ virtual const ValueObject *
GetParent() const
{
return m_parent;
@@ -436,8 +440,8 @@ protected:
//------------------------------------------------------------------
// Classes that inherit from ValueObject can see and modify these
//------------------------------------------------------------------
- ValueObject* m_parent; // The parent value object, or NULL if this has no parent
- EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
+ ValueObject *m_parent; // The parent value object, or NULL if this has no parent
+ EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
// updated. When we are asked to update the value object, we check whether
// the context & stop id are the same before updating.
ConstString m_name; // The name of this object
@@ -453,6 +457,10 @@ protected:
std::vector<lldb::ValueObjectSP> m_children;
std::map<ConstString, lldb::ValueObjectSP> m_synthetic_children;
lldb::ValueObjectSP m_dynamic_value_sp;
+ lldb::ValueObjectSP m_addr_of_valobj_sp; // These two shared pointers help root the ValueObject shared pointers that
+ lldb::ValueObjectSP m_deref_valobj_sp; // we hand out, so that we can use them in their dynamic types and ensure
+ // they will last as long as this ValueObject...
+
lldb::Format m_format;
bool m_value_is_valid:1,
m_value_did_change:1,
@@ -463,6 +471,7 @@ protected:
friend class CommandObjectExpression;
friend class ClangExpressionVariable;
+ friend class ClangExpressionDeclMap; // For GetValue...
friend class Target;
friend class ValueObjectChild;
//------------------------------------------------------------------
@@ -486,6 +495,9 @@ protected:
virtual bool
UpdateValue () = 0;
+ virtual void
+ CalculateDynamicValue ();
+
// Should only be called by ValueObject::GetChildAtIndex()
virtual lldb::ValueObjectSP
CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index);
@@ -509,7 +521,7 @@ protected:
void
SetValueIsValid (bool valid);
-
+public:
lldb::addr_t
GetPointerValue (AddressType &address_type,
bool scalar_is_load_address);
diff --git a/lldb/include/lldb/Core/ValueObjectConstResult.h b/lldb/include/lldb/Core/ValueObjectConstResult.h
index 6fca731047f..2c6cbc8d145 100644
--- a/lldb/include/lldb/Core/ValueObjectConstResult.h
+++ b/lldb/include/lldb/Core/ValueObjectConstResult.h
@@ -91,6 +91,12 @@ protected:
virtual bool
UpdateValue ();
+ virtual void
+ CalculateDynamicValue () {} // CalculateDynamicValue doesn't change the dynamic value, since this can get
+ // called at any time and you can't reliably fetch the dynamic value at any time.
+ // If we want to have dynamic values for ConstResults, then we'll need to make them
+ // up when we make the const result & stuff them in by hand.
+
clang::ASTContext *m_clang_ast; // The clang AST that the clang type comes from
ConstString m_type_name;
uint32_t m_byte_size;
diff --git a/lldb/include/lldb/Core/ValueObjectDynamicValue.h b/lldb/include/lldb/Core/ValueObjectDynamicValue.h
new file mode 100644
index 00000000000..e87fa94188d
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectDynamicValue.h
@@ -0,0 +1,105 @@
+//===-- ValueObjectDynamicValue.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ValueObjectDynamicValue_h_
+#define liblldb_ValueObjectDynamicValue_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that represents memory at a given address, viewed as some
+// set lldb type.
+//----------------------------------------------------------------------
+class ValueObjectDynamicValue : public ValueObject
+{
+public:
+ ValueObjectDynamicValue (ValueObject &parent);
+
+ virtual
+ ~ValueObjectDynamicValue();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual lldb::clang_type_t
+ GetClangType ();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual bool
+ IsInScope ();
+
+ virtual bool
+ IsDynamic ()
+ {
+ return true;
+ }
+
+ virtual ValueObject *
+ GetParent()
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ virtual const ValueObject *
+ GetParent() const
+ {
+ if (m_parent)
+ return m_parent->GetParent();
+ else
+ return NULL;
+ }
+
+ void
+ SetOwningSP (lldb::ValueObjectSP &owning_sp)
+ {
+ if (m_owning_valobj_sp == owning_sp)
+ return;
+
+ assert (m_owning_valobj_sp.get() == NULL);
+ m_owning_valobj_sp = owning_sp;
+ }
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ Address m_address; ///< The variable that this value object is based upon
+ lldb::TypeSP m_type_sp;
+ lldb::ValueObjectSP m_owning_valobj_sp;
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectDynamicValue);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectDynamicValue_h_
diff --git a/lldb/include/lldb/Core/ValueObjectMemory.h b/lldb/include/lldb/Core/ValueObjectMemory.h
new file mode 100644
index 00000000000..4d9a69e65ec
--- /dev/null
+++ b/lldb/include/lldb/Core/ValueObjectMemory.h
@@ -0,0 +1,73 @@
+//===-- ValueObjectMemory.h -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ValueObjectMemory_h_
+#define liblldb_ValueObjectMemory_h_
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/ValueObject.h"
+
+namespace lldb_private {
+
+//----------------------------------------------------------------------
+// A ValueObject that represents memory at a given address, viewed as some
+// set lldb type.
+//----------------------------------------------------------------------
+class ValueObjectMemory : public ValueObject
+{
+public:
+ ValueObjectMemory (ExecutionContextScope *exe_scope,
+ const char *name,
+ const Address &address,
+ lldb::TypeSP &type_sp);
+
+ virtual
+ ~ValueObjectMemory();
+
+ virtual size_t
+ GetByteSize();
+
+ virtual clang::ASTContext *
+ GetClangAST ();
+
+ virtual lldb::clang_type_t
+ GetClangType ();
+
+ virtual ConstString
+ GetTypeName();
+
+ virtual uint32_t
+ CalculateNumChildren();
+
+ virtual lldb::ValueType
+ GetValueType() const;
+
+ virtual bool
+ IsInScope ();
+
+protected:
+ virtual bool
+ UpdateValue ();
+
+ Address m_address; ///< The variable that this value object is based upon
+ lldb::TypeSP m_type_sp;
+
+private:
+ //------------------------------------------------------------------
+ // For ValueObject only
+ //------------------------------------------------------------------
+ DISALLOW_COPY_AND_ASSIGN (ValueObjectMemory);
+};
+
+} // namespace lldb_private
+
+#endif // liblldb_ValueObjectMemory_h_
diff --git a/lldb/include/lldb/Target/LanguageRuntime.h b/lldb/include/lldb/Target/LanguageRuntime.h
index 2d193768e64..6005e34e6d3 100644
--- a/lldb/include/lldb/Target/LanguageRuntime.h
+++ b/lldb/include/lldb/Target/LanguageRuntime.h
@@ -42,9 +42,14 @@ public:
virtual bool
GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) = 0;
- virtual lldb::ValueObjectSP
- GetDynamicValue (lldb::ValueObjectSP in_value) = 0;
+ virtual bool
+ GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address) = 0;
+ // This should be a fast test to determine whether it is likely that this value would
+ // have a dynamic type.
+ virtual bool
+ CouldHaveDynamicValue (ValueObject &in_value) = 0;
+
virtual void
SetExceptionBreakpoints ()
{
diff --git a/lldb/include/lldb/Target/StackFrame.h b/lldb/include/lldb/Target/StackFrame.h
index 5b1707956aa..af8b317dc6e 100644
--- a/lldb/include/lldb/Target/StackFrame.h
+++ b/lldb/include/lldb/Target/StackFrame.h
@@ -33,7 +33,8 @@ public:
enum ExpressionPathOption
{
eExpressionPathOptionCheckPtrVsMember = (1u << 0),
- eExpressionPathOptionsNoFragileObjcIvar = (1u << 1)
+ eExpressionPathOptionsNoFragileObjcIvar = (1u << 1),
+ eExpressionPathOptionsDynamicValue = (1u << 2)
};
//------------------------------------------------------------------
// Constructors and Destructors
@@ -133,10 +134,10 @@ public:
}
lldb::ValueObjectSP
- GetValueObjectForFrameVariable (const lldb::VariableSP &variable_sp);
+ GetValueObjectForFrameVariable (const lldb::VariableSP &variable_sp, bool use_dynamic);
lldb::ValueObjectSP
- TrackGlobalVariable (const lldb::VariableSP &variable_sp);
+ TrackGlobalVariable (const lldb::VariableSP &variable_sp, bool use_dynamic);
//------------------------------------------------------------------
// lldb::ExecutionContextScope pure virtual functions
diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h
index f1cb0a8a5c8..0fd68f4aabf 100644
--- a/lldb/include/lldb/Target/Target.h
+++ b/lldb/include/lldb/Target/Target.h
@@ -66,6 +66,12 @@ public:
StringList &value,
Error *err);
+ bool
+ GetPreferDynamicValue()
+ {
+ return m_prefer_dynamic_value;
+ }
+
protected:
void
@@ -77,6 +83,7 @@ protected:
std::string m_expr_prefix_path;
std::string m_expr_prefix_contents;
+ bool m_prefer_dynamic_value;
};
@@ -461,6 +468,7 @@ public:
StackFrame *frame,
bool unwind_on_error,
bool keep_in_memory,
+ bool fetch_dynamic_value,
lldb::ValueObjectSP &result_valobj_sp);
ClangPersistentVariables &
diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj
index 92250ab243d..66a68401082 100644
--- a/lldb/lldb.xcodeproj/project.pbxproj
+++ b/lldb/lldb.xcodeproj/project.pbxproj
@@ -408,6 +408,10 @@
26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; };
+ 4CABA9DD134A8BA800539BDD /* ValueObjectMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */; };
+ 4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */; };
+ 4CD0BD0D134BFAB600CB44D4 /* ValueObjectDynamicValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */; };
+ 4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
9A357583116CFDEE00E8ED2F /* SBValueList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A357582116CFDEE00E8ED2F /* SBValueList.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -1103,6 +1107,8 @@
4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecordingMemoryManager.h; path = include/lldb/Expression/RecordingMemoryManager.h; sourceTree = "<group>"; };
4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectApropos.cpp; path = source/Commands/CommandObjectApropos.cpp; sourceTree = "<group>"; };
4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectApropos.h; path = source/Commands/CommandObjectApropos.h; sourceTree = "<group>"; };
+ 4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectMemory.h; path = include/lldb/Core/ValueObjectMemory.h; sourceTree = "<group>"; };
+ 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectMemory.cpp; path = source/Core/ValueObjectMemory.cpp; sourceTree = "<group>"; };
4CAFCE001101216B00CA63DB /* ThreadPlanRunToAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanRunToAddress.h; path = include/lldb/Target/ThreadPlanRunToAddress.h; sourceTree = "<group>"; };
4CAFCE031101218900CA63DB /* ThreadPlanRunToAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanRunToAddress.cpp; path = source/Target/ThreadPlanRunToAddress.cpp; sourceTree = "<group>"; };
4CB4430912491DDA00C13DC2 /* LanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LanguageRuntime.h; path = include/lldb/Target/LanguageRuntime.h; sourceTree = "<group>"; };
@@ -1115,6 +1121,8 @@
4CB443F612499B6E00C13DC2 /* ObjCLanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCLanguageRuntime.h; path = include/lldb/Target/ObjCLanguageRuntime.h; sourceTree = "<group>"; };
4CC2A148128C73ED001531C4 /* ThreadPlanTracer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanTracer.cpp; path = source/Target/ThreadPlanTracer.cpp; sourceTree = "<group>"; };
4CC2A14C128C7409001531C4 /* ThreadPlanTracer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanTracer.h; path = include/lldb/Target/ThreadPlanTracer.h; sourceTree = "<group>"; };
+ 4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectDynamicValue.h; path = include/lldb/Core/ValueObjectDynamicValue.h; sourceTree = "<group>"; };
+ 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectDynamicValue.cpp; path = source/Core/ValueObjectDynamicValue.cpp; sourceTree = "<group>"; };
4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
69A01E1B1236C5D400C660B5 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Condition.cpp; sourceTree = "<group>"; };
69A01E1C1236C5D400C660B5 /* Host.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Host.cpp; sourceTree = "<group>"; };
@@ -1902,8 +1910,12 @@
26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */,
26424E3E125986D30016D82C /* ValueObjectConstResult.h */,
26424E3C125986CB0016D82C /* ValueObjectConstResult.cpp */,
+ 4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */,
+ 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */,
26BC7D8410F1B77400F91463 /* ValueObjectList.h */,
26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */,
+ 4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */,
+ 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */,
2643343A1110F63C00CDB6C6 /* ValueObjectRegister.h */,
264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */,
26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */,
@@ -2550,6 +2562,8 @@
26651A16133BF9CD005B64B7 /* Opcode.h in Headers */,
266603CD1345B5C0004DA8B6 /* ConnectionSharedMemory.h in Headers */,
2671A0CE134825F6003A87BB /* ConnectionMachPort.h in Headers */,
+ 4CABA9DD134A8BA800539BDD /* ValueObjectMemory.h in Headers */,
+ 4CD0BD0D134BFAB600CB44D4 /* ValueObjectDynamicValue.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3114,6 +3128,8 @@
26651A18133BF9E0005B64B7 /* Opcode.cpp in Sources */,
266603CA1345B5A8004DA8B6 /* ConnectionSharedMemory.cpp in Sources */,
2671A0D013482601003A87BB /* ConnectionMachPort.cpp in Sources */,
+ 4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */,
+ 4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -3209,7 +3225,6 @@
LLVM_CONFIGURATION = Release;
LLVM_SOURCE_DIR = "$(SRCROOT)/llvm";
ONLY_ACTIVE_ARCH = YES;
- PREBINDING = NO;
VALID_ARCHS = "x86_64 i386";
};
name = Debug;
@@ -3251,7 +3266,6 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
GCC_DYNAMIC_NO_PIC = NO;
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
GCC_OPTIMIZATION_LEVEL = 0;
INSTALL_PATH = /Developer/usr/bin;
ONLY_ACTIVE_ARCH = NO;
@@ -3265,7 +3279,6 @@
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
INSTALL_PATH = /Developer/usr/bin;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "darwin-debug";
@@ -3277,7 +3290,6 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
- GCC_ENABLE_FIX_AND_CONTINUE = YES;
INSTALL_PATH = /Developer/usr/bin;
ONLY_ACTIVE_ARCH = NO;
PRODUCT_NAME = "darwin-debug";
@@ -3542,7 +3554,6 @@
"$(inherited)",
"\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
);
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
HEADER_SEARCH_PATHS = "";
@@ -3730,7 +3741,6 @@
"$(inherited)",
"\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
);
- GCC_ENABLE_FIX_AND_CONTINUE = NO;
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
HEADER_SEARCH_PATHS = "";
diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp
index e51c2ecfcfb..93c54108ce7 100644
--- a/lldb/source/API/SBFrame.cpp
+++ b/lldb/source/API/SBFrame.cpp
@@ -343,6 +343,13 @@ SBFrame::Clear()
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 @@ SBFrame::FindVariable (const char *name)
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 @@ SBFrame::FindVariable (const char *name)
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 @@ SBFrame::FindValue (const char *name, ValueType value_type)
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 @@ SBFrame::GetVariables (bool arguments,
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 @@ SBFrame::GetVariables (bool arguments,
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 @@ SBFrame::GetDescription (SBStream &description)
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 @@ SBFrame::EvaluateExpression (const char *expr)
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/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp
index a607841a527..64011789878 100644
--- a/lldb/source/API/SBValue.cpp
+++ b/lldb/source/API/SBValue.cpp
@@ -339,6 +339,13 @@ SBValue::SetValueFromCString (const char *value_str)
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 @@ SBValue::GetChildAtIndex (uint32_t idx)
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::GetIndexOfChildWithName (const char *name)
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 @@ SBValue::GetChildMemberWithName (const char *name)
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/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 7b9f01cd3c8..82d2197e7cc 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -77,6 +77,23 @@ CommandObjectExpression::CommandOptions::SetOptionValue (uint32_t option_idx, co
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 @@ CommandObjectExpression::CommandOptions::OptionParsingStarting ()
debug = false;
format = eFormatDefault;
print_object = false;
+ use_dynamic = eLazyBoolCalculate;
unwind_on_error = true;
show_types = true;
show_summary = true;
@@ -239,8 +257,27 @@ CommandObjectExpression::EvaluateExpression
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 @@ CommandObjectExpression::EvaluateExpression
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 @@ CommandObjectExpression::CommandOptions::g_option_table[] =
//{ 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/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h
index 6eff72c0045..71eb9bf8ea1 100644
--- a/lldb/source/Commands/CommandObjectExpression.h
+++ b/lldb/source/Commands/CommandObjectExpression.h
@@ -51,6 +51,7 @@ public:
lldb::Format format;
bool debug;
bool print_object;
+ LazyBool use_dynamic;
bool unwind_on_error;
bool show_types;
bool show_summary;
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index 51299c2aaf3..bdcd7039b99 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -310,6 +310,22 @@ public:
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 @@ public:
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 @@ public:
show_decl = false;
debug = false;
flat_output = false;
+ use_dynamic = eLazyBoolCalculate;
max_depth = UINT32_MAX;
ptr_depth = 0;
format = eFormatDefault;
@@ -391,6 +408,7 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
var_sp->GetDeclaration ().DumpStopContext (&s, false);
s.PutCString (": ");
}
-
+
ValueObject::DumpValueObject (result.GetOutputStream(),
valobj_sp.get(),
name_cstr,
@@ -510,7 +554,8 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
// 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 @@ public:
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 @@ protected:
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/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp
index eeb3ac082d9..d95806cf192 100644
--- a/lldb/source/Core/ValueObject.cpp
+++ b/lldb/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 @@ ValueObject::UpdateValueIfNeeded ()
return m_error.Success();
}
-const DataExtractor &
-ValueObject::GetDataExtractor () const
-{
- return m_data;
-}
-
DataExtractor &
ValueObject::GetDataExtractor ()
{
+ UpdateValueIfNeeded();
return m_data;
}
@@ -281,17 +277,20 @@ ValueObjectSP
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 @@ ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
// 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)
- {
- 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 (UpdateValueIfNeeded())
+ {
+ 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
+ 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)
{
- child_sp.reset();
- }
+ 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 @@ ValueObjectSP
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;
-
- 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);
+ 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 (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 @@ ValueObject::GetValueAsCString ()
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 @@ ValueObject::GetPointerValue (AddressType &address_type, bool scalar_is_load_add
{
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 @@ ValueObject::GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create)
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 @@ ValueObject::GetBaseClassPath (Stream &s)
{
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::GetBaseClassPath (Stream &s)
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 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes)
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 @@ ValueObject::DumpValueObject
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 @@ ValueObject::DumpValueObject
show_types,
show_location,
false,
+ use_dynamic,
true,
flat_output);
}
@@ -1296,7 +1370,9 @@ ValueObject::CreateConstantValue (const ConstString &name)
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 @@ ValueObject::Dereference (Error &error)
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 @@ ValueObject::Dereference (Error &error)
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 @@ ValueObject::AddressOf (Error &error)
{
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 @@ ValueObject::EvaluationPoint::SyncWithProcessState()
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/lldb/source/Core/ValueObjectChild.cpp b/lldb/source/Core/ValueObjectChild.cpp
index fc5f6c850f5..509852f4b3a 100644
--- a/lldb/source/Core/ValueObjectChild.cpp
+++ b/lldb/source/Core/ValueObjectChild.cpp
@@ -97,7 +97,7 @@ ValueObjectChild::UpdateValue ()
ValueObject* parent = m_parent;
if (parent)
{
- if (parent->UpdateValue())
+ if (parent->UpdateValueIfNeeded())
{
m_value.SetContext(Value::eContextTypeClangType, m_clang_type);
diff --git a/lldb/source/Core/ValueObjectDynamicValue.cpp b/lldb/source/Core/ValueObjectDynamicValue.cpp
new file mode 100644
index 00000000000..2b80ae513e3
--- /dev/null
+++ b/lldb/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/lldb/source/Core/ValueObjectMemory.cpp b/lldb/source/Core/ValueObjectMemory.cpp
new file mode 100644
index 00000000000..d3998488eba
--- /dev/null
+++ b/lldb/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/lldb/source/Expression/ClangExpressionDeclMap.cpp b/lldb/source/Expression/ClangExpressionDeclMap.cpp
index 99f0e60a0f0..0054a03967b 100644
--- a/lldb/source/Expression/ClangExpressionDeclMap.cpp
+++ b/lldb/source/Expression/ClangExpressionDeclMap.cpp
@@ -848,7 +848,6 @@ ClangExpressionDeclMap::DoMaterialize
// 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 @@ ClangExpressionDeclMap::DoMaterialize
if (result_sp_ptr)
*result_sp_ptr = member_sp;
- keep_this_in_memory = m_keep_result_in_memory;
}
if (!DoMaterializeOnePersistentVariable (dematerialize,
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index b0f7733c2cd..fb4c98dc441 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/lldb/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 @@ using namespace lldb_private;
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)
+{
+ return in_value.IsPointerOrReferenceType();
+}
+
+bool
+ItaniumABILanguageRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &dynamic_type_sp, Address &dynamic_address)
{
- ValueObjectSP ret_sp;
- return ret_sp;
+ // 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/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
index d7ac04adc20..421ac12725f 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h
@@ -30,9 +30,12 @@ namespace lldb_private {
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/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
index 392abeeaebf..08af0b68431 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.cpp
@@ -191,11 +191,16 @@ AppleObjCRuntime::GetPrintForDebuggerAddr()
return m_PrintForDebugger_addr.get();
}
-lldb::ValueObjectSP
-AppleObjCRuntime::GetDynamicValue (lldb::ValueObjectSP in_value)
+bool
+AppleObjCRuntime::CouldHaveDynamicValue (ValueObject &in_value)
+{
+ return in_value.IsPointerType();
+}
+
+bool
+AppleObjCRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address)
{
- lldb::ValueObjectSP ret_sp;
- return ret_sp;
+ return false;
}
bool
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
index 1c500e39be1..e7e0f71d956 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h
@@ -37,8 +37,11 @@ public:
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/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
index 46747571198..000f14e3df1 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.cpp
@@ -40,11 +40,10 @@ static const char *pluginName = "AppleObjCRuntimeV1";
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/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
index 2b815b18091..975c018b4e9 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV1.h
@@ -31,8 +31,8 @@ public:
~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/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 5d276dcd02d..c6e3533a09d 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -46,11 +46,10 @@ AppleObjCRuntimeV2::AppleObjCRuntimeV2 (Process *process, ModuleSP &objc_module_
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/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
index d2bd414bfc3..0015dd2f424 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.h
@@ -31,8 +31,8 @@ public:
~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/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 26d84b968dc..a492e47642d 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -1902,6 +1902,12 @@ Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
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 @@ Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
ubuf + bytes_written,
size - bytes_written,
error);
-
+
return bytes_written;
}
diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp
index 0d0c0e8ec61..a5df9284b55 100644
--- a/lldb/source/Target/StackFrame.cpp
+++ b/lldb/source/Target/StackFrame.cpp
@@ -493,6 +493,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
{
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 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
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 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
return ValueObjectSP();
}
}
-
child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
if (!child_valobj_sp)
{
@@ -624,6 +626,12 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
}
// 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 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
}
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 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
// %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 @@ StackFrame::HasDebugInformation ()
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 @@ StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp)
}
}
}
+ 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 @@ StackFrame::TrackGlobalVariable (const VariableSP &variable_sp)
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/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index 2ade9e66142..d08a0fe2bd1 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -887,6 +887,7 @@ Target::EvaluateExpression
StackFrame *frame,
bool unwind_on_error,
bool keep_in_memory,
+ bool fetch_dynamic_value,
lldb::ValueObjectSP &result_valobj_sp
)
{
@@ -927,7 +928,16 @@ Target::EvaluateExpression
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 @@ Target::SettingsController::CreateInstanceSettings (const char *instance_name)
}
-#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 @@ GetSettingNameForExecutionOSType ()
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 @@ TargetInstanceSettings::TargetInstanceSettings
) :
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 @@ TargetInstanceSettings::UpdateInstanceSettingsVariable (const ConstString &var_n
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 @@ TargetInstanceSettings::CopyInstanceSettings (const lldb::InstanceSettingsSP &ne
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 @@ TargetInstanceSettings::GetInstanceSettingsValue (const SettingEntry &entry,
{
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 @@ Target::SettingsController::instance_settings_table[] =
// 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/lldb/source/Target/ThreadPlanTestCondition.cpp b/lldb/source/Target/ThreadPlanTestCondition.cpp
index 9facfdcb95c..1349e9eb649 100644
--- a/lldb/source/Target/ThreadPlanTestCondition.cpp
+++ b/lldb/source/Target/ThreadPlanTestCondition.cpp
@@ -84,8 +84,8 @@ ThreadPlanTestCondition::ShouldStop (Event *event_ptr)
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;
diff --git a/lldb/test/cpp/dynamic-value/Makefile b/lldb/test/cpp/dynamic-value/Makefile
new file mode 100644
index 00000000000..ceb406ee2ea
--- /dev/null
+++ b/lldb/test/cpp/dynamic-value/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := pass-to-base.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/cpp/dynamic-value/TestDynamicValue.py b/lldb/test/cpp/dynamic-value/TestDynamicValue.py
new file mode 100644
index 00000000000..78b2f22208f
--- /dev/null
+++ b/lldb/test/cpp/dynamic-value/TestDynamicValue.py
@@ -0,0 +1,226 @@
+"""
+Use lldb Python API to test dynamic values in C++
+"""
+
+import os, time
+import re
+import unittest2
+import lldb, lldbutil
+from lldbtest import *
+
+class DynamicValueTestCase(TestBase):
+
+ mydir = os.path.join("cpp", "dynamic-value")
+
+ @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
+ @python_api_test
+ def test_get_dynamic_vals_with_dsym(self):
+ """Test fetching C++ dynamic values from pointers & references."""
+ self.buildDsym()
+ self.do_get_dynamic_vals()
+
+ @python_api_test
+ def test_get_dynamic_vals_with_dwarf(self):
+ """Test fetching C++ dynamic values from pointers & references."""
+ self.buildDwarf()
+ self.do_get_dynamic_vals()
+
+ def setUp(self):
+ # Call super's setUp().
+ TestBase.setUp(self)
+
+ # Find the line number to break for main.c.
+
+ self.do_something_line = line_number('pass-to-base.cpp', '// Break here in doSomething.')
+ self.main_first_call_line = line_number('pass-to-base.cpp',
+ '// Break here and get real addresses of myB and otherB.')
+ self.main_second_call_line = line_number('pass-to-base.cpp',
+ '// Break here and get real address of reallyA.')
+
+ def examine_value_object_of_this_ptr (self, this_static, this_dynamic, dynamic_location):
+
+ # Get "this" as its static value
+
+ self.assertTrue (this_static.IsValid())
+ this_static_loc = int (this_static.GetValue(), 16)
+
+ # Get "this" as its dynamic value
+
+ self.assertTrue (this_dynamic.IsValid())
+ this_dynamic_typename = this_dynamic.GetTypeName()
+ self.assertTrue (this_dynamic_typename.find('B') != -1)
+ this_dynamic_loc = int (this_dynamic.GetValue(), 16)
+
+ # Make sure we got the right address for "this"
+
+ self.assertTrue (this_dynamic_loc == dynamic_location)
+
+ # And that the static address is greater than the dynamic one
+
+ self.assertTrue (this_static_loc > this_dynamic_loc)
+
+ # Now read m_b_value which is only in the dynamic value:
+
+ this_dynamic_m_b_value = this_dynamic.GetChildMemberWithName('m_b_value', True)
+ self.assertTrue (this_dynamic_m_b_value.IsValid())
+
+ m_b_value = int (this_dynamic_m_b_value.GetValue(), 0)
+ self.assertTrue (m_b_value == 10)
+
+ # Make sure it is not in the static version
+
+ this_static_m_b_value = this_static.GetChildMemberWithName('m_b_value', False)
+ self.assertTrue (this_static_m_b_value.IsValid() == False)
+
+ # Okay, now let's make sure that we can get the dynamic type of a child element:
+
+ contained_auto_ptr = this_dynamic.GetChildMemberWithName ('m_client_A', True)
+ self.assertTrue (contained_auto_ptr.IsValid())
+ contained_b = contained_auto_ptr.GetChildMemberWithName ('_M_ptr', True)
+ self.assertTrue (contained_b.IsValid())
+
+ contained_b_static = contained_auto_ptr.GetChildMemberWithName ('_M_ptr', False)
+ self.assertTrue (contained_b_static.IsValid())
+
+ contained_b_addr = int (contained_b.GetValue(), 16)
+ contained_b_static_addr = int (contained_b_static.GetValue(), 16)
+
+ self.assertTrue (contained_b_addr < contained_b_static_addr)
+
+ def do_get_dynamic_vals(self):
+ """Get argument vals for the call stack when stopped on a breakpoint."""
+ exe = os.path.join(os.getcwd(), "a.out")
+
+ # Create a target from the debugger.
+
+ target = self.dbg.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT)
+ self.assertTrue(target.IsValid(), VALID_TARGET)
+
+ # Set up our breakpoints:
+
+ do_something_bpt = target.BreakpointCreateByLocation('pass-to-base.cpp', self.do_something_line)
+ self.assertTrue(do_something_bpt.IsValid() and
+ do_something_bpt.GetNumLocations() == 1,
+ VALID_BREAKPOINT)
+
+ first_call_bpt = target.BreakpointCreateByLocation('pass-to-base.cpp', self.main_first_call_line)
+ self.assertTrue(first_call_bpt.IsValid() and
+ first_call_bpt.GetNumLocations() == 1,
+ VALID_BREAKPOINT)
+
+ second_call_bpt = target.BreakpointCreateByLocation('pass-to-base.cpp', self.main_second_call_line)
+ self.assertTrue(second_call_bpt.IsValid() and
+ second_call_bpt.GetNumLocations() == 1,
+ VALID_BREAKPOINT)
+
+ # Now launch the process, and do not stop at the entry point.
+
+ error = lldb.SBError()
+ self.process = target.Launch (self.dbg.GetListener(), None, None, os.ctermid(), os.ctermid(), os.ctermid(), None, 0, False, error)
+
+ self.assertTrue(self.process.GetState() == lldb.eStateStopped,
+ PROCESS_STOPPED)
+
+ threads = lldbutil.GetThreadsStoppedAtBreakpoint (self.process, first_call_bpt)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+
+ frame = thread.GetFrameAtIndex(0)
+
+ # Now find the dynamic addresses of myB and otherB so we can compare them
+ # with the dynamic values we get in doSomething:
+
+ noDynamic = False
+ useDynamic = True
+
+ myB = frame.FindVariable ('myB', noDynamic);
+ self.assertTrue (myB.IsValid())
+ myB_loc = int (myB.GetLocation(), 16)
+
+ otherB = frame.FindVariable('otherB', noDynamic)
+ self.assertTrue (otherB.IsValid())
+ otherB_loc = int (otherB.GetLocation(), 16)
+
+ # Okay now run to doSomething:
+
+ threads = lldbutil.ContinueToBreakpoint (self.process, do_something_bpt)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+
+ frame = thread.GetFrameAtIndex(0)
+
+ # Get "this" using FindVariable:
+
+ this_static = frame.FindVariable ('this', noDynamic)
+ this_dynamic = frame.FindVariable ('this', useDynamic)
+ self.examine_value_object_of_this_ptr (this_static, this_dynamic, myB_loc)
+
+ # Get "this" using FindValue, make sure that works too:
+ this_static = frame.FindValue ('this', lldb.eValueTypeVariableArgument, noDynamic)
+ this_dynamic = frame.FindValue ('this', lldb.eValueTypeVariableArgument, useDynamic)
+ self.examine_value_object_of_this_ptr (this_static, this_dynamic, myB_loc)
+
+ # Get "this" using the EvaluateExpression:
+ # These tests fail for now because EvaluateExpression doesn't currently support dynamic typing...
+ #this_static = frame.EvaluateExpression ('this', False)
+ #this_dynamic = frame.EvaluateExpression ('this', True)
+ #self.examine_value_object_of_this_ptr (this_static, this_dynamic, myB_loc)
+
+ # The "frame var" code uses another path to get into children, so let's
+ # make sure that works as well:
+
+ self.expect('frame var -d 1 anotherA.m_client_A._M_ptr', 'frame var finds its way into a child member',
+ patterns = ['\(.* B \*\)'])
+
+ # Now make sure we also get it right for a reference as well:
+
+ anotherA_static = frame.FindVariable ('anotherA', False)
+ self.assertTrue (anotherA_static.IsValid())
+ anotherA_static_addr = int (anotherA_static.GetValue(), 16)
+
+ anotherA_dynamic = frame.FindVariable ('anotherA', True)
+ self.assertTrue (anotherA_dynamic.IsValid())
+ anotherA_dynamic_addr = int (anotherA_dynamic.GetValue(), 16)
+ anotherA_dynamic_typename = anotherA_dynamic.GetTypeName()
+ self.assertTrue (anotherA_dynamic_typename.find('B') != -1)
+
+ self.assertTrue(anotherA_dynamic_addr < anotherA_static_addr)
+
+ anotherA_m_b_value_dynamic = anotherA_dynamic.GetChildMemberWithName('m_b_value', True)
+ self.assertTrue (anotherA_m_b_value_dynamic.IsValid())
+ anotherA_m_b_val = int (anotherA_m_b_value_dynamic.GetValue(), 10)
+ self.assertTrue (anotherA_m_b_val == 300)
+
+ anotherA_m_b_value_static = anotherA_static.GetChildMemberWithName('m_b_value', True)
+ self.assertTrue (anotherA_m_b_value_static.IsValid() == False)
+
+ # Okay, now continue again, and when we hit the second breakpoint in main
+
+ threads = lldbutil.ContinueToBreakpoint (self.process, second_call_bpt)
+ self.assertTrue (len(threads) == 1)
+ thread = threads[0]
+
+ frame = thread.GetFrameAtIndex(0)
+ reallyA_value = frame.FindVariable ('reallyA', False)
+ self.assertTrue(reallyA_value.IsValid())
+ reallyA_loc = int (reallyA_value.GetLocation(), 16)
+
+ # Finally continue to doSomething again, and make sure we get the right value for anotherA,
+ # which this time around is just an "A".
+
+ threads = lldbutil.ContinueToBreakpoint (self.process, do_something_bpt)
+ self.assertTrue(len(threads) == 1)
+ thread = threads[0]
+
+ frame = thread.GetFrameAtIndex(0)
+ anotherA_value = frame.FindVariable ('anotherA', True)
+ self.assertTrue(anotherA_value.IsValid())
+ anotherA_loc = int (anotherA_value.GetValue(), 16)
+ self.assertTrue (anotherA_loc == reallyA_loc)
+ self.assertTrue (anotherA_value.GetTypeName().find ('B') == -1)
+
+if __name__ == '__main__':
+ import atexit
+ lldb.SBDebugger.Initialize()
+ atexit.register(lambda: lldb.SBDebugger.Terminate())
+ unittest2.main()
diff --git a/lldb/test/cpp/dynamic-value/pass-to-base.cpp b/lldb/test/cpp/dynamic-value/pass-to-base.cpp
new file mode 100644
index 00000000000..83ab1617f71
--- /dev/null
+++ b/lldb/test/cpp/dynamic-value/pass-to-base.cpp
@@ -0,0 +1,62 @@
+#include <stdio.h>
+#include <memory>
+
+class Extra
+{
+public:
+ Extra (int in_one, int in_two) : m_extra_one(in_one), m_extra_two(in_two) {}
+
+private:
+ int m_extra_one;
+ int m_extra_two;
+};
+
+class A
+{
+public:
+ A(int value) : m_a_value (value) {}
+ A(int value, A* client_A) : m_a_value (value), m_client_A (client_A) {}
+
+ virtual void
+ doSomething (A &anotherA)
+ {
+ printf ("In A %p doing something with %d.\n", this, m_a_value);
+ printf ("Also have another A at %p: %d.\n", &anotherA, anotherA.Value()); // Break here in doSomething.
+ }
+
+ int
+ Value()
+ {
+ return m_a_value;
+ }
+
+private:
+ int m_a_value;
+ std::auto_ptr<A> m_client_A;
+};
+
+class B : public Extra, public virtual A
+{
+public:
+ B (int b_value, int a_value) : Extra(b_value, a_value), A(a_value), m_b_value(b_value) {}
+ B (int b_value, int a_value, A *client_A) : Extra(b_value, a_value), A(a_value, client_A), m_b_value(b_value) {}
+private:
+ int m_b_value;
+};
+
+static A* my_global_A_ptr;
+
+int
+main (int argc, char **argv)
+{
+ my_global_A_ptr = new B (100, 200);
+ B myB (10, 20, my_global_A_ptr);
+ B otherB (300, 400, my_global_A_ptr);
+
+ myB.doSomething(otherB); // Break here and get real addresses of myB and otherB.
+
+ A reallyA (500);
+ myB.doSomething (reallyA); // Break here and get real address of reallyA.
+
+ return 0;
+}
diff --git a/lldb/test/lldbutil.py b/lldb/test/lldbutil.py
index 05813665e0a..998e68dbac9 100644
--- a/lldb/test/lldbutil.py
+++ b/lldb/test/lldbutil.py
@@ -383,3 +383,30 @@ def PrintStackTraces(process, string_buffer = False):
if string_buffer:
return output.getvalue()
+
+def GetThreadsStoppedAtBreakpoint (process, bkpt):
+ """ For a stopped process returns the thread stopped at the breakpoint passed in in bkpt"""
+ stopped_threads = []
+ threads = []
+
+ stopped_threads = get_stopped_threads (process, lldb.eStopReasonBreakpoint)
+
+ if len(stopped_threads) == 0:
+ return threads
+
+ for thread in stopped_threads:
+ # Make sure we've hit our breakpoint...
+ break_id = thread.GetStopReasonDataAtIndex (0)
+ if break_id == bkpt.GetID():
+ threads.append(thread)
+
+ return threads
+
+def ContinueToBreakpoint (process, bkpt):
+ """ Continues the process, when it stops, if there is a thread stopped at bkpt, returns that thread"""
+ process.Continue()
+ if process.GetState() != lldb.eStateStopped:
+ return None
+ else:
+ return GetThreadsStoppedAtBreakpoint (process, bkpt)
+
diff --git a/lldb/test/python_api/process/TestProcessAPI.py b/lldb/test/python_api/process/TestProcessAPI.py
index d00ad19ca09..02dff3c0078 100644
--- a/lldb/test/python_api/process/TestProcessAPI.py
+++ b/lldb/test/python_api/process/TestProcessAPI.py
@@ -209,7 +209,13 @@ class ProcessAPITestCase(TestBase):
if not error.Success() or result != byteSize:
self.fail("SBProcess.WriteMemory() failed")
- # Get the SBValue for the global variable 'my_int' again, with its updated value.
+ # Make sure that the val we got originally updates itself to notice the change:
+ self.expect(val.GetValue(frame),
+ "SBProcess.ReadMemory() successfully writes (int)256 to the memory location for 'my_int'",
+ exe=False,
+ startstr = '256')
+
+ # And for grins, get the SBValue for the global variable 'my_int' again, to make sure that also tracks the new value:
val = frame.FindValue("my_int", lldb.eValueTypeVariableGlobal)
self.expect(val.GetValue(frame),
"SBProcess.ReadMemory() successfully writes (int)256 to the memory location for 'my_int'",
diff --git a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
index cefd565c311..6074fedfa28 100644
--- a/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
+++ b/lldb/tools/debugserver/debugserver.xcodeproj/project.pbxproj
@@ -551,7 +551,6 @@
"-llockdown",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
- PREBINDING = NO;
PRODUCT_NAME = debugserver;
STRIP_INSTALLED_PRODUCT = YES;
USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR)";
@@ -592,7 +591,6 @@
"-llockdown",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
- PREBINDING = NO;
PRODUCT_NAME = debugserver;
"PROVISIONING_PROFILE[sdk=macosx*]" = "";
USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR)";
@@ -633,7 +631,6 @@
"-llockdown",
);
OTHER_MIGFLAGS = "-I$(DERIVED_FILE_DIR)";
- PREBINDING = NO;
PRODUCT_NAME = debugserver;
"PROVISIONING_PROFILE[sdk=macosx*]" = "";
USER_HEADER_SEARCH_PATHS = "./source ../../source $(DERIVED_SOURCES_DIR)";
OpenPOWER on IntegriCloud