forked from OSchip/llvm-project
Add support for "dynamic values" for C++ classes. This currently only works for "frame var" and for the
expressions that are simple enough to get passed to the "frame var" underpinnings. The parser code will have to be changed to also query for the dynamic types & offsets as it is looking up variables. The behavior of "frame var" is controlled in two ways. You can pass "-d {true/false} to the frame var command to get the dynamic or static value of the variables you are printing. There's also a general setting: target.prefer-dynamic-value (boolean) = 'true' which is consulted if you call "frame var" without supplying a value for the -d option. llvm-svn: 129623
This commit is contained in:
parent
f46b33852c
commit
78a685aa2d
|
@ -71,9 +71,13 @@ 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);
|
||||
|
||||
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
|
||||
// for a stack frame. Inlined functions are represented as SBBlock objects
|
||||
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 ();
|
||||
|
||||
|
|
|
@ -325,9 +325,6 @@ public:
|
|||
bool
|
||||
UpdateValueIfNeeded ();
|
||||
|
||||
const DataExtractor &
|
||||
GetDataExtractor () const;
|
||||
|
||||
DataExtractor &
|
||||
GetDataExtractor ();
|
||||
|
||||
|
@ -345,10 +342,10 @@ public:
|
|||
GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetDynamicValue ()
|
||||
{
|
||||
return m_dynamic_value_sp;
|
||||
}
|
||||
GetDynamicValue (bool can_create);
|
||||
|
||||
lldb::ValueObjectSP
|
||||
GetDynamicValue (bool can_create, lldb::ValueObjectSP &owning_valobj_sp);
|
||||
|
||||
virtual lldb::ValueObjectSP
|
||||
CreateConstantValue (const ConstString &name);
|
||||
|
@ -369,8 +366,11 @@ public:
|
|||
m_object_desc_str.clear();
|
||||
}
|
||||
|
||||
bool
|
||||
SetDynamicValue ();
|
||||
virtual bool
|
||||
IsDynamic ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
DumpValueObject (Stream &s,
|
||||
|
@ -382,6 +382,7 @@ public:
|
|||
bool show_types,
|
||||
bool show_location,
|
||||
bool use_objc,
|
||||
bool use_dynamic,
|
||||
bool scope_already_checked,
|
||||
bool flat_output);
|
||||
|
||||
|
@ -411,13 +412,16 @@ public:
|
|||
m_format = format;
|
||||
}
|
||||
|
||||
ValueObject *
|
||||
// Use GetParent for display purposes, but if you want to tell the parent to update itself
|
||||
// then use m_parent. The ValueObjectDynamicValue's parent is not the correct parent for
|
||||
// displaying, they are really siblings, so for display it needs to route through to its grandparent.
|
||||
virtual ValueObject *
|
||||
GetParent()
|
||||
{
|
||||
return m_parent;
|
||||
}
|
||||
|
||||
const ValueObject *
|
||||
virtual const ValueObject *
|
||||
GetParent() const
|
||||
{
|
||||
return m_parent;
|
||||
|
@ -436,8 +440,8 @@ protected:
|
|||
//------------------------------------------------------------------
|
||||
// Classes that inherit from ValueObject can see and modify these
|
||||
//------------------------------------------------------------------
|
||||
ValueObject* m_parent; // The parent value object, or NULL if this has no parent
|
||||
EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
|
||||
ValueObject *m_parent; // The parent value object, or NULL if this has no parent
|
||||
EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
|
||||
// updated. When we are asked to update the value object, we check whether
|
||||
// the context & stop id are the same before updating.
|
||||
ConstString m_name; // The name of this object
|
||||
|
@ -453,6 +457,10 @@ protected:
|
|||
std::vector<lldb::ValueObjectSP> m_children;
|
||||
std::map<ConstString, lldb::ValueObjectSP> m_synthetic_children;
|
||||
lldb::ValueObjectSP m_dynamic_value_sp;
|
||||
lldb::ValueObjectSP m_addr_of_valobj_sp; // These two shared pointers help root the ValueObject shared pointers that
|
||||
lldb::ValueObjectSP m_deref_valobj_sp; // we hand out, so that we can use them in their dynamic types and ensure
|
||||
// they will last as long as this ValueObject...
|
||||
|
||||
lldb::Format m_format;
|
||||
bool m_value_is_valid:1,
|
||||
m_value_did_change:1,
|
||||
|
@ -463,6 +471,7 @@ protected:
|
|||
|
||||
friend class CommandObjectExpression;
|
||||
friend class ClangExpressionVariable;
|
||||
friend class ClangExpressionDeclMap; // For GetValue...
|
||||
friend class Target;
|
||||
friend class ValueObjectChild;
|
||||
//------------------------------------------------------------------
|
||||
|
@ -486,6 +495,9 @@ protected:
|
|||
virtual bool
|
||||
UpdateValue () = 0;
|
||||
|
||||
virtual void
|
||||
CalculateDynamicValue ();
|
||||
|
||||
// Should only be called by ValueObject::GetChildAtIndex()
|
||||
virtual lldb::ValueObjectSP
|
||||
CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index);
|
||||
|
@ -509,7 +521,7 @@ protected:
|
|||
void
|
||||
SetValueIsValid (bool valid);
|
||||
|
||||
|
||||
public:
|
||||
lldb::addr_t
|
||||
GetPointerValue (AddressType &address_type,
|
||||
bool scalar_is_load_address);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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_
|
|
@ -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_
|
|
@ -42,8 +42,13 @@ 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 ()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 &
|
||||
|
|
|
@ -408,6 +408,10 @@
|
|||
26F5C37510F3F61B009D5894 /* libobjc.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C37410F3F61B009D5894 /* libobjc.dylib */; };
|
||||
26F5C39110F3FA26009D5894 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26F5C39010F3FA26009D5894 /* CoreFoundation.framework */; };
|
||||
4C74CB6312288704006A8171 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4C74CB6212288704006A8171 /* Carbon.framework */; };
|
||||
4CABA9DD134A8BA800539BDD /* ValueObjectMemory.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */; };
|
||||
4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */; };
|
||||
4CD0BD0D134BFAB600CB44D4 /* ValueObjectDynamicValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */; };
|
||||
4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; };
|
||||
9A19A6AF1163BBB200E0D453 /* SBValue.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A19A6A51163BB7E00E0D453 /* SBValue.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
9A19A6B01163BBB300E0D453 /* SBValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9A19A6AD1163BB9800E0D453 /* SBValue.cpp */; };
|
||||
9A357583116CFDEE00E8ED2F /* SBValueList.h in Headers */ = {isa = PBXBuildFile; fileRef = 9A357582116CFDEE00E8ED2F /* SBValueList.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
|
@ -1103,6 +1107,8 @@
|
|||
4C98D3E1118FB98F00E575D0 /* RecordingMemoryManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RecordingMemoryManager.h; path = include/lldb/Expression/RecordingMemoryManager.h; sourceTree = "<group>"; };
|
||||
4CA9637911B6E99A00780E28 /* CommandObjectApropos.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CommandObjectApropos.cpp; path = source/Commands/CommandObjectApropos.cpp; sourceTree = "<group>"; };
|
||||
4CA9637A11B6E99A00780E28 /* CommandObjectApropos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CommandObjectApropos.h; path = source/Commands/CommandObjectApropos.h; sourceTree = "<group>"; };
|
||||
4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectMemory.h; path = include/lldb/Core/ValueObjectMemory.h; sourceTree = "<group>"; };
|
||||
4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectMemory.cpp; path = source/Core/ValueObjectMemory.cpp; sourceTree = "<group>"; };
|
||||
4CAFCE001101216B00CA63DB /* ThreadPlanRunToAddress.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanRunToAddress.h; path = include/lldb/Target/ThreadPlanRunToAddress.h; sourceTree = "<group>"; };
|
||||
4CAFCE031101218900CA63DB /* ThreadPlanRunToAddress.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanRunToAddress.cpp; path = source/Target/ThreadPlanRunToAddress.cpp; sourceTree = "<group>"; };
|
||||
4CB4430912491DDA00C13DC2 /* LanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = LanguageRuntime.h; path = include/lldb/Target/LanguageRuntime.h; sourceTree = "<group>"; };
|
||||
|
@ -1115,6 +1121,8 @@
|
|||
4CB443F612499B6E00C13DC2 /* ObjCLanguageRuntime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ObjCLanguageRuntime.h; path = include/lldb/Target/ObjCLanguageRuntime.h; sourceTree = "<group>"; };
|
||||
4CC2A148128C73ED001531C4 /* ThreadPlanTracer.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ThreadPlanTracer.cpp; path = source/Target/ThreadPlanTracer.cpp; sourceTree = "<group>"; };
|
||||
4CC2A14C128C7409001531C4 /* ThreadPlanTracer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanTracer.h; path = include/lldb/Target/ThreadPlanTracer.h; sourceTree = "<group>"; };
|
||||
4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectDynamicValue.h; path = include/lldb/Core/ValueObjectDynamicValue.h; sourceTree = "<group>"; };
|
||||
4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectDynamicValue.cpp; path = source/Core/ValueObjectDynamicValue.cpp; sourceTree = "<group>"; };
|
||||
4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
|
||||
69A01E1B1236C5D400C660B5 /* Condition.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Condition.cpp; sourceTree = "<group>"; };
|
||||
69A01E1C1236C5D400C660B5 /* Host.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Host.cpp; sourceTree = "<group>"; };
|
||||
|
@ -1902,8 +1910,12 @@
|
|||
26BC7E9B10F1B85900F91463 /* ValueObjectChild.cpp */,
|
||||
26424E3E125986D30016D82C /* ValueObjectConstResult.h */,
|
||||
26424E3C125986CB0016D82C /* ValueObjectConstResult.cpp */,
|
||||
4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */,
|
||||
4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */,
|
||||
26BC7D8410F1B77400F91463 /* ValueObjectList.h */,
|
||||
26BC7E9C10F1B85900F91463 /* ValueObjectList.cpp */,
|
||||
4CABA9DC134A8BA700539BDD /* ValueObjectMemory.h */,
|
||||
4CABA9DF134A8BCD00539BDD /* ValueObjectMemory.cpp */,
|
||||
2643343A1110F63C00CDB6C6 /* ValueObjectRegister.h */,
|
||||
264334381110F63100CDB6C6 /* ValueObjectRegister.cpp */,
|
||||
26BC7D8510F1B77400F91463 /* ValueObjectVariable.h */,
|
||||
|
@ -2550,6 +2562,8 @@
|
|||
26651A16133BF9CD005B64B7 /* Opcode.h in Headers */,
|
||||
266603CD1345B5C0004DA8B6 /* ConnectionSharedMemory.h in Headers */,
|
||||
2671A0CE134825F6003A87BB /* ConnectionMachPort.h in Headers */,
|
||||
4CABA9DD134A8BA800539BDD /* ValueObjectMemory.h in Headers */,
|
||||
4CD0BD0D134BFAB600CB44D4 /* ValueObjectDynamicValue.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3114,6 +3128,8 @@
|
|||
26651A18133BF9E0005B64B7 /* Opcode.cpp in Sources */,
|
||||
266603CA1345B5A8004DA8B6 /* ConnectionSharedMemory.cpp in Sources */,
|
||||
2671A0D013482601003A87BB /* ConnectionMachPort.cpp in Sources */,
|
||||
4CABA9E0134A8BCD00539BDD /* ValueObjectMemory.cpp in Sources */,
|
||||
4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
@ -3209,7 +3225,6 @@
|
|||
LLVM_CONFIGURATION = Release;
|
||||
LLVM_SOURCE_DIR = "$(SRCROOT)/llvm";
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
PREBINDING = NO;
|
||||
VALID_ARCHS = "x86_64 i386";
|
||||
};
|
||||
name = Debug;
|
||||
|
@ -3251,7 +3266,6 @@
|
|||
COPY_PHASE_STRIP = NO;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
INSTALL_PATH = /Developer/usr/bin;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
|
@ -3265,7 +3279,6 @@
|
|||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
COPY_PHASE_STRIP = YES;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
INSTALL_PATH = /Developer/usr/bin;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_NAME = "darwin-debug";
|
||||
|
@ -3277,7 +3290,6 @@
|
|||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
INSTALL_PATH = /Developer/usr/bin;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
PRODUCT_NAME = "darwin-debug";
|
||||
|
@ -3542,7 +3554,6 @@
|
|||
"$(inherited)",
|
||||
"\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
|
||||
);
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
|
@ -3730,7 +3741,6 @@
|
|||
"$(inherited)",
|
||||
"\"$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks\"",
|
||||
);
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = NO;
|
||||
GCC_INLINES_ARE_PRIVATE_EXTERN = NO;
|
||||
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
|
||||
HEADER_SEARCH_PATHS = "";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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."},
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
@ -511,6 +555,7 @@ public:
|
|||
m_options.show_types,
|
||||
m_options.show_location,
|
||||
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,7 +598,7 @@ 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)
|
||||
|
@ -572,6 +619,7 @@ public:
|
|||
m_options.show_types,
|
||||
m_options.show_location,
|
||||
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);
|
||||
|
||||
|
@ -616,6 +674,7 @@ public:
|
|||
m_options.show_types,
|
||||
m_options.show_location,
|
||||
m_options.use_objc,
|
||||
use_dynamic,
|
||||
false,
|
||||
m_options.flat_output);
|
||||
}
|
||||
|
@ -639,6 +698,7 @@ public:
|
|||
for (uint32_t i=0; i<num_variables; i++)
|
||||
{
|
||||
var_sp = variable_list->GetVariableAtIndex(i);
|
||||
|
||||
bool dump_variable = true;
|
||||
|
||||
switch (var_sp->GetScope())
|
||||
|
@ -677,7 +737,7 @@ public:
|
|||
// Use the variable object code to make sure we are
|
||||
// using the same APIs as the the public API will be
|
||||
// using...
|
||||
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
|
||||
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
|
||||
if (valobj_sp)
|
||||
{
|
||||
if (m_options.format != eFormatDefault)
|
||||
|
@ -701,6 +761,7 @@ public:
|
|||
m_options.show_types,
|
||||
m_options.show_location,
|
||||
m_options.use_objc,
|
||||
use_dynamic,
|
||||
false,
|
||||
m_options.flat_output);
|
||||
}
|
||||
|
@ -722,22 +783,23 @@ protected:
|
|||
OptionDefinition
|
||||
CommandObjectFrameVariable::CommandOptions::g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug information."},
|
||||
{ LLDB_OPT_SET_1, false, "depth", 'd', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
|
||||
{ LLDB_OPT_SET_1, false, "show-globals",'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
|
||||
{ LLDB_OPT_SET_1, false, "find-global",'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
|
||||
{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
|
||||
{ LLDB_OPT_SET_1, false, "show-declaration", 'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
|
||||
{ LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
|
||||
{ LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
|
||||
{ LLDB_OPT_SET_1, false, "show-types", 't', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
|
||||
{ LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
|
||||
{ LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
|
||||
{ LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, eArgTypeNone, "When looking up a variable by name, print as an Objective-C object."},
|
||||
{ LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
|
||||
{ LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
|
||||
{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
|
||||
{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the variable output should use."},
|
||||
{ LLDB_OPT_SET_1, false, "aggregate-depth", 'A', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
|
||||
{ LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
|
||||
{ LLDB_OPT_SET_1, false, "show-declaration",'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
|
||||
{ LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug information."},
|
||||
{ LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, NULL, 0, eArgTypeBoolean, "Show the object as its full dynamic type, not its static type, if available."},
|
||||
{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the variable output should use."},
|
||||
{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
|
||||
{ LLDB_OPT_SET_1, false, "show-globals", 'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
|
||||
{ LLDB_OPT_SET_1, false, "find-global", 'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
|
||||
{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
|
||||
{ LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
|
||||
{ LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, eArgTypeNone, "When looking up a variable by name, print as an Objective-C object."},
|
||||
{ LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
|
||||
{ LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
|
||||
{ LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
|
||||
{ LLDB_OPT_SET_1, false, "show-types", 't', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
|
||||
{ LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
|
||||
{ 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
|
||||
};
|
||||
#pragma mark CommandObjectMultiwordFrame
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/ValueObjectChild.h"
|
||||
#include "lldb/Core/ValueObjectConstResult.h"
|
||||
#include "lldb/Core/ValueObjectDynamicValue.h"
|
||||
#include "lldb/Core/ValueObjectList.h"
|
||||
|
||||
#include "lldb/Host/Endian.h"
|
||||
|
@ -159,15 +160,10 @@ ValueObject::UpdateValueIfNeeded ()
|
|||
return m_error.Success();
|
||||
}
|
||||
|
||||
const DataExtractor &
|
||||
ValueObject::GetDataExtractor () const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
DataExtractor &
|
||||
ValueObject::GetDataExtractor ()
|
||||
{
|
||||
UpdateValueIfNeeded();
|
||||
return m_data;
|
||||
}
|
||||
|
||||
|
@ -281,17 +277,20 @@ ValueObjectSP
|
|||
ValueObject::GetChildAtIndex (uint32_t idx, bool can_create)
|
||||
{
|
||||
ValueObjectSP child_sp;
|
||||
if (idx < GetNumChildren())
|
||||
if (UpdateValueIfNeeded())
|
||||
{
|
||||
// Check if we have already made the child value object?
|
||||
if (can_create && m_children[idx].get() == NULL)
|
||||
if (idx < GetNumChildren())
|
||||
{
|
||||
// No we haven't created the child at this index, so lets have our
|
||||
// subclass do it and cache the result for quick future access.
|
||||
m_children[idx] = CreateChildAtIndex (idx, false, 0);
|
||||
}
|
||||
// Check if we have already made the child value object?
|
||||
if (can_create && m_children[idx].get() == NULL)
|
||||
{
|
||||
// No we haven't created the child at this index, so lets have our
|
||||
// subclass do it and cache the result for quick future access.
|
||||
m_children[idx] = CreateChildAtIndex (idx, false, 0);
|
||||
}
|
||||
|
||||
child_sp = m_children[idx];
|
||||
child_sp = m_children[idx];
|
||||
}
|
||||
}
|
||||
return child_sp;
|
||||
}
|
||||
|
@ -312,34 +311,38 @@ ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
|
|||
// when getting a child by name, it could be buried inside some base
|
||||
// classes (which really aren't part of the expression path), so we
|
||||
// need a vector of indexes that can get us down to the correct child
|
||||
std::vector<uint32_t> child_indexes;
|
||||
clang::ASTContext *clang_ast = GetClangAST();
|
||||
void *clang_type = GetClangType();
|
||||
bool omit_empty_base_classes = true;
|
||||
const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast,
|
||||
clang_type,
|
||||
name.GetCString(),
|
||||
omit_empty_base_classes,
|
||||
child_indexes);
|
||||
ValueObjectSP child_sp;
|
||||
if (num_child_indexes > 0)
|
||||
|
||||
if (UpdateValueIfNeeded())
|
||||
{
|
||||
std::vector<uint32_t>::const_iterator pos = child_indexes.begin ();
|
||||
std::vector<uint32_t>::const_iterator end = child_indexes.end ();
|
||||
|
||||
child_sp = GetChildAtIndex(*pos, can_create);
|
||||
for (++pos; pos != end; ++pos)
|
||||
std::vector<uint32_t> child_indexes;
|
||||
clang::ASTContext *clang_ast = GetClangAST();
|
||||
void *clang_type = GetClangType();
|
||||
bool omit_empty_base_classes = true;
|
||||
const size_t num_child_indexes = ClangASTContext::GetIndexOfChildMemberWithName (clang_ast,
|
||||
clang_type,
|
||||
name.GetCString(),
|
||||
omit_empty_base_classes,
|
||||
child_indexes);
|
||||
if (num_child_indexes > 0)
|
||||
{
|
||||
if (child_sp)
|
||||
{
|
||||
ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create));
|
||||
child_sp = new_child_sp;
|
||||
}
|
||||
else
|
||||
{
|
||||
child_sp.reset();
|
||||
}
|
||||
std::vector<uint32_t>::const_iterator pos = child_indexes.begin ();
|
||||
std::vector<uint32_t>::const_iterator end = child_indexes.end ();
|
||||
|
||||
child_sp = GetChildAtIndex(*pos, can_create);
|
||||
for (++pos; pos != end; ++pos)
|
||||
{
|
||||
if (child_sp)
|
||||
{
|
||||
ValueObjectSP new_child_sp(child_sp->GetChildAtIndex (*pos, can_create));
|
||||
child_sp = new_child_sp;
|
||||
}
|
||||
else
|
||||
{
|
||||
child_sp.reset();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
return child_sp;
|
||||
|
@ -378,55 +381,60 @@ 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<ValueObjectDynamicValue *>(m_dynamic_value_sp.get());
|
||||
as_dynamic_value->SetOwningSP (owning_valobj_sp);
|
||||
}
|
||||
}
|
||||
return m_dynamic_value_sp;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -974,7 +1039,7 @@ ValueObject::GetBaseClassPath (Stream &s)
|
|||
{
|
||||
if (IsBaseClass())
|
||||
{
|
||||
bool parent_had_base_class = m_parent && m_parent->GetBaseClassPath (s);
|
||||
bool parent_had_base_class = GetParent() && GetParent()->GetBaseClassPath (s);
|
||||
clang_type_t clang_type = GetClangType();
|
||||
std::string cxx_class_name;
|
||||
bool this_had_base_class = ClangASTContext::GetCXXClassName (clang_type, cxx_class_name);
|
||||
|
@ -993,12 +1058,12 @@ ValueObject::GetBaseClassPath (Stream &s)
|
|||
ValueObject *
|
||||
ValueObject::GetNonBaseClassParent()
|
||||
{
|
||||
if (m_parent)
|
||||
if (GetParent())
|
||||
{
|
||||
if (m_parent->IsBaseClass())
|
||||
return m_parent->GetNonBaseClassParent();
|
||||
if (GetParent()->IsBaseClass())
|
||||
return GetParent()->GetNonBaseClassParent();
|
||||
else
|
||||
return m_parent;
|
||||
return GetParent();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1011,8 +1076,8 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes)
|
|||
if (is_deref_of_parent)
|
||||
s.PutCString("*(");
|
||||
|
||||
if (m_parent)
|
||||
m_parent->GetExpressionPath (s, qualify_cxx_base_classes);
|
||||
if (GetParent())
|
||||
GetParent()->GetExpressionPath (s, qualify_cxx_base_classes);
|
||||
|
||||
if (!IsBaseClass())
|
||||
{
|
||||
|
@ -1067,12 +1132,20 @@ ValueObject::DumpValueObject
|
|||
bool show_types,
|
||||
bool show_location,
|
||||
bool use_objc,
|
||||
bool use_dynamic,
|
||||
bool scope_already_checked,
|
||||
bool flat_output
|
||||
)
|
||||
{
|
||||
if (valobj && valobj->UpdateValueIfNeeded ())
|
||||
{
|
||||
if (use_dynamic)
|
||||
{
|
||||
ValueObject *dynamic_value = valobj->GetDynamicValue(true).get();
|
||||
if (dynamic_value)
|
||||
valobj = dynamic_value;
|
||||
}
|
||||
|
||||
clang_type_t clang_type = valobj->GetClangType();
|
||||
|
||||
const Flags type_flags (ClangASTContext::GetTypeInfo (clang_type, NULL, NULL));
|
||||
|
@ -1216,6 +1289,7 @@ ValueObject::DumpValueObject
|
|||
show_types,
|
||||
show_location,
|
||||
false,
|
||||
use_dynamic,
|
||||
true,
|
||||
flat_output);
|
||||
}
|
||||
|
@ -1296,7 +1370,9 @@ ValueObject::CreateConstantValue (const ConstString &name)
|
|||
lldb::ValueObjectSP
|
||||
ValueObject::Dereference (Error &error)
|
||||
{
|
||||
lldb::ValueObjectSP valobj_sp;
|
||||
if (m_deref_valobj_sp)
|
||||
return m_deref_valobj_sp;
|
||||
|
||||
const bool is_pointer_type = IsPointerType();
|
||||
if (is_pointer_type)
|
||||
{
|
||||
|
@ -1332,20 +1408,20 @@ ValueObject::Dereference (Error &error)
|
|||
if (!child_name_str.empty())
|
||||
child_name.SetCString (child_name_str.c_str());
|
||||
|
||||
valobj_sp.reset (new ValueObjectChild (*this,
|
||||
clang_ast,
|
||||
child_clang_type,
|
||||
child_name,
|
||||
child_byte_size,
|
||||
child_byte_offset,
|
||||
child_bitfield_bit_size,
|
||||
child_bitfield_bit_offset,
|
||||
child_is_base_class,
|
||||
child_is_deref_of_parent));
|
||||
m_deref_valobj_sp.reset (new ValueObjectChild (*this,
|
||||
clang_ast,
|
||||
child_clang_type,
|
||||
child_name,
|
||||
child_byte_size,
|
||||
child_byte_offset,
|
||||
child_bitfield_bit_size,
|
||||
child_bitfield_bit_offset,
|
||||
child_is_base_class,
|
||||
child_is_deref_of_parent));
|
||||
}
|
||||
}
|
||||
|
||||
if (valobj_sp)
|
||||
if (m_deref_valobj_sp)
|
||||
{
|
||||
error.Clear();
|
||||
}
|
||||
|
@ -1360,13 +1436,15 @@ ValueObject::Dereference (Error &error)
|
|||
error.SetErrorStringWithFormat("not a pointer type: (%s) %s", GetTypeName().AsCString("<invalid type>"), strm.GetString().c_str());
|
||||
}
|
||||
|
||||
return valobj_sp;
|
||||
return m_deref_valobj_sp;
|
||||
}
|
||||
|
||||
lldb::ValueObjectSP
|
||||
lldb::ValueObjectSP
|
||||
ValueObject::AddressOf (Error &error)
|
||||
{
|
||||
lldb::ValueObjectSP valobj_sp;
|
||||
if (m_addr_of_valobj_sp)
|
||||
return m_addr_of_valobj_sp;
|
||||
|
||||
AddressType address_type = eAddressTypeInvalid;
|
||||
const bool scalar_is_load_address = false;
|
||||
lldb::addr_t addr = GetAddressOf (address_type, scalar_is_load_address);
|
||||
|
@ -1394,19 +1472,19 @@ ValueObject::AddressOf (Error &error)
|
|||
{
|
||||
std::string name (1, '&');
|
||||
name.append (m_name.AsCString(""));
|
||||
valobj_sp.reset (new ValueObjectConstResult (GetExecutionContextScope(),
|
||||
ast,
|
||||
ClangASTContext::CreatePointerType (ast, clang_type),
|
||||
ConstString (name.c_str()),
|
||||
addr,
|
||||
eAddressTypeInvalid,
|
||||
m_data.GetAddressByteSize()));
|
||||
m_addr_of_valobj_sp.reset (new ValueObjectConstResult (GetExecutionContextScope(),
|
||||
ast,
|
||||
ClangASTContext::CreatePointerType (ast, clang_type),
|
||||
ConstString (name.c_str()),
|
||||
addr,
|
||||
eAddressTypeInvalid,
|
||||
m_data.GetAddressByteSize()));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return valobj_sp;
|
||||
return m_addr_of_valobj_sp;
|
||||
}
|
||||
|
||||
ValueObject::EvaluationPoint::EvaluationPoint () :
|
||||
|
@ -1523,10 +1601,16 @@ ValueObject::EvaluationPoint::SyncWithProcessState()
|
|||
return false;
|
||||
|
||||
// If our stop id is the current stop ID, nothing has changed:
|
||||
if (m_stop_id == m_process_sp->GetStopID())
|
||||
uint32_t cur_stop_id = m_process_sp->GetStopID();
|
||||
if (m_stop_id == cur_stop_id)
|
||||
return false;
|
||||
|
||||
m_stop_id = m_process_sp->GetStopID();
|
||||
// If the current stop id is 0, either we haven't run yet, or the process state has been cleared.
|
||||
// In either case, we aren't going to be able to sync with the process state.
|
||||
if (cur_stop_id == 0)
|
||||
return false;
|
||||
|
||||
m_stop_id = cur_stop_id;
|
||||
m_needs_update = true;
|
||||
m_exe_scope = m_process_sp.get();
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -0,0 +1,254 @@
|
|||
//===-- ValueObjectDynamicValue.cpp ---------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#include "lldb/Core/ValueObjectDynamicValue.h"
|
||||
|
||||
// C Includes
|
||||
// C++ Includes
|
||||
// Other libraries and framework includes
|
||||
// Project includes
|
||||
#include "lldb/Core/Module.h"
|
||||
#include "lldb/Core/ValueObjectList.h"
|
||||
#include "lldb/Core/Value.h"
|
||||
#include "lldb/Core/ValueObject.h"
|
||||
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Symbol/SymbolContext.h"
|
||||
#include "lldb/Symbol/Type.h"
|
||||
#include "lldb/Symbol/Variable.h"
|
||||
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/LanguageRuntime.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
#include "lldb/Target/Thread.h"
|
||||
|
||||
|
||||
using namespace lldb_private;
|
||||
|
||||
ValueObjectDynamicValue::ValueObjectDynamicValue (ValueObject &parent) :
|
||||
ValueObject(parent),
|
||||
m_address (),
|
||||
m_type_sp()
|
||||
{
|
||||
// THINK ABOUT: It looks ugly to doctor up the name like this. But if
|
||||
// people find it confusing to tell the difference, we may want to do something...
|
||||
|
||||
// std::string dynamic_name ("<dynamic value for \"");
|
||||
// dynamic_name.append(parent.GetName().AsCString());
|
||||
// dynamic_name.append("\">");
|
||||
//
|
||||
// SetName (dynamic_name.c_str());
|
||||
SetName (parent.GetName().AsCString());
|
||||
}
|
||||
|
||||
ValueObjectDynamicValue::~ValueObjectDynamicValue()
|
||||
{
|
||||
m_owning_valobj_sp.reset();
|
||||
}
|
||||
|
||||
lldb::clang_type_t
|
||||
ValueObjectDynamicValue::GetClangType ()
|
||||
{
|
||||
if (m_type_sp)
|
||||
return m_value.GetClangType();
|
||||
else
|
||||
return m_parent->GetClangType();
|
||||
}
|
||||
|
||||
ConstString
|
||||
ValueObjectDynamicValue::GetTypeName()
|
||||
{
|
||||
// FIXME: Maybe cache the name, but have to clear it out if the type changes...
|
||||
if (!UpdateValueIfNeeded())
|
||||
return ConstString("<unknown type>");
|
||||
|
||||
if (m_type_sp)
|
||||
return ClangASTType::GetClangTypeName (GetClangType());
|
||||
else
|
||||
return m_parent->GetTypeName();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ValueObjectDynamicValue::CalculateNumChildren()
|
||||
{
|
||||
if (!UpdateValueIfNeeded())
|
||||
return 0;
|
||||
|
||||
if (m_type_sp)
|
||||
return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true);
|
||||
else
|
||||
return m_parent->GetNumChildren();
|
||||
}
|
||||
|
||||
clang::ASTContext *
|
||||
ValueObjectDynamicValue::GetClangAST ()
|
||||
{
|
||||
if (!UpdateValueIfNeeded())
|
||||
return NULL;
|
||||
|
||||
if (m_type_sp)
|
||||
return m_type_sp->GetClangAST();
|
||||
else
|
||||
return m_parent->GetClangAST ();
|
||||
}
|
||||
|
||||
size_t
|
||||
ValueObjectDynamicValue::GetByteSize()
|
||||
{
|
||||
if (!UpdateValueIfNeeded())
|
||||
return 0;
|
||||
|
||||
if (m_type_sp)
|
||||
return m_value.GetValueByteSize(GetClangAST(), NULL);
|
||||
else
|
||||
return m_parent->GetByteSize();
|
||||
}
|
||||
|
||||
lldb::ValueType
|
||||
ValueObjectDynamicValue::GetValueType() const
|
||||
{
|
||||
return m_parent->GetValueType();
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObjectDynamicValue::UpdateValue ()
|
||||
{
|
||||
SetValueIsValid (false);
|
||||
m_error.Clear();
|
||||
|
||||
if (!m_parent->UpdateValueIfNeeded())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ExecutionContext exe_ctx (GetExecutionContextScope());
|
||||
|
||||
if (exe_ctx.target)
|
||||
{
|
||||
m_data.SetByteOrder(exe_ctx.target->GetArchitecture().GetByteOrder());
|
||||
m_data.SetAddressByteSize(exe_ctx.target->GetArchitecture().GetAddressByteSize());
|
||||
}
|
||||
|
||||
// First make sure our Type and/or Address haven't changed:
|
||||
Process *process = m_update_point.GetProcess();
|
||||
if (!process)
|
||||
return false;
|
||||
|
||||
lldb::TypeSP dynamic_type_sp;
|
||||
Address dynamic_address;
|
||||
bool found_dynamic_type = false;
|
||||
|
||||
lldb::LanguageType known_type = m_parent->GetObjectRuntimeLanguage();
|
||||
if (known_type != lldb::eLanguageTypeUnknown && known_type != lldb::eLanguageTypeC)
|
||||
{
|
||||
LanguageRuntime *runtime = process->GetLanguageRuntime (known_type);
|
||||
if (runtime)
|
||||
found_dynamic_type = runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
|
||||
}
|
||||
else
|
||||
{
|
||||
LanguageRuntime *cpp_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeC_plus_plus);
|
||||
if (cpp_runtime)
|
||||
found_dynamic_type = cpp_runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
|
||||
|
||||
if (!found_dynamic_type)
|
||||
{
|
||||
LanguageRuntime *objc_runtime = process->GetLanguageRuntime (lldb::eLanguageTypeObjC);
|
||||
if (objc_runtime)
|
||||
found_dynamic_type = cpp_runtime->GetDynamicValue(*m_parent, dynamic_type_sp, dynamic_address);
|
||||
}
|
||||
}
|
||||
|
||||
// If we don't have a dynamic type, then make ourselves just a echo of our parent.
|
||||
// Or we could return false, and make ourselves an echo of our parent?
|
||||
if (!found_dynamic_type)
|
||||
{
|
||||
if (m_type_sp)
|
||||
SetValueDidChange(true);
|
||||
m_value = m_parent->GetValue();
|
||||
m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0);
|
||||
return m_error.Success();
|
||||
}
|
||||
|
||||
Value old_value(m_value);
|
||||
|
||||
if (!m_type_sp)
|
||||
{
|
||||
m_type_sp = dynamic_type_sp;
|
||||
}
|
||||
else if (dynamic_type_sp != m_type_sp)
|
||||
{
|
||||
// We are another type, we need to tear down our children...
|
||||
m_type_sp = dynamic_type_sp;
|
||||
SetValueDidChange (true);
|
||||
}
|
||||
|
||||
if (!m_address.IsValid() || m_address != dynamic_address)
|
||||
{
|
||||
if (m_address.IsValid())
|
||||
SetValueDidChange (true);
|
||||
|
||||
// We've moved, so we should be fine...
|
||||
m_address = dynamic_address;
|
||||
lldb::addr_t load_address = m_address.GetLoadAddress(m_update_point.GetTarget());
|
||||
m_value.GetScalar() = load_address;
|
||||
}
|
||||
|
||||
// The type will always be the type of the dynamic object. If our parent's type was a pointer,
|
||||
// then our type should be a pointer to the type of the dynamic object. If a reference, then the original type
|
||||
// should be okay...
|
||||
lldb::clang_type_t orig_type = m_type_sp->GetClangForwardType();
|
||||
lldb::clang_type_t corrected_type = orig_type;
|
||||
if (m_parent->IsPointerType())
|
||||
corrected_type = ClangASTContext::CreatePointerType (m_type_sp->GetClangAST(), orig_type);
|
||||
else if (m_parent->IsPointerOrReferenceType())
|
||||
corrected_type = ClangASTContext::CreateLValueReferenceType (m_type_sp->GetClangAST(), orig_type);
|
||||
|
||||
m_value.SetContext (Value::eContextTypeClangType, corrected_type);
|
||||
|
||||
// Our address is the location of the dynamic type stored in memory. It isn't a load address,
|
||||
// because we aren't pointing to the LOCATION that stores the pointer to us, we're pointing to us...
|
||||
m_value.SetValueType(Value::eValueTypeScalar);
|
||||
|
||||
if (m_address.IsValid() && m_type_sp)
|
||||
{
|
||||
// The variable value is in the Scalar value inside the m_value.
|
||||
// We can point our m_data right to it.
|
||||
m_error = m_value.GetValueAsData (&exe_ctx, GetClangAST(), m_data, 0);
|
||||
if (m_error.Success())
|
||||
{
|
||||
if (ClangASTContext::IsAggregateType (GetClangType()))
|
||||
{
|
||||
// this value object represents an aggregate type whose
|
||||
// children have values, but this object does not. So we
|
||||
// say we are changed if our location has changed.
|
||||
SetValueDidChange (m_value.GetValueType() != old_value.GetValueType() || m_value.GetScalar() != old_value.GetScalar());
|
||||
}
|
||||
|
||||
SetValueIsValid (true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// We get here if we've failed above...
|
||||
SetValueIsValid (false);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool
|
||||
ValueObjectDynamicValue::IsInScope ()
|
||||
{
|
||||
return m_parent->IsInScope();
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -30,8 +30,11 @@ 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,7 +529,9 @@ 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
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../make
|
||||
|
||||
CXX_SOURCES := pass-to-base.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -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()
|
|
@ -0,0 +1,62 @@
|
|||
#include <stdio.h>
|
||||
#include <memory>
|
||||
|
||||
class Extra
|
||||
{
|
||||
public:
|
||||
Extra (int in_one, int in_two) : m_extra_one(in_one), m_extra_two(in_two) {}
|
||||
|
||||
private:
|
||||
int m_extra_one;
|
||||
int m_extra_two;
|
||||
};
|
||||
|
||||
class A
|
||||
{
|
||||
public:
|
||||
A(int value) : m_a_value (value) {}
|
||||
A(int value, A* client_A) : m_a_value (value), m_client_A (client_A) {}
|
||||
|
||||
virtual void
|
||||
doSomething (A &anotherA)
|
||||
{
|
||||
printf ("In A %p doing something with %d.\n", this, m_a_value);
|
||||
printf ("Also have another A at %p: %d.\n", &anotherA, anotherA.Value()); // Break here in doSomething.
|
||||
}
|
||||
|
||||
int
|
||||
Value()
|
||||
{
|
||||
return m_a_value;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_a_value;
|
||||
std::auto_ptr<A> m_client_A;
|
||||
};
|
||||
|
||||
class B : public Extra, public virtual A
|
||||
{
|
||||
public:
|
||||
B (int b_value, int a_value) : Extra(b_value, a_value), A(a_value), m_b_value(b_value) {}
|
||||
B (int b_value, int a_value, A *client_A) : Extra(b_value, a_value), A(a_value, client_A), m_b_value(b_value) {}
|
||||
private:
|
||||
int m_b_value;
|
||||
};
|
||||
|
||||
static A* my_global_A_ptr;
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
my_global_A_ptr = new B (100, 200);
|
||||
B myB (10, 20, my_global_A_ptr);
|
||||
B otherB (300, 400, my_global_A_ptr);
|
||||
|
||||
myB.doSomething(otherB); // Break here and get real addresses of myB and otherB.
|
||||
|
||||
A reallyA (500);
|
||||
myB.doSomething (reallyA); // Break here and get real address of reallyA.
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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'",
|
||||
|
|
|
@ -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)";
|
||||
|
|
Loading…
Reference in New Issue