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)";