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:
Jim Ingham 2011-04-16 00:01:13 +00:00
parent f46b33852c
commit 78a685aa2d
38 changed files with 1739 additions and 238 deletions

View File

@ -71,8 +71,12 @@ public:
lldb::SBBlock
GetBlock () const;
// The version that doesn't supply a "use_dynamic" value will use the target's default.
lldb::SBValue
EvaluateExpression (const char *expr);
EvaluateExpression (const char *expr);
lldb::SBValue
EvaluateExpression (const char *expr, bool fetch_dynamic_value);
// Gets the lexical block that defines the stack frame. Another way to think
// of this is it will return the block that contains all of the variables
@ -116,17 +120,32 @@ public:
bool statics,
bool in_scope_only);
// The version that doesn't supply a "use_dynamic" value will use the target's default.
lldb::SBValueList
GetVariables (bool arguments,
bool locals,
bool statics,
bool in_scope_only,
bool use_dynamic);
lldb::SBValueList
GetRegisters ();
// The version that doesn't supply a "use_dynamic" value will use the target's default.
lldb::SBValue
FindVariable (const char *var_name);
lldb::SBValue
FindVariable (const char *var_name, bool use_dynamic);
// Find variables, register sets, registers, or persistent variables using
// the frame as the scope
lldb::SBValue
FindValue (const char *name, ValueType value_type);
lldb::SBValue
FindValue (const char *name, ValueType value_type, bool use_dynamic);
bool
GetDescription (lldb::SBStream &description);

View File

@ -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 ();

View File

@ -306,7 +306,7 @@ public:
bool
ResolveValue (Scalar &scalar);
const char *
GetLocationAsCString ();
@ -325,9 +325,6 @@ public:
bool
UpdateValueIfNeeded ();
const DataExtractor &
GetDataExtractor () const;
DataExtractor &
GetDataExtractor ();
@ -345,10 +342,10 @@ public:
GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create);
lldb::ValueObjectSP
GetDynamicValue ()
{
return m_dynamic_value_sp;
}
GetDynamicValue (bool can_create);
lldb::ValueObjectSP
GetDynamicValue (bool can_create, lldb::ValueObjectSP &owning_valobj_sp);
virtual lldb::ValueObjectSP
CreateConstantValue (const ConstString &name);
@ -369,8 +366,11 @@ public:
m_object_desc_str.clear();
}
bool
SetDynamicValue ();
virtual bool
IsDynamic ()
{
return false;
}
static void
DumpValueObject (Stream &s,
@ -382,6 +382,7 @@ public:
bool show_types,
bool show_location,
bool use_objc,
bool use_dynamic,
bool scope_already_checked,
bool flat_output);
@ -411,13 +412,16 @@ public:
m_format = format;
}
ValueObject *
// Use GetParent for display purposes, but if you want to tell the parent to update itself
// then use m_parent. The ValueObjectDynamicValue's parent is not the correct parent for
// displaying, they are really siblings, so for display it needs to route through to its grandparent.
virtual ValueObject *
GetParent()
{
return m_parent;
}
const ValueObject *
virtual const ValueObject *
GetParent() const
{
return m_parent;
@ -436,8 +440,8 @@ protected:
//------------------------------------------------------------------
// Classes that inherit from ValueObject can see and modify these
//------------------------------------------------------------------
ValueObject* m_parent; // The parent value object, or NULL if this has no parent
EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
ValueObject *m_parent; // The parent value object, or NULL if this has no parent
EvaluationPoint m_update_point; // Stores both the stop id and the full context at which this value was last
// updated. When we are asked to update the value object, we check whether
// the context & stop id are the same before updating.
ConstString m_name; // The name of this object
@ -453,6 +457,10 @@ protected:
std::vector<lldb::ValueObjectSP> m_children;
std::map<ConstString, lldb::ValueObjectSP> m_synthetic_children;
lldb::ValueObjectSP m_dynamic_value_sp;
lldb::ValueObjectSP m_addr_of_valobj_sp; // These two shared pointers help root the ValueObject shared pointers that
lldb::ValueObjectSP m_deref_valobj_sp; // we hand out, so that we can use them in their dynamic types and ensure
// they will last as long as this ValueObject...
lldb::Format m_format;
bool m_value_is_valid:1,
m_value_did_change:1,
@ -463,6 +471,7 @@ protected:
friend class CommandObjectExpression;
friend class ClangExpressionVariable;
friend class ClangExpressionDeclMap; // For GetValue...
friend class Target;
friend class ValueObjectChild;
//------------------------------------------------------------------
@ -486,6 +495,9 @@ protected:
virtual bool
UpdateValue () = 0;
virtual void
CalculateDynamicValue ();
// Should only be called by ValueObject::GetChildAtIndex()
virtual lldb::ValueObjectSP
CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int32_t synthetic_index);
@ -509,7 +521,7 @@ protected:
void
SetValueIsValid (bool valid);
public:
lldb::addr_t
GetPointerValue (AddressType &address_type,
bool scalar_is_load_address);

