From 78a685aa2d8bbf48f25f2f93d4c0a74652eb0e9b Mon Sep 17 00:00:00 2001 From: Jim Ingham Date: Sat, 16 Apr 2011 00:01:13 +0000 Subject: [PATCH] Add support for "dynamic values" for C++ classes. This currently only works for "frame var" and for the expressions that are simple enough to get passed to the "frame var" underpinnings. The parser code will have to be changed to also query for the dynamic types & offsets as it is looking up variables. The behavior of "frame var" is controlled in two ways. You can pass "-d {true/false} to the frame var command to get the dynamic or static value of the variables you are printing. There's also a general setting: target.prefer-dynamic-value (boolean) = 'true' which is consulted if you call "frame var" without supplying a value for the -d option. llvm-svn: 129623 --- lldb/include/lldb/API/SBFrame.h | 21 +- lldb/include/lldb/API/SBValue.h | 8 + lldb/include/lldb/Core/ValueObject.h | 42 ++- .../lldb/Core/ValueObjectConstResult.h | 6 + .../lldb/Core/ValueObjectDynamicValue.h | 105 ++++++ lldb/include/lldb/Core/ValueObjectMemory.h | 73 ++++ lldb/include/lldb/Target/LanguageRuntime.h | 9 +- lldb/include/lldb/Target/StackFrame.h | 7 +- lldb/include/lldb/Target/Target.h | 8 + lldb/lldb.xcodeproj/project.pbxproj | 22 +- lldb/source/API/SBFrame.cpp | 54 ++- lldb/source/API/SBValue.cpp | 34 ++ .../Commands/CommandObjectExpression.cpp | 41 ++- .../source/Commands/CommandObjectExpression.h | 1 + lldb/source/Commands/CommandObjectFrame.cpp | 126 +++++-- lldb/source/Core/ValueObject.cpp | 330 +++++++++++------- lldb/source/Core/ValueObjectChild.cpp | 2 +- lldb/source/Core/ValueObjectDynamicValue.cpp | 254 ++++++++++++++ lldb/source/Core/ValueObjectMemory.cpp | 196 +++++++++++ .../Expression/ClangExpressionDeclMap.cpp | 2 - .../ItaniumABI/ItaniumABILanguageRuntime.cpp | 132 ++++++- .../ItaniumABI/ItaniumABILanguageRuntime.h | 9 +- .../AppleObjCRuntime/AppleObjCRuntime.cpp | 13 +- .../ObjC/AppleObjCRuntime/AppleObjCRuntime.h | 7 +- .../AppleObjCRuntime/AppleObjCRuntimeV1.cpp | 7 +- .../AppleObjCRuntime/AppleObjCRuntimeV1.h | 4 +- .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp | 7 +- .../AppleObjCRuntime/AppleObjCRuntimeV2.h | 4 +- lldb/source/Target/Process.cpp | 8 +- lldb/source/Target/StackFrame.cpp | 37 +- lldb/source/Target/Target.cpp | 73 +++- .../source/Target/ThreadPlanTestCondition.cpp | 4 +- lldb/test/cpp/dynamic-value/Makefile | 5 + .../cpp/dynamic-value/TestDynamicValue.py | 226 ++++++++++++ lldb/test/cpp/dynamic-value/pass-to-base.cpp | 62 ++++ lldb/test/lldbutil.py | 27 ++ .../test/python_api/process/TestProcessAPI.py | 8 +- .../debugserver.xcodeproj/project.pbxproj | 3 - 38 files changed, 1739 insertions(+), 238 deletions(-) create mode 100644 lldb/include/lldb/Core/ValueObjectDynamicValue.h create mode 100644 lldb/include/lldb/Core/ValueObjectMemory.h create mode 100644 lldb/source/Core/ValueObjectDynamicValue.cpp create mode 100644 lldb/source/Core/ValueObjectMemory.cpp create mode 100644 lldb/test/cpp/dynamic-value/Makefile create mode 100644 lldb/test/cpp/dynamic-value/TestDynamicValue.py create mode 100644 lldb/test/cpp/dynamic-value/pass-to-base.cpp diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h index acbbcba49eac..d3222e4c3250 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 08ec657151fc..b8ac830f675f 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 b0a8028fe27e..6dcf6bdba915 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 m_children; std::map 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 6fca731047f3..2c6cbc8d145f 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 000000000000..e87fa94188d3 --- /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 000000000000..4d9a69e65ec7 --- /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 2d193768e646..6005e34e6d34 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 5b1707956aae..af8b317dc6e9 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 f1cb0a8a5c88..0fd68f4aabfd 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 92250ab243d6..66a684010826 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 = ""; }; 4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectApropos.cpp; path = source/Commands/CommandObjectApropos.cpp; sourceTree = ""; }; 4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectApropos.h; path = source/Commands/CommandObjectApropos.h; sourceTree = ""; }; + 4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectMemory.h; path = include/lldb/Core/ValueObjectMemory.h; sourceTree = ""; }; + 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectMemory.cpp; path = source/Core/ValueObjectMemory.cpp; sourceTree = ""; }; 4CAFCE001101216B00CA63DB /* ThreadPlanRunToAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanRunToAddress.h; path = include/lldb/Target/ThreadPlanRunToAddress.h; sourceTree = ""; }; 4CAFCE031101218900CA63DB /* ThreadPlanRunToAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanRunToAddress.cpp; path = source/Target/ThreadPlanRunToAddress.cpp; sourceTree = ""; }; 4CB4430912491DDA00C13DC2 /* LanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LanguageRuntime.h; path = include/lldb/Target/LanguageRuntime.h; sourceTree = ""; }; @@ -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 = ""; }; 4CC2A148128C73ED001531C4 /* ThreadPlanTracer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanTracer.cpp; path = source/Target/ThreadPlanTracer.cpp; sourceTree = ""; }; 4CC2A14C128C7409001531C4 /* ThreadPlanTracer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanTracer.h; path = include/lldb/Target/ThreadPlanTracer.h; sourceTree = ""; }; + 4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectDynamicValue.h; path = include/lldb/Core/ValueObjectDynamicValue.h; sourceTree = ""; }; + 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectDynamicValue.cpp; path = source/Core/ValueObjectDynamicValue.cpp; sourceTree = ""; }; 4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = ""; }; 69A01E1B1236C5D400C660B5 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Condition.cpp; sourceTree = ""; }; 69A01E1C1236C5D400C660B5 /* Host.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Host.cpp; sourceTree = ""; }; @@ -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 e51c2ecfcfb3..93c54108ce72 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -342,6 +342,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) @@ -381,6 +388,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; } } @@ -563,6 +578,17 @@ SBFrame::GetVariables (bool arguments, bool locals, 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)); @@ -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)); } } } @@ -679,6 +705,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()); @@ -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 a607841a527b..640117898786 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -338,6 +338,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; @@ -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) @@ -373,6 +390,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 7b9f01cd3c88..82d2197e7cc0 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 6eff72c0045d..71eb9bf8ea11 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 51299c2aaf34..bdcd7039b999 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; iGetVariableAtIndex(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 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 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 eeb3ac082d9d..d95806cf1929 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 child_indexes; - clang::ASTContext *clang_ast = GetClangAST(); - void *clang_type = GetClangType(); - bool omit_empty_base_classes = true; - const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast, - clang_type, - name.GetCString(), - omit_empty_base_classes, - child_indexes); ValueObjectSP child_sp; - if (num_child_indexes > 0) + + if (UpdateValueIfNeeded()) { - std::vector::const_iterator pos = child_indexes.begin (); - std::vector::const_iterator end = child_indexes.end (); - - child_sp = GetChildAtIndex(*pos, can_create); - for (++pos; pos != end; ++pos) + std::vector child_indexes; + clang::ASTContext *clang_ast = GetClangAST(); + void *clang_type = GetClangType(); + bool omit_empty_base_classes = true; + const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast, + clang_type, + name.GetCString(), + omit_empty_base_classes, + child_indexes); + if (num_child_indexes > 0) { - if (child_sp) - { - ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create)); - child_sp = new_child_sp; - } - else - { - child_sp.reset(); - } + std::vector::const_iterator pos = child_indexes.begin (); + std::vector::const_iterator end = child_indexes.end (); + child_sp = GetChildAtIndex(*pos, can_create); + for (++pos; pos != end; ++pos) + { + if (child_sp) + { + ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create)); + child_sp = new_child_sp; + } + else + { + child_sp.reset(); + } + + } } } return child_sp; @@ -378,55 +381,60 @@ 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; + bool omit_empty_base_classes = true; - ConstString child_name; - if (!child_name_str.empty()) - child_name.SetCString (child_name_str.c_str()); + std::string child_name_str; + uint32_t child_byte_size = 0; + int32_t child_byte_offset = 0; + uint32_t child_bitfield_bit_size = 0; + uint32_t child_bitfield_bit_offset = 0; + bool child_is_base_class = false; + bool child_is_deref_of_parent = false; - valobj_sp.reset (new ValueObjectChild (*this, - clang_ast, - child_clang_type, - child_name, - child_byte_size, - child_byte_offset, - child_bitfield_bit_size, - child_bitfield_bit_offset, - child_is_base_class, - child_is_deref_of_parent)); - if (m_pointers_point_to_load_addrs) - valobj_sp->SetPointersPointToLoadAddrs (m_pointers_point_to_load_addrs); + const bool transparent_pointers = synthetic_array_member == false; + clang::ASTContext *clang_ast = GetClangAST(); + clang_type_t clang_type = GetClangType(); + clang_type_t child_clang_type; + child_clang_type = ClangASTContext::GetChildClangTypeAtIndex (clang_ast, + GetName().GetCString(), + clang_type, + idx, + transparent_pointers, + omit_empty_base_classes, + child_name_str, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent); + if (child_clang_type && child_byte_size) + { + if (synthetic_index) + child_byte_offset += child_byte_size * synthetic_index; + + ConstString child_name; + if (!child_name_str.empty()) + child_name.SetCString (child_name_str.c_str()); + + valobj_sp.reset (new ValueObjectChild (*this, + clang_ast, + child_clang_type, + child_name, + child_byte_size, + child_byte_offset, + child_bitfield_bit_size, + child_bitfield_bit_offset, + child_is_base_class, + child_is_deref_of_parent)); + if (m_pointers_point_to_load_addrs) + valobj_sp->SetPointersPointToLoadAddrs (m_pointers_point_to_load_addrs); + } } + return valobj_sp; } @@ -710,6 +718,9 @@ 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(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(""), 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 fc5f6c850f5a..509852f4b3a3 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 000000000000..2b80ae513e37 --- /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 (""); +// +// 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(""); + + 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 000000000000..d3998488ebaa --- /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 99f0e60a0f08..0054a03967bf 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 b0f7733c2cd0..fb4c98dc4419 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) { - ValueObjectSP ret_sp; - return ret_sp; + return in_value.IsPointerOrReferenceType(); +} + +bool +ItaniumABILanguageRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &dynamic_type_sp, Address &dynamic_address) +{ + // For Itanium, if the type has a vtable pointer in the object, it will be at offset 0 + // in the object. That will point to the "address point" within the vtable (not the beginning of the + // vtable.) We can then look up the symbol containing this "address point" and that symbol's name + // demangled will contain the full class name. + // The second pointer above the "address point" is the "offset_to_top". We'll use that to get the + // start of the value object which holds the dynamic type. + // + + // Only a pointer or reference type can have a different dynamic and static type: + if (CouldHaveDynamicValue (in_value)) + { + // FIXME: Can we get the Clang Type and ask it if the thing is really virtual? That would avoid false positives, + // at the cost of not looking for the dynamic type of objects if DWARF->Clang gets it wrong. + + // First job, pull out the address at 0 offset from the object. + AddressType address_type; + lldb::addr_t original_ptr = in_value.GetPointerValue(address_type, true); + if (original_ptr == LLDB_INVALID_ADDRESS) + return false; + + Target *target = in_value.GetUpdatePoint().GetTarget(); + Process *process = in_value.GetUpdatePoint().GetProcess(); + + char memory_buffer[16]; + DataExtractor data(memory_buffer, sizeof(memory_buffer), + process->GetByteOrder(), + process->GetAddressByteSize()); + size_t address_byte_size = process->GetAddressByteSize(); + Error error; + size_t bytes_read = process->ReadMemory (original_ptr, + memory_buffer, + address_byte_size, + error); + if (!error.Success() || (bytes_read != address_byte_size)) + { + return false; + } + + uint32_t offset_ptr = 0; + lldb::addr_t vtable_address_point = data.GetAddress (&offset_ptr); + + if (offset_ptr == 0) + return false; + + // Now find the symbol that contains this address: + + SymbolContext sc; + Address address_point_address; + if (target && !target->GetSectionLoadList().IsEmpty()) + { + if (target->GetSectionLoadList().ResolveLoadAddress (vtable_address_point, address_point_address)) + { + target->GetImages().ResolveSymbolContextForAddress (address_point_address, eSymbolContextSymbol, sc); + Symbol *symbol = sc.symbol; + if (symbol != NULL) + { + const char *name = symbol->GetMangled().GetDemangledName().AsCString(); + if (strstr(name, vtable_demangled_prefix) == name) + { + // We are a C++ class, that's good. Get the class name and look it up: + const char *class_name = name + strlen(vtable_demangled_prefix); + TypeList class_types; + uint32_t num_matches = target->GetImages().FindTypes (sc, + ConstString(class_name), + true, + UINT32_MAX, + class_types); + if (num_matches == 1) + { + dynamic_type_sp = class_types.GetTypeAtIndex(0); + } + else if (num_matches > 1) + { + // How to sort out which of the type matches to pick? + } + + if (!dynamic_type_sp) + return false; + + // The offset_to_top is two pointers above the address. + Address offset_to_top_address = address_point_address; + int64_t slide = -2 * ((int64_t) target->GetArchitecture().GetAddressByteSize()); + offset_to_top_address.Slide (slide); + + Error error; + lldb::addr_t offset_to_top_location = offset_to_top_address.GetLoadAddress(target); + + size_t bytes_read = process->ReadMemory (offset_to_top_location, + memory_buffer, + address_byte_size, + error); + + if (!error.Success() || (bytes_read != address_byte_size)) + { + return false; + } + + offset_ptr = 0; + int64_t offset_to_top = data.GetMaxS64(&offset_ptr, process->GetAddressByteSize()); + + // So the dynamic type is a value that starts at offset_to_top + // above the original address. + lldb::addr_t dynamic_addr = original_ptr + offset_to_top; + if (!target->GetSectionLoadList().ResolveLoadAddress (dynamic_addr, dynamic_address)) + { + dynamic_address.SetOffset(dynamic_addr); + dynamic_address.SetSection(NULL); + } + return true; + } + } + } + } + + } + + return false; } bool diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.h index d7ac04adc200..421ac12725f6 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 392abeeaebfe..08af0b684319 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) { - lldb::ValueObjectSP ret_sp; - return ret_sp; + return in_value.IsPointerType(); +} + +bool +AppleObjCRuntime::GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address) +{ + return false; } bool diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntime.h index 1c500e39be17..e7e0f71d9568 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 467475711985..000f14e3df19 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 2b815b18091a..975c018b4e9a 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 5d276dcd02d1..c6e3533a09dc 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 d2bd414bfc3b..0015dd2f424c 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 26d84b968dc3..a492e47642db 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 0d0c0e8ec613..a5df9284b55c 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 2ade9e661429..d08a0fe2bd11 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 9facfdcb95c9..1349e9eb6490 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 000000000000..ceb406ee2eab --- /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 000000000000..78b2f22208ff --- /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 000000000000..83ab1617f711 --- /dev/null +++ b/lldb/test/cpp/dynamic-value/pass-to-base.cpp @@ -0,0 +1,62 @@ +#include +#include + +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 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 05813665e0aa..998e68dbac97 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 d00ad19ca09f..02dff3c00786 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 cefd565c3117..6074fedfa280 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)";