View File

@ -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;

View File

@ -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_

View File

@ -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_

View File

@ -42,9 +42,14 @@ public:
virtual bool
GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) = 0;
virtual lldb::ValueObjectSP
GetDynamicValue (lldb::ValueObjectSP in_value) = 0;
virtual bool
GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address) = 0;
// This should be a fast test to determine whether it is likely that this value would
// have a dynamic type.
virtual bool
CouldHaveDynamicValue (ValueObject &in_value) = 0;
virtual void
SetExceptionBreakpoints ()
{

View File

@ -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

View File

@ -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 &

View File

@ -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 = "";

View File

@ -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;
}

View File

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

View File

@ -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."},

View File

@ -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;

View File

@ -310,6 +310,22 @@ public:
switch (short_option)
{
case 'o': use_objc = true; break;
case 'd':
{
bool success;
bool result;
result = Args::StringToBoolean(option_arg, true, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid dynamic value setting: \"%s\".\n", option_arg);
else
{
if (result)
use_dynamic = eLazyBoolYes;
else
use_dynamic = eLazyBoolNo;
}
}
break;
case 'r': use_regex = true; break;
case 'a': show_args = false; break;
case 'l': show_locals = false; break;
@ -321,7 +337,7 @@ public:
case 'D': debug = true; break;
case 'f': error = Args::StringToFormat(option_arg, format); break;
case 'F': flat_output = true; break;
case 'd':
case 'A':
max_depth = Args::StringToUInt32 (option_arg, UINT32_MAX, 0, &success);
if (!success)
error.SetErrorStringWithFormat("Invalid max depth '%s'.\n", option_arg);
@ -364,6 +380,7 @@ public:
show_decl = false;
debug = false;
flat_output = false;
use_dynamic = eLazyBoolCalculate;
max_depth = UINT32_MAX;
ptr_depth = 0;
format = eFormatDefault;
@ -391,6 +408,7 @@ public:
show_decl:1,
debug:1,
flat_output:1;
LazyBool use_dynamic;
uint32_t max_depth; // The depth to print when dumping concrete (not pointers) aggreate values
uint32_t ptr_depth; // The default depth that is dumped when we find pointers
lldb::Format format; // The format to use when dumping variables or children of variables
@ -461,7 +479,28 @@ public:
VariableSP var_sp;
ValueObjectSP valobj_sp;
//ValueObjectList &valobj_list = exe_ctx.frame->GetValueObjectList();
bool use_dynamic;
// If use dynamic is not set, get it from the target:
switch (m_options.use_dynamic)
{
case eLazyBoolCalculate:
{
if (exe_ctx.target->GetPreferDynamicValue())
use_dynamic = true;
else
use_dynamic = false;
}
break;
case eLazyBoolYes:
use_dynamic = true;
break;
case eLazyBoolNo:
use_dynamic = false;
break;
}
const char *name_cstr = NULL;
size_t idx;
if (!m_options.globals.empty())
@ -473,12 +512,17 @@ public:
for (idx = 0; idx < num_globals; ++idx)
{
VariableList global_var_list;
const uint32_t num_matching_globals = exe_ctx.target->GetImages().FindGlobalVariables (m_options.globals[idx], true, UINT32_MAX, global_var_list);
const uint32_t num_matching_globals
= exe_ctx.target->GetImages().FindGlobalVariables (m_options.globals[idx],
true,
UINT32_MAX,
global_var_list);
if (num_matching_globals == 0)
{
++fail_count;
result.GetErrorStream().Printf ("error: can't find global variable '%s'\n", m_options.globals[idx].AsCString());
result.GetErrorStream().Printf ("error: can't find global variable '%s'\n",
m_options.globals[idx].AsCString());
}
else
{
@ -487,9 +531,9 @@ public:
var_sp = global_var_list.GetVariableAtIndex(global_idx);
if (var_sp)
{
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (!valobj_sp)
valobj_sp = exe_ctx.frame->TrackGlobalVariable (var_sp);
valobj_sp = exe_ctx.frame->TrackGlobalVariable (var_sp, use_dynamic);
if (valobj_sp)
{
@ -501,7 +545,7 @@ public:
var_sp->GetDeclaration ().DumpStopContext (&s, false);
s.PutCString (": ");
}
ValueObject::DumpValueObject (result.GetOutputStream(),
valobj_sp.get(),
name_cstr,
@ -510,7 +554,8 @@ public:
m_options.max_depth,
m_options.show_types,
m_options.show_location,
m_options.use_objc,
m_options.use_objc,
use_dynamic,
false,
m_options.flat_output);
}
@ -541,7 +586,9 @@ public:
if (regex.Compile(name_cstr))
{
size_t num_matches = 0;
const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex, regex_var_list, num_matches);
const size_t num_new_regex_vars = variable_list->AppendVariablesIfUnique(regex,
regex_var_list,
num_matches);
if (num_new_regex_vars > 0)
{
for (uint32_t regex_idx = regex_start_index, end_index = regex_var_list.GetSize();
@ -551,9 +598,9 @@ public:
var_sp = regex_var_list.GetVariableAtIndex (regex_idx);
if (var_sp)
{
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (valobj_sp)
{
{
if (m_options.format != eFormatDefault)
valobj_sp->SetFormat (m_options.format);
@ -571,7 +618,8 @@ public:
m_options.max_depth,
m_options.show_types,
m_options.show_location,
m_options.use_objc,
m_options.use_objc,
use_dynamic,
false,
m_options.flat_output);
}
@ -595,10 +643,20 @@ public:
else
{
Error error;
const uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
uint32_t expr_path_options = StackFrame::eExpressionPathOptionCheckPtrVsMember;
if (use_dynamic)
expr_path_options |= StackFrame::eExpressionPathOptionsDynamicValue;
valobj_sp = exe_ctx.frame->GetValueForVariableExpressionPath (name_cstr, expr_path_options, error);
if (valobj_sp)
{
// if (use_dynamic)
// {
// lldb::ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(true, valobj_sp);
// if (dynamic_sp != NULL)
// valobj_sp = dynamic_sp;
// }
//
if (m_options.format != eFormatDefault)
valobj_sp->SetFormat (m_options.format);
@ -615,7 +673,8 @@ public:
m_options.max_depth,
m_options.show_types,
m_options.show_location,
m_options.use_objc,
m_options.use_objc,
use_dynamic,
false,
m_options.flat_output);
}
@ -639,6 +698,7 @@ public:
for (uint32_t i=0; i<num_variables; i++)
{
var_sp = variable_list->GetVariableAtIndex(i);
bool dump_variable = true;
switch (var_sp->GetScope())
@ -677,7 +737,7 @@ public:
// Use the variable object code to make sure we are
// using the same APIs as the the public API will be
// using...
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp);
valobj_sp = exe_ctx.frame->GetValueObjectForFrameVariable (var_sp, use_dynamic);
if (valobj_sp)
{
if (m_options.format != eFormatDefault)
@ -700,7 +760,8 @@ public:
m_options.max_depth,
m_options.show_types,
m_options.show_location,
m_options.use_objc,
m_options.use_objc,
use_dynamic,
false,
m_options.flat_output);
}
@ -722,22 +783,23 @@ protected:
OptionDefinition
CommandObjectFrameVariable::CommandOptions::g_option_table[] =
{
{ LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug information."},
{ LLDB_OPT_SET_1, false, "depth", 'd', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
{ LLDB_OPT_SET_1, false, "show-globals",'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
{ LLDB_OPT_SET_1, false, "find-global",'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
{ LLDB_OPT_SET_1, false, "show-declaration", 'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
{ LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
{ LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
{ LLDB_OPT_SET_1, false, "show-types", 't', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
{ LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
{ LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
{ LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, eArgTypeNone, "When looking up a variable by name, print as an Objective-C object."},
{ LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
{ LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the variable output should use."},
{ LLDB_OPT_SET_1, false, "aggregate-depth", 'A', required_argument, NULL, 0, eArgTypeCount, "Set the max recurse depth when dumping aggregate types (default is infinity)."},
{ LLDB_OPT_SET_1, false, "no-args", 'a', no_argument, NULL, 0, eArgTypeNone, "Omit function arguments."},
{ LLDB_OPT_SET_1, false, "show-declaration",'c', no_argument, NULL, 0, eArgTypeNone, "Show variable declaration information (source file and line where the variable was declared)."},
{ LLDB_OPT_SET_1, false, "debug", 'D', no_argument, NULL, 0, eArgTypeNone, "Enable verbose debug information."},
{ LLDB_OPT_SET_1, false, "dynamic-type", 'd', required_argument, NULL, 0, eArgTypeBoolean, "Show the object as its full dynamic type, not its static type, if available."},
{ LLDB_OPT_SET_1, false, "format", 'f', required_argument, NULL, 0, eArgTypeExprFormat, "Specify the format that the variable output should use."},
{ LLDB_OPT_SET_1, false, "flat", 'F', no_argument, NULL, 0, eArgTypeNone, "Display results in a flat format that uses expression paths for each variable or member."},
{ LLDB_OPT_SET_1, false, "show-globals", 'g', no_argument, NULL, 0, eArgTypeNone, "Show the current frame source file global and static variables."},
{ LLDB_OPT_SET_1, false, "find-global", 'G', required_argument, NULL, 0, eArgTypeVarName, "Find a global variable by name (which might not be in the current stack frame source file)."},
{ LLDB_OPT_SET_1, false, "location", 'L', no_argument, NULL, 0, eArgTypeNone, "Show variable location information."},
{ LLDB_OPT_SET_1, false, "no-locals", 'l', no_argument, NULL, 0, eArgTypeNone, "Omit local variables."},
{ LLDB_OPT_SET_1, false, "objc", 'o', no_argument, NULL, 0, eArgTypeNone, "When looking up a variable by name, print as an Objective-C object."},
{ LLDB_OPT_SET_1, false, "ptr-depth", 'p', required_argument, NULL, 0, eArgTypeCount, "The number of pointers to be traversed when dumping values (default is zero)."},
{ LLDB_OPT_SET_1, false, "regex", 'r', no_argument, NULL, 0, eArgTypeRegularExpression, "The <variable-name> argument for name lookups are regular expressions."},
{ LLDB_OPT_SET_1, false, "scope", 's', no_argument, NULL, 0, eArgTypeNone, "Show variable scope (argument, local, global, static)."},
{ LLDB_OPT_SET_1, false, "show-types", 't', no_argument, NULL, 0, eArgTypeNone, "Show variable types when dumping values."},
{ LLDB_OPT_SET_1, false, "no-summary", 'y', no_argument, NULL, 0, eArgTypeNone, "Omit summary information."},
{ 0, false, NULL, 0, 0, NULL, NULL, eArgTypeNone, NULL }
};
#pragma mark CommandObjectMultiwordFrame

View File

@ -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();

View File

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

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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,

View File

@ -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

View File

@ -30,9 +30,12 @@ namespace lldb_private {
virtual bool
IsVTableName (const char *name);
virtual lldb::ValueObjectSP
GetDynamicValue (lldb::ValueObjectSP in_value);
virtual bool
GetDynamicValue (ValueObject &in_value, lldb::TypeSP &type_sp, Address &address);
virtual bool
CouldHaveDynamicValue (ValueObject &in_value);
//------------------------------------------------------------------
// Static Functions
//------------------------------------------------------------------

View File

@ -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

View File

@ -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.

View File

@ -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;
}
//------------------------------------------------------------------

View File

@ -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 *);

View File

@ -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;
}
//------------------------------------------------------------------

View File

@ -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 *);

View File

@ -1902,6 +1902,12 @@ Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
if (buf == NULL || size == 0)
return 0;
// Need to bump the stop ID after writing so that ValueObjects will know to re-read themselves.
// FUTURE: Doing this should be okay, but if anybody else gets upset about the stop_id changing when
// the target hasn't run, then we will need to add a "memory generation" as well as a stop_id...
m_stop_id++;
// We need to write any data that would go where any current software traps
// (enabled software breakpoints) any software traps (breakpoints) that we
// may have placed in our tasks memory.
@ -1962,7 +1968,7 @@ Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
ubuf + bytes_written,
size - bytes_written,
error);
return bytes_written;
}

View File

@ -493,6 +493,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
{
const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0;
const bool no_fragile_ivar = (options & eExpressionPathOptionsNoFragileObjcIvar) != 0;
const bool dynamic_value = (options & eExpressionPathOptionsDynamicValue) != 0;
error.Clear();
bool deref = false;
bool address_of = false;
@ -528,8 +529,10 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
VariableSP var_sp (variable_list->FindVariable(name_const_string));
if (var_sp)
{
valobj_sp = GetValueObjectForFrameVariable (var_sp);
valobj_sp = GetValueObjectForFrameVariable (var_sp, dynamic_value);
if (!valobj_sp)
return valobj_sp;
var_path.erase (0, name_const_string.GetLength ());
// We are dumping at least one child
while (separator_idx != std::string::npos)
@ -600,7 +603,6 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
return ValueObjectSP();
}
}
child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
if (!child_valobj_sp)
{
@ -624,6 +626,12 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
}
// Remove the child name from the path
var_path.erase(0, child_name.GetLength());
if (dynamic_value)
{
ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(true, child_valobj_sp));
if (dynamic_value_sp)
child_valobj_sp = dynamic_value_sp;
}
}
break;
@ -650,6 +658,8 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
}
else if (ClangASTContext::IsArrayType (valobj_sp->GetClangType(), NULL, NULL))
{
// Pass false to dynamic_value here so we can tell the difference between
// no dynamic value and no member of this type...
child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true);
if (!child_valobj_sp)
{
@ -678,7 +688,12 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, uint32
// %i is the array index
var_path.erase(0, (end - var_path.c_str()) + 1);
separator_idx = var_path.find_first_of(".-[");
if (dynamic_value)
{
ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(true, child_valobj_sp));
if (dynamic_value_sp)
child_valobj_sp = dynamic_value_sp;
}
// Break out early from the switch since we were
// able to find the child member
break;
@ -794,7 +809,7 @@ StackFrame::HasDebugInformation ()
ValueObjectSP
StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp)
StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, bool use_dynamic)
{
ValueObjectSP valobj_sp;
VariableList *var_list = GetVariableList (true);
@ -815,14 +830,20 @@ StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp)
}
}
}
if (use_dynamic && valobj_sp)
{
ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue (true, valobj_sp);
if (dynamic_sp)
return dynamic_sp;
}
return valobj_sp;
}
ValueObjectSP
StackFrame::TrackGlobalVariable (const VariableSP &variable_sp)
StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, bool use_dynamic)
{
// Check to make sure we aren't already tracking this variable?
ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp));
ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp, use_dynamic));
if (!valobj_sp)
{
// We aren't already tracking this global
@ -835,7 +856,7 @@ StackFrame::TrackGlobalVariable (const VariableSP &variable_sp)
m_variable_list_sp->AddVariable (variable_sp);
// Now make a value object for it so we can track its changes
valobj_sp = GetValueObjectForFrameVariable (variable_sp);
valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic);
}
return valobj_sp;
}

View File

@ -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 }
};

View File

@ -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;

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := pass-to-base.cpp
include $(LEVEL)/Makefile.rules

View File

@ -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()

View File

@ -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;
}

View File

@ -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)

View File

@ -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'",

View File

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