Fixed a bug where a variable could not be formatted in a summary if its datatype already had a custom format
Fixed a bug where Objective-C variables coming out of the expression parser could crash the Python synthetic providers: - expression parser output has a "frozen data" component, which is a byte-exact copy of the value (in host memory), if trying to read into memory based on the host address, LLDB would crash. we are now passing the correct (target) pointer to the Python code Objective-C "id" variables are now formatted according to their dynamic type, if the -d option to frame variable is used: - Code based on the Objective-C 2.0 runtime is used to obtain this information without running code on the target llvm-svn: 136695
This commit is contained in:
parent
9ab728bb05
commit
c3e320a7a0
|
@ -486,7 +486,7 @@ public:
|
|||
{
|
||||
public:
|
||||
static bool
|
||||
Get(ValueObject& vobj, ValueFormat::SharedPointer &entry);
|
||||
Get(ValueObject& vobj, lldb::DynamicValueType use_dynamic, ValueFormat::SharedPointer &entry);
|
||||
|
||||
static void
|
||||
Add(const ConstString &type, const ValueFormat::SharedPointer &entry);
|
||||
|
@ -509,9 +509,11 @@ public:
|
|||
|
||||
static bool
|
||||
GetSummaryFormat(ValueObject& vobj,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
lldb::SummaryFormatSP& entry);
|
||||
static bool
|
||||
GetSyntheticFilter(ValueObject& vobj,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
lldb::SyntheticChildrenSP& entry);
|
||||
|
||||
class NamedSummaryFormats
|
||||
|
|
|
@ -55,7 +55,9 @@ namespace std
|
|||
#include "lldb/Core/ValueObject.h"
|
||||
#include "lldb/Interpreter/ScriptInterpreterPython.h"
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
#include "lldb/Target/Platform.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/StackFrame.h"
|
||||
#include "lldb/Target/TargetList.h"
|
||||
|
||||
|
@ -189,6 +191,8 @@ private:
|
|||
typedef FormatMap<KeyType,ValueType> BackEndType;
|
||||
|
||||
BackEndType m_format_map;
|
||||
|
||||
std::string m_name;
|
||||
|
||||
public:
|
||||
typedef typename BackEndType::MapType MapType;
|
||||
|
@ -201,8 +205,10 @@ public:
|
|||
|
||||
friend class FormatCategory;
|
||||
|
||||
FormatNavigator(IFormatChangeListener* lst = NULL) :
|
||||
m_format_map(lst)
|
||||
FormatNavigator(std::string name,
|
||||
IFormatChangeListener* lst = NULL) :
|
||||
m_format_map(lst),
|
||||
m_name(name)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -223,11 +229,12 @@ public:
|
|||
bool
|
||||
Get(ValueObject& vobj,
|
||||
MapValueType& entry,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
uint32_t* why = NULL)
|
||||
{
|
||||
uint32_t value = lldb::eFormatterChoiceCriterionDirectChoice;
|
||||
clang::QualType type = clang::QualType::getFromOpaquePtr(vobj.GetClangType());
|
||||
bool ret = Get(vobj, type, entry, value);
|
||||
bool ret = Get(vobj, type, entry, use_dynamic, value);
|
||||
if (ret)
|
||||
entry = MapValueType(entry);
|
||||
else
|
||||
|
@ -267,9 +274,64 @@ private:
|
|||
return m_format_map.Get(type, entry);
|
||||
}
|
||||
|
||||
bool Get_ObjC(ValueObject& vobj,
|
||||
ObjCLanguageRuntime::ObjCISA isa,
|
||||
MapValueType& entry,
|
||||
uint32_t& reason)
|
||||
{
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
|
||||
if (log)
|
||||
log->Printf("going to an Objective-C dynamic scanning");
|
||||
Process* process = vobj.GetUpdatePoint().GetProcessSP().get();
|
||||
ObjCLanguageRuntime* runtime = process->GetObjCLanguageRuntime();
|
||||
if (runtime == NULL)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("no valid ObjC runtime, bailing out");
|
||||
return false;
|
||||
}
|
||||
if (runtime->IsValidISA(isa) == false)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("invalid ISA, bailing out");
|
||||
return false;
|
||||
}
|
||||
ConstString name = runtime->GetActualTypeName(isa);
|
||||
if (log)
|
||||
log->Printf("looking for formatter for %s", name.GetCString());
|
||||
if (Get(name.GetCString(), entry))
|
||||
{
|
||||
if (log)
|
||||
log->Printf("direct match found, returning");
|
||||
return true;
|
||||
}
|
||||
if (log)
|
||||
log->Printf("no direct match");
|
||||
ObjCLanguageRuntime::ObjCISA parent = runtime->GetParentClass(isa);
|
||||
if (runtime->IsValidISA(parent) == false)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("invalid parent ISA, bailing out");
|
||||
return false;
|
||||
}
|
||||
if (parent == isa)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("parent-child loop, bailing out");
|
||||
return false;
|
||||
}
|
||||
if (Get_ObjC(vobj, parent, entry, reason))
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionNavigatedBaseClasses;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Get(ValueObject& vobj,
|
||||
clang::QualType type,
|
||||
MapValueType& entry,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
uint32_t& reason)
|
||||
{
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
|
||||
|
@ -299,7 +361,10 @@ private:
|
|||
log->Printf("appended bitfield info, final result is %s", name.GetCString());
|
||||
}
|
||||
if (log)
|
||||
log->Printf("trying to get format for VO name %s of type %s",vobj.GetName().AsCString(),name.AsCString());
|
||||
log->Printf("trying to get %s for VO name %s of type %s",
|
||||
m_name.c_str(),
|
||||
vobj.GetName().AsCString(),
|
||||
name.AsCString());
|
||||
if (Get(name.GetCString(), entry))
|
||||
{
|
||||
if (log)
|
||||
|
@ -313,17 +378,48 @@ private:
|
|||
{
|
||||
if (log)
|
||||
log->Printf("stripping reference");
|
||||
if (Get(vobj,type.getNonReferenceType(),entry, reason) && !entry->m_skip_references)
|
||||
if (Get(vobj,type.getNonReferenceType(),entry, use_dynamic, reason) && !entry->m_skip_references)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionStrippedPointerReference;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (use_dynamic != lldb::eNoDynamicValues &&
|
||||
typePtr == vobj.GetClangAST()->ObjCBuiltinIdTy.getTypePtr())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("this is an ObjC 'id', let's do dynamic search");
|
||||
Process* process = vobj.GetUpdatePoint().GetProcessSP().get();
|
||||
ObjCLanguageRuntime* runtime = process->GetObjCLanguageRuntime();
|
||||
if (runtime == NULL)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("no valid ObjC runtime, skipping dynamic");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Get_ObjC(vobj, runtime->GetISA(vobj), entry, reason))
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionDynamicObjCHierarchy;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (use_dynamic != lldb::eNoDynamicValues && log)
|
||||
{
|
||||
log->Printf("typename: %s, typePtr = %p, id = %p",
|
||||
name.AsCString(), typePtr, vobj.GetClangAST()->ObjCBuiltinIdTy.getTypePtr());
|
||||
}
|
||||
else if (log)
|
||||
{
|
||||
log->Printf("no dynamic");
|
||||
}
|
||||
if (typePtr->isPointerType())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("stripping pointer");
|
||||
if (Get(vobj, typePtr->getPointeeType(), entry, reason) && !entry->m_skip_pointers)
|
||||
clang::QualType pointee = typePtr->getPointeeType();
|
||||
if (Get(vobj, pointee, entry, use_dynamic, reason) && !entry->m_skip_pointers)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionStrippedPointerReference;
|
||||
return true;
|
||||
|
@ -331,6 +427,27 @@ private:
|
|||
}
|
||||
if (typePtr->isObjCObjectPointerType())
|
||||
{
|
||||
if (use_dynamic != lldb::eNoDynamicValues &&
|
||||
name.GetCString() == ConstString("id").GetCString())
|
||||
{
|
||||
if (log)
|
||||
log->Printf("this is an ObjC 'id', let's do dynamic search");
|
||||
Process* process = vobj.GetUpdatePoint().GetProcessSP().get();
|
||||
ObjCLanguageRuntime* runtime = process->GetObjCLanguageRuntime();
|
||||
if (runtime == NULL)
|
||||
{
|
||||
if (log)
|
||||
log->Printf("no valid ObjC runtime, skipping dynamic");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Get_ObjC(vobj, runtime->GetISA(vobj), entry, reason))
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionDynamicObjCHierarchy;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (log)
|
||||
log->Printf("stripping ObjC pointer");
|
||||
/*
|
||||
|
@ -343,7 +460,7 @@ private:
|
|||
ValueObject* target = vobj.Dereference(error).get();
|
||||
if (error.Fail() || !target)
|
||||
return false;
|
||||
if (Get(*target, typePtr->getPointeeType(), entry, reason) && !entry->m_skip_pointers)
|
||||
if (Get(*target, typePtr->getPointeeType(), entry, use_dynamic, reason) && !entry->m_skip_pointers)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionStrippedPointerReference;
|
||||
return true;
|
||||
|
@ -368,7 +485,7 @@ private:
|
|||
if (log)
|
||||
log->Printf("got a parent class for this ObjC class");
|
||||
clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl));
|
||||
if (Get(vobj, ivar_qual_type, entry, reason) && entry->m_cascades)
|
||||
if (Get(vobj, ivar_qual_type, entry, use_dynamic, reason) && entry->m_cascades)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionNavigatedBaseClasses;
|
||||
return true;
|
||||
|
@ -397,7 +514,7 @@ private:
|
|||
end = record->bases_end();
|
||||
for (pos = record->bases_begin(); pos != end; pos++)
|
||||
{
|
||||
if ((Get(vobj, pos->getType(), entry, reason)) && entry->m_cascades)
|
||||
if ((Get(vobj, pos->getType(), entry, use_dynamic, reason)) && entry->m_cascades)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionNavigatedBaseClasses;
|
||||
return true;
|
||||
|
@ -411,7 +528,7 @@ private:
|
|||
end = record->vbases_end();
|
||||
for (pos = record->vbases_begin(); pos != end; pos++)
|
||||
{
|
||||
if ((Get(vobj, pos->getType(), entry, reason)) && entry->m_cascades)
|
||||
if ((Get(vobj, pos->getType(), entry, use_dynamic, reason)) && entry->m_cascades)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionNavigatedBaseClasses;
|
||||
return true;
|
||||
|
@ -427,7 +544,7 @@ private:
|
|||
{
|
||||
if (log)
|
||||
log->Printf("stripping typedef");
|
||||
if ((Get(vobj, type_tdef->getDecl()->getUnderlyingType(), entry, reason)) && entry->m_cascades)
|
||||
if ((Get(vobj, type_tdef->getDecl()->getUnderlyingType(), entry, use_dynamic, reason)) && entry->m_cascades)
|
||||
{
|
||||
reason |= lldb::eFormatterChoiceCriterionNavigatedTypedefs;
|
||||
return true;
|
||||
|
@ -495,9 +612,9 @@ public:
|
|||
|
||||
FormatCategory(IFormatChangeListener* clist,
|
||||
std::string name) :
|
||||
m_summary_nav(new SummaryNavigator(clist)),
|
||||
m_regex_summary_nav(new RegexSummaryNavigator(clist)),
|
||||
m_filter_nav(new FilterNavigator(clist)),
|
||||
m_summary_nav(new SummaryNavigator("summary",clist)),
|
||||
m_regex_summary_nav(new RegexSummaryNavigator("regex-summary",clist)),
|
||||
m_filter_nav(new FilterNavigator("filter",clist)),
|
||||
m_enabled(false),
|
||||
m_change_listener(clist),
|
||||
m_mutex(Mutex::eMutexTypeRecursive),
|
||||
|
@ -531,13 +648,14 @@ public:
|
|||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SummaryFormatSP& entry,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
uint32_t* reason = NULL)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return false;
|
||||
if (Summary()->Get(vobj, entry, reason))
|
||||
if (Summary()->Get(vobj, entry, use_dynamic, reason))
|
||||
return true;
|
||||
bool regex = RegexSummary()->Get(vobj, entry, reason);
|
||||
bool regex = RegexSummary()->Get(vobj, entry, use_dynamic, reason);
|
||||
if (regex && reason)
|
||||
*reason |= lldb::eFormatterChoiceCriterionRegularExpressionSummary;
|
||||
return regex;
|
||||
|
@ -546,11 +664,12 @@ public:
|
|||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SyntheticChildrenSP& entry,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
uint32_t* reason = NULL)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return false;
|
||||
return (Filter()->Get(vobj, entry, reason));
|
||||
return (Filter()->Get(vobj, entry, use_dynamic, reason));
|
||||
}
|
||||
|
||||
// just a shortcut for Summary()->Clear; RegexSummary()->Clear()
|
||||
|
@ -760,43 +879,44 @@ public:
|
|||
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SummaryFormatSP& entry)
|
||||
lldb::SummaryFormatSP& entry,
|
||||
lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
|
||||
uint32_t reason_why;
|
||||
bool first = true;
|
||||
|
||||
uint32_t reason_why;
|
||||
ActiveCategoriesIterator begin, end = m_active_categories.end();
|
||||
|
||||
for (begin = m_active_categories.begin(); begin != end; begin++)
|
||||
{
|
||||
FormatCategory::SharedPointer category = *begin;
|
||||
lldb::SummaryFormatSP current_format;
|
||||
if (!category->Get(vobj, current_format, &reason_why))
|
||||
if (!category->Get(vobj, current_format, use_dynamic, &reason_why))
|
||||
continue;
|
||||
if (reason_why == lldb::eFormatterChoiceCriterionDirectChoice)
|
||||
{
|
||||
entry = current_format;
|
||||
return true;
|
||||
}
|
||||
else if (first)
|
||||
{
|
||||
entry = current_format;
|
||||
first = false;
|
||||
}
|
||||
/*if (reason_why == lldb::eFormatterChoiceCriterionDirectChoice)
|
||||
{
|
||||
entry = current_format;
|
||||
return true;
|
||||
}
|
||||
else if (first)
|
||||
{
|
||||
entry = current_format;
|
||||
first = false;
|
||||
}*/
|
||||
entry = current_format;
|
||||
return true;
|
||||
}
|
||||
return !first;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SyntheticChildrenSP& entry)
|
||||
lldb::SyntheticChildrenSP& entry,
|
||||
lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
|
||||
uint32_t reason_why;
|
||||
bool first = true;
|
||||
|
||||
ActiveCategoriesIterator begin, end = m_active_categories.end();
|
||||
|
||||
|
@ -804,9 +924,9 @@ public:
|
|||
{
|
||||
FormatCategory::SharedPointer category = *begin;
|
||||
lldb::SyntheticChildrenSP current_format;
|
||||
if (!category->Get(vobj, current_format, &reason_why))
|
||||
if (!category->Get(vobj, current_format, use_dynamic, &reason_why))
|
||||
continue;
|
||||
if (reason_why == lldb::eFormatterChoiceCriterionDirectChoice)
|
||||
/*if (reason_why == lldb::eFormatterChoiceCriterionDirectChoice)
|
||||
{
|
||||
entry = current_format;
|
||||
return true;
|
||||
|
@ -815,9 +935,11 @@ public:
|
|||
{
|
||||
entry = current_format;
|
||||
first = false;
|
||||
}
|
||||
}*/
|
||||
entry = current_format;
|
||||
return true;
|
||||
}
|
||||
return !first;
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -847,7 +969,7 @@ public:
|
|||
typedef bool (*CategoryCallback)(void*, const char*, const FormatCategory::SharedPointer&);
|
||||
|
||||
FormatManager() :
|
||||
m_value_nav(this),
|
||||
m_value_nav("format",this),
|
||||
m_named_summaries_map(this),
|
||||
m_last_revision(0),
|
||||
m_categories_map(this)
|
||||
|
@ -941,15 +1063,17 @@ public:
|
|||
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SummaryFormatSP& entry)
|
||||
lldb::SummaryFormatSP& entry,
|
||||
lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
return m_categories_map.Get(vobj, entry);
|
||||
return m_categories_map.Get(vobj, entry, use_dynamic);
|
||||
}
|
||||
bool
|
||||
Get(ValueObject& vobj,
|
||||
lldb::SyntheticChildrenSP& entry)
|
||||
lldb::SyntheticChildrenSP& entry,
|
||||
lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
return m_categories_map.Get(vobj, entry);
|
||||
return m_categories_map.Get(vobj, entry, use_dynamic);
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
@ -443,6 +443,9 @@ public:
|
|||
|
||||
virtual const char *
|
||||
GetValueAsCString ();
|
||||
|
||||
virtual unsigned long long
|
||||
GetValueAsUnsigned();
|
||||
|
||||
virtual bool
|
||||
SetValueFromCString (const char *value_str);
|
||||
|
@ -513,8 +516,11 @@ public:
|
|||
bool
|
||||
UpdateValueIfNeeded (bool update_format = true);
|
||||
|
||||
bool
|
||||
UpdateValueIfNeeded (lldb::DynamicValueType use_dynamic, bool update_format = true);
|
||||
|
||||
void
|
||||
UpdateFormatsIfNeeded();
|
||||
UpdateFormatsIfNeeded(lldb::DynamicValueType use_dynamic = lldb::eNoDynamicValues);
|
||||
|
||||
DataExtractor &
|
||||
GetDataExtractor ();
|
||||
|
@ -639,6 +645,18 @@ public:
|
|||
return m_format;
|
||||
}
|
||||
|
||||
void
|
||||
SetIsExpressionResult(bool expr)
|
||||
{
|
||||
m_is_expression_result = expr;
|
||||
}
|
||||
|
||||
bool
|
||||
GetIsExpressionResult()
|
||||
{
|
||||
return m_is_expression_result;
|
||||
}
|
||||
|
||||
void
|
||||
SetFormat (lldb::Format format)
|
||||
{
|
||||
|
@ -677,7 +695,7 @@ public:
|
|||
lldb::SummaryFormatSP
|
||||
GetSummaryFormat()
|
||||
{
|
||||
UpdateFormatsIfNeeded();
|
||||
UpdateFormatsIfNeeded(m_last_format_mgr_dynamic);
|
||||
if (HasCustomSummaryFormat())
|
||||
return m_forced_summary_format;
|
||||
return m_last_summary_format;
|
||||
|
@ -744,6 +762,7 @@ protected:
|
|||
|
||||
lldb::Format m_format;
|
||||
uint32_t m_last_format_mgr_revision;
|
||||
lldb::DynamicValueType m_last_format_mgr_dynamic;
|
||||
lldb::SummaryFormatSP m_last_summary_format;
|
||||
lldb::SummaryFormatSP m_forced_summary_format;
|
||||
lldb::ValueFormatSP m_last_value_format;
|
||||
|
@ -759,7 +778,8 @@ protected:
|
|||
m_is_array_item_for_pointer:1,
|
||||
m_is_bitfield_for_scalar:1,
|
||||
m_is_expression_path_child:1,
|
||||
m_is_child_at_offset:1;
|
||||
m_is_child_at_offset:1,
|
||||
m_is_expression_result:1;
|
||||
|
||||
// used to prevent endless looping into GetpPrintableRepresentation()
|
||||
uint32_t m_dump_printable_counter;
|
||||
|
|
|
@ -98,7 +98,8 @@ public:
|
|||
GetMinimumLanguage ();
|
||||
|
||||
static lldb::LanguageType
|
||||
GetMinimumLanguage (lldb::clang_type_t clang_type);
|
||||
GetMinimumLanguage (clang::ASTContext *ctx,
|
||||
lldb::clang_type_t clang_type);
|
||||
|
||||
void
|
||||
DumpValue (ExecutionContext *exe_ctx,
|
||||
|
|
|
@ -72,6 +72,20 @@ public:
|
|||
{
|
||||
return eObjC_VersionUnknown;
|
||||
}
|
||||
|
||||
typedef lldb::addr_t ObjCISA;
|
||||
|
||||
virtual bool
|
||||
IsValidISA(ObjCISA isa) = 0;
|
||||
|
||||
virtual ObjCISA
|
||||
GetISA(ValueObject& valobj) = 0;
|
||||
|
||||
virtual ConstString
|
||||
GetActualTypeName(ObjCISA isa) = 0;
|
||||
|
||||
virtual ObjCISA
|
||||
GetParentClass(ObjCISA isa) = 0;
|
||||
|
||||
// Finds the byte offset of the child_type ivar in parent_type. If it can't find the
|
||||
// offset, returns LLDB_INVALID_IVAR_OFFSET.
|
||||
|
|
|
@ -505,7 +505,8 @@ namespace lldb {
|
|||
eFormatterChoiceCriterionStrippedPointerReference = 0x00000001,
|
||||
eFormatterChoiceCriterionNavigatedTypedefs = 0x00000002,
|
||||
eFormatterChoiceCriterionNavigatedBaseClasses = 0x00000004,
|
||||
eFormatterChoiceCriterionRegularExpressionSummary = 0x00000008
|
||||
eFormatterChoiceCriterionRegularExpressionSummary = 0x00000008,
|
||||
eFormatterChoiceCriterionDynamicObjCHierarchy = 0x00000010
|
||||
} FormatterChoiceCriterion;
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -321,6 +321,9 @@ CommandObjectExpression::EvaluateExpression
|
|||
{
|
||||
if (result_valobj_sp->GetError().Success())
|
||||
{
|
||||
|
||||
result_valobj_sp.get()->SetIsExpressionResult(true);
|
||||
|
||||
if (m_options.format != eFormatDefault)
|
||||
result_valobj_sp->SetFormat (m_options.format);
|
||||
|
||||
|
|
|
@ -1010,22 +1010,35 @@ Debugger::FormatPrompt
|
|||
if (!vobj)
|
||||
break;
|
||||
|
||||
if (log)
|
||||
log->Printf("initial string: %s",var_name_begin);
|
||||
|
||||
// check for *var and *svar
|
||||
if (*var_name_begin == '*')
|
||||
{
|
||||
do_deref_pointer = true;
|
||||
var_name_begin++;
|
||||
}
|
||||
|
||||
if (log)
|
||||
log->Printf("initial string: %s",var_name_begin);
|
||||
|
||||
if (*var_name_begin == 's')
|
||||
{
|
||||
vobj = vobj->GetSyntheticValue(lldb::eUseSyntheticFilter).get();
|
||||
var_name_begin++;
|
||||
}
|
||||
|
||||
if (log)
|
||||
log->Printf("initial string: %s",var_name_begin);
|
||||
|
||||
// should be a 'v' by now
|
||||
if (*var_name_begin != 'v')
|
||||
break;
|
||||
|
||||
if (log)
|
||||
log->Printf("initial string: %s",var_name_begin);
|
||||
|
||||
ValueObject::ExpressionPathAftermath what_next = (do_deref_pointer ?
|
||||
ValueObject::eDereference : ValueObject::eNothing);
|
||||
ValueObject::GetValueForExpressionPathOptions options;
|
||||
|
@ -1765,9 +1778,9 @@ Debugger::Formatting::ForceUpdate()
|
|||
}
|
||||
|
||||
bool
|
||||
Debugger::Formatting::ValueFormats::Get(ValueObject& vobj, ValueFormat::SharedPointer &entry)
|
||||
Debugger::Formatting::ValueFormats::Get(ValueObject& vobj, lldb::DynamicValueType use_dynamic, ValueFormat::SharedPointer &entry)
|
||||
{
|
||||
return GetFormatManager().Value().Get(vobj,entry);
|
||||
return GetFormatManager().Value().Get(vobj,entry, use_dynamic);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1808,15 +1821,17 @@ Debugger::Formatting::ValueFormats::GetCount()
|
|||
|
||||
bool
|
||||
Debugger::Formatting::GetSummaryFormat(ValueObject& vobj,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
lldb::SummaryFormatSP& entry)
|
||||
{
|
||||
return GetFormatManager().Get(vobj, entry);
|
||||
return GetFormatManager().Get(vobj, entry, use_dynamic);
|
||||
}
|
||||
bool
|
||||
Debugger::Formatting::GetSyntheticFilter(ValueObject& vobj,
|
||||
lldb::DynamicValueType use_dynamic,
|
||||
lldb::SyntheticChildrenSP& entry)
|
||||
{
|
||||
return GetFormatManager().Get(vobj, entry);
|
||||
return GetFormatManager().Get(vobj, entry, use_dynamic);
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/FormatClasses.h"
|
||||
#include "lldb/Core/StreamString.h"
|
||||
#include "lldb/Core/ValueObjectConstResult.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Symbol/ClangASTType.h"
|
||||
#include "lldb/Target/StackFrame.h"
|
||||
|
@ -121,8 +122,29 @@ StringSummaryFormat::GetDescription()
|
|||
std::string
|
||||
ScriptSummaryFormat::FormatObject(lldb::ValueObjectSP object)
|
||||
{
|
||||
lldb::ValueObjectSP target_object;
|
||||
if (object->GetIsExpressionResult() &&
|
||||
ClangASTContext::IsPointerType(object->GetClangType()) &&
|
||||
object->GetValue().GetValueType() == Value::eValueTypeHostAddress)
|
||||
{
|
||||
// when using the expression parser, an additional layer of "frozen data"
|
||||
// can be created, which is basically a byte-exact copy of the data returned
|
||||
// by the expression, but in host memory. because Python code might need to read
|
||||
// into the object memory in non-obvious ways, we need to hand it the target version
|
||||
// of the expression output
|
||||
lldb::addr_t tgt_address = object->GetValueAsUnsigned();
|
||||
target_object = ValueObjectConstResult::Create (object->GetExecutionContextScope(),
|
||||
object->GetClangAST(),
|
||||
object->GetClangType(),
|
||||
object->GetName(),
|
||||
tgt_address,
|
||||
eAddressTypeLoad,
|
||||
object->GetUpdatePoint().GetProcessSP()->GetAddressByteSize());
|
||||
}
|
||||
else
|
||||
target_object = object;
|
||||
return std::string(ScriptInterpreterPython::CallPythonScriptFunction(m_function_name.c_str(),
|
||||
object).c_str());
|
||||
target_object).c_str());
|
||||
}
|
||||
|
||||
std::string
|
||||
|
@ -171,7 +193,26 @@ m_python_class(pclass)
|
|||
return;
|
||||
}
|
||||
|
||||
m_interpreter = be->GetUpdatePoint().GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
|
||||
if (be->GetIsExpressionResult() &&
|
||||
ClangASTContext::IsPointerType(be->GetClangType()) &&
|
||||
be->GetValue().GetValueType() == Value::eValueTypeHostAddress)
|
||||
{
|
||||
// when using the expression parser, an additional layer of "frozen data"
|
||||
// can be created, which is basically a byte-exact copy of the data returned
|
||||
// by the expression, but in host memory. because Python code might need to read
|
||||
// into the object memory in non-obvious ways, we need to hand it the target version
|
||||
// of the expression output
|
||||
lldb::addr_t tgt_address = be->GetValueAsUnsigned();
|
||||
m_backend = ValueObjectConstResult::Create (be->GetExecutionContextScope(),
|
||||
be->GetClangAST(),
|
||||
be->GetClangType(),
|
||||
be->GetName(),
|
||||
tgt_address,
|
||||
eAddressTypeLoad,
|
||||
be->GetUpdatePoint().GetProcessSP()->GetAddressByteSize());
|
||||
}
|
||||
|
||||
m_interpreter = m_backend->GetUpdatePoint().GetTargetSP()->GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
|
||||
|
||||
if (m_interpreter == NULL)
|
||||
m_wrapper = NULL;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
|
||||
#include "lldb/Target/ExecutionContext.h"
|
||||
#include "lldb/Target/LanguageRuntime.h"
|
||||
#include "lldb/Target/ObjCLanguageRuntime.h"
|
||||
#include "lldb/Target/Process.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/Target.h"
|
||||
|
@ -76,6 +77,7 @@ ValueObject::ValueObject (ValueObject &parent) :
|
|||
m_deref_valobj(NULL),
|
||||
m_format (eFormatDefault),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_format_mgr_dynamic(lldb::eNoDynamicValues),
|
||||
m_last_summary_format(),
|
||||
m_forced_summary_format(),
|
||||
m_last_value_format(),
|
||||
|
@ -91,6 +93,7 @@ ValueObject::ValueObject (ValueObject &parent) :
|
|||
m_is_bitfield_for_scalar(false),
|
||||
m_is_expression_path_child(false),
|
||||
m_is_child_at_offset(false),
|
||||
m_is_expression_result(false),
|
||||
m_dump_printable_counter(0)
|
||||
{
|
||||
m_manager->ManageObject(this);
|
||||
|
@ -120,6 +123,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
|
|||
m_deref_valobj(NULL),
|
||||
m_format (eFormatDefault),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_format_mgr_dynamic(lldb::eNoDynamicValues),
|
||||
m_last_summary_format(),
|
||||
m_forced_summary_format(),
|
||||
m_last_value_format(),
|
||||
|
@ -135,6 +139,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
|
|||
m_is_bitfield_for_scalar(false),
|
||||
m_is_expression_path_child(false),
|
||||
m_is_child_at_offset(false),
|
||||
m_is_expression_result(false),
|
||||
m_dump_printable_counter(0)
|
||||
{
|
||||
m_manager = new ValueObjectManager();
|
||||
|
@ -150,10 +155,16 @@ ValueObject::~ValueObject ()
|
|||
|
||||
bool
|
||||
ValueObject::UpdateValueIfNeeded (bool update_format)
|
||||
{
|
||||
return UpdateValueIfNeeded(m_last_format_mgr_dynamic, update_format);
|
||||
}
|
||||
|
||||
bool
|
||||
ValueObject::UpdateValueIfNeeded (lldb::DynamicValueType use_dynamic, bool update_format)
|
||||
{
|
||||
|
||||
if (update_format)
|
||||
UpdateFormatsIfNeeded();
|
||||
UpdateFormatsIfNeeded(use_dynamic);
|
||||
|
||||
// If this is a constant value, then our success is predicated on whether
|
||||
// we have an error or not
|
||||
|
@ -204,7 +215,7 @@ ValueObject::UpdateValueIfNeeded (bool update_format)
|
|||
}
|
||||
|
||||
void
|
||||
ValueObject::UpdateFormatsIfNeeded()
|
||||
ValueObject::UpdateFormatsIfNeeded(lldb::DynamicValueType use_dynamic)
|
||||
{
|
||||
LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TYPES));
|
||||
if (log)
|
||||
|
@ -217,7 +228,8 @@ ValueObject::UpdateFormatsIfNeeded()
|
|||
ClearCustomSummaryFormat();
|
||||
m_summary_str.clear();
|
||||
}
|
||||
if (m_last_format_mgr_revision != Debugger::Formatting::ValueFormats::GetCurrentRevision())
|
||||
if ( (m_last_format_mgr_revision != Debugger::Formatting::ValueFormats::GetCurrentRevision()) ||
|
||||
m_last_format_mgr_dynamic != use_dynamic)
|
||||
{
|
||||
if (m_last_summary_format.get())
|
||||
m_last_summary_format.reset((StringSummaryFormat*)NULL);
|
||||
|
@ -228,11 +240,12 @@ ValueObject::UpdateFormatsIfNeeded()
|
|||
|
||||
m_synthetic_value = NULL;
|
||||
|
||||
Debugger::Formatting::ValueFormats::Get(*this, m_last_value_format);
|
||||
Debugger::Formatting::GetSummaryFormat(*this, m_last_summary_format);
|
||||
Debugger::Formatting::GetSyntheticFilter(*this, m_last_synthetic_filter);
|
||||
Debugger::Formatting::ValueFormats::Get(*this, use_dynamic, m_last_value_format);
|
||||
Debugger::Formatting::GetSummaryFormat(*this, use_dynamic, m_last_summary_format);
|
||||
Debugger::Formatting::GetSyntheticFilter(*this, use_dynamic, m_last_synthetic_filter);
|
||||
|
||||
m_last_format_mgr_revision = Debugger::Formatting::ValueFormats::GetCurrentRevision();
|
||||
m_last_format_mgr_dynamic = use_dynamic;
|
||||
|
||||
ClearUserVisibleData();
|
||||
}
|
||||
|
@ -241,14 +254,14 @@ ValueObject::UpdateFormatsIfNeeded()
|
|||
DataExtractor &
|
||||
ValueObject::GetDataExtractor ()
|
||||
{
|
||||
UpdateValueIfNeeded();
|
||||
UpdateValueIfNeeded(false);
|
||||
return m_data;
|
||||
}
|
||||
|
||||
const Error &
|
||||
ValueObject::GetError()
|
||||
{
|
||||
UpdateValueIfNeeded();
|
||||
UpdateValueIfNeeded(false);
|
||||
return m_error;
|
||||
}
|
||||
|
||||
|
@ -261,7 +274,7 @@ ValueObject::GetName() const
|
|||
const char *
|
||||
ValueObject::GetLocationAsCString ()
|
||||
{
|
||||
if (UpdateValueIfNeeded())
|
||||
if (UpdateValueIfNeeded(false))
|
||||
{
|
||||
if (m_location_str.empty())
|
||||
{
|
||||
|
@ -358,7 +371,7 @@ ValueObject::GetChildAtIndex (uint32_t idx, bool can_create)
|
|||
ValueObjectSP child_sp;
|
||||
// We may need to update our value if we are dynamic
|
||||
if (IsPossibleDynamicType ())
|
||||
UpdateValueIfNeeded();
|
||||
UpdateValueIfNeeded(false);
|
||||
if (idx < GetNumChildren())
|
||||
{
|
||||
// Check if we have already made the child value object?
|
||||
|
@ -395,7 +408,7 @@ ValueObject::GetChildMemberWithName (const ConstString &name, bool can_create)
|
|||
|
||||
// We may need to update our value if we are dynamic
|
||||
if (IsPossibleDynamicType ())
|
||||
UpdateValueIfNeeded();
|
||||
UpdateValueIfNeeded(false);
|
||||
|
||||
std::vector<uint32_t> child_indexes;
|
||||
clang::ASTContext *clang_ast = GetClangAST();
|
||||
|
@ -519,7 +532,7 @@ ValueObject::CreateChildAtIndex (uint32_t idx, bool synthetic_array_member, int3
|
|||
const char *
|
||||
ValueObject::GetSummaryAsCString ()
|
||||
{
|
||||
if (UpdateValueIfNeeded ())
|
||||
if (UpdateValueIfNeeded (m_last_format_mgr_dynamic, true))
|
||||
{
|
||||
if (m_summary_str.empty())
|
||||
{
|
||||
|
@ -775,7 +788,7 @@ const char *
|
|||
ValueObject::GetObjectDescription ()
|
||||
{
|
||||
|
||||
if (!UpdateValueIfNeeded ())
|
||||
if (!UpdateValueIfNeeded (m_last_format_mgr_dynamic, true))
|
||||
return NULL;
|
||||
|
||||
if (!m_object_desc_str.empty())
|
||||
|
@ -826,7 +839,7 @@ ValueObject::GetValueAsCString ()
|
|||
// If our byte size is zero this is an aggregate type that has children
|
||||
if (ClangASTContext::IsAggregateType (GetClangType()) == false)
|
||||
{
|
||||
if (UpdateValueIfNeeded())
|
||||
if (UpdateValueIfNeeded(true))
|
||||
{
|
||||
if (m_value_str.empty())
|
||||
{
|
||||
|
@ -841,7 +854,7 @@ ValueObject::GetValueAsCString ()
|
|||
clang_type_t clang_type = GetClangType ();
|
||||
if (clang_type)
|
||||
{
|
||||
if (m_last_value_format)
|
||||
if (m_format == lldb::eFormatDefault && m_last_value_format)
|
||||
{
|
||||
m_value_str = m_last_value_format->FormatObject(GetSP());
|
||||
}
|
||||
|
@ -905,6 +918,24 @@ ValueObject::GetValueAsCString ()
|
|||
return m_value_str.c_str();
|
||||
}
|
||||
|
||||
// if > 8bytes, 0 is returned. this method should mostly be used
|
||||
// to read address values out of pointers
|
||||
unsigned long long
|
||||
ValueObject::GetValueAsUnsigned()
|
||||
{
|
||||
// If our byte size is zero this is an aggregate type that has children
|
||||
if (ClangASTContext::IsAggregateType (GetClangType()) == false)
|
||||
{
|
||||
if (UpdateValueIfNeeded(true))
|
||||
{
|
||||
uint32_t offset = 0;
|
||||
return m_data.GetMaxU64(&offset,
|
||||
m_data.GetByteSize());
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// this call should only return pointers to data that needs no special memory management
|
||||
// (either because they are hardcoded strings, or because they are backed by some other
|
||||
// object); returning any new()-ed or malloc()-ed data here, will lead to leaks!
|
||||
|
@ -1092,7 +1123,7 @@ ValueObject::DumpPrintableRepresentation(Stream& s,
|
|||
addr_t
|
||||
ValueObject::GetAddressOf (AddressType &address_type, bool scalar_is_load_address)
|
||||
{
|
||||
if (!UpdateValueIfNeeded())
|
||||
if (!UpdateValueIfNeeded(false))
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
|
||||
switch (m_value.GetValueType())
|
||||
|
@ -1124,7 +1155,7 @@ ValueObject::GetPointerValue (AddressType &address_type, bool scalar_is_load_add
|
|||
lldb::addr_t address = LLDB_INVALID_ADDRESS;
|
||||
address_type = eAddressTypeInvalid;
|
||||
|
||||
if (!UpdateValueIfNeeded())
|
||||
if (!UpdateValueIfNeeded(false))
|
||||
return address;
|
||||
|
||||
switch (m_value.GetValueType())
|
||||
|
@ -1161,7 +1192,7 @@ ValueObject::SetValueFromCString (const char *value_str)
|
|||
{
|
||||
// Make sure our value is up to date first so that our location and location
|
||||
// type is valid.
|
||||
if (!UpdateValueIfNeeded())
|
||||
if (!UpdateValueIfNeeded(false))
|
||||
return false;
|
||||
|
||||
uint32_t count = 0;
|
||||
|
@ -1256,7 +1287,8 @@ ValueObject::Write ()
|
|||
lldb::LanguageType
|
||||
ValueObject::GetObjectRuntimeLanguage ()
|
||||
{
|
||||
return ClangASTType::GetMinimumLanguage (GetClangType());
|
||||
return ClangASTType::GetMinimumLanguage (GetClangAST(),
|
||||
GetClangType());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1521,7 +1553,7 @@ ValueObject::CalculateSyntheticValue (lldb::SyntheticValueType use_synthetic)
|
|||
if (use_synthetic == lldb::eNoSyntheticFilter)
|
||||
return;
|
||||
|
||||
UpdateFormatsIfNeeded();
|
||||
UpdateFormatsIfNeeded(m_last_format_mgr_dynamic);
|
||||
|
||||
if (m_last_synthetic_filter.get() == NULL)
|
||||
return;
|
||||
|
@ -1601,7 +1633,7 @@ ValueObject::GetSyntheticValue (SyntheticValueType use_synthetic)
|
|||
if (use_synthetic == lldb::eNoSyntheticFilter)
|
||||
return GetSP();
|
||||
|
||||
UpdateFormatsIfNeeded();
|
||||
UpdateFormatsIfNeeded(m_last_format_mgr_dynamic);
|
||||
|
||||
if (m_last_synthetic_filter.get() == NULL)
|
||||
return GetSP();
|
||||
|
@ -2537,7 +2569,7 @@ ValueObject::DumpValueObject
|
|||
{
|
||||
if (valobj)
|
||||
{
|
||||
bool update_success = valobj->UpdateValueIfNeeded ();
|
||||
bool update_success = valobj->UpdateValueIfNeeded (use_dynamic, true);
|
||||
|
||||
if (update_success && use_dynamic != lldb::eNoDynamicValues)
|
||||
{
|
||||
|
@ -2566,7 +2598,33 @@ ValueObject::DumpValueObject
|
|||
|
||||
// Always show the type for the top level items.
|
||||
if (show_types || (curr_depth == 0 && !flat_output))
|
||||
s.Printf("(%s) ", valobj->GetTypeName().AsCString("<invalid type>"));
|
||||
{
|
||||
s.Printf("(%s", valobj->GetTypeName().AsCString("<invalid type>"));
|
||||
if (use_dynamic != lldb::eNoDynamicValues &&
|
||||
strcmp(valobj->GetTypeName().AsCString("NULL"), "id") == 0)
|
||||
{
|
||||
Process* process = valobj->GetUpdatePoint().GetProcessSP().get();
|
||||
if (process == NULL)
|
||||
s.Printf(") ");
|
||||
else
|
||||
{
|
||||
ObjCLanguageRuntime *runtime = process->GetObjCLanguageRuntime();
|
||||
if (runtime == NULL)
|
||||
s.Printf(") ");
|
||||
else
|
||||
{
|
||||
ObjCLanguageRuntime::ObjCISA isa = runtime->GetISA(*valobj);
|
||||
if (!runtime->IsValidISA(isa))
|
||||
s.Printf(") ");
|
||||
else
|
||||
s.Printf(", dynamic type: %s) ",
|
||||
runtime->GetActualTypeName(isa).GetCString());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
s.Printf(") ");
|
||||
}
|
||||
|
||||
|
||||
if (flat_output)
|
||||
|
@ -2758,7 +2816,7 @@ ValueObject::CreateConstantValue (const ConstString &name)
|
|||
{
|
||||
ValueObjectSP valobj_sp;
|
||||
|
||||
if (UpdateValueIfNeeded() && m_error.Success())
|
||||
if (UpdateValueIfNeeded(false) && m_error.Success())
|
||||
{
|
||||
ExecutionContextScope *exe_scope = GetExecutionContextScope();
|
||||
if (exe_scope)
|
||||
|
@ -2957,7 +3015,6 @@ ValueObject::CastPointerType (const char *name, TypeSP &type_sp)
|
|||
return valobj_sp;
|
||||
}
|
||||
|
||||
|
||||
ValueObject::EvaluationPoint::EvaluationPoint () :
|
||||
m_thread_id (LLDB_INVALID_UID),
|
||||
m_stop_id (0)
|
||||
|
|
|
@ -97,7 +97,7 @@ ValueObjectChild::UpdateValue ()
|
|||
ValueObject* parent = m_parent;
|
||||
if (parent)
|
||||
{
|
||||
if (parent->UpdateValueIfNeeded())
|
||||
if (parent->UpdateValueIfNeeded(false))
|
||||
{
|
||||
m_value.SetContext(Value::eContextTypeClangType, m_clang_type);
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ ValueObjectDynamicValue::GetClangType ()
|
|||
ConstString
|
||||
ValueObjectDynamicValue::GetTypeName()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded();
|
||||
const bool success = UpdateValueIfNeeded(false);
|
||||
if (success && m_type_sp)
|
||||
return ClangASTType::GetConstTypeName (GetClangType());
|
||||
else
|
||||
|
@ -70,7 +70,7 @@ ValueObjectDynamicValue::GetTypeName()
|
|||
uint32_t
|
||||
ValueObjectDynamicValue::CalculateNumChildren()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded();
|
||||
const bool success = UpdateValueIfNeeded(false);
|
||||
if (success && m_type_sp)
|
||||
return ClangASTContext::GetNumChildren (GetClangAST (), GetClangType(), true);
|
||||
else
|
||||
|
@ -90,7 +90,7 @@ ValueObjectDynamicValue::GetClangAST ()
|
|||
size_t
|
||||
ValueObjectDynamicValue::GetByteSize()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded();
|
||||
const bool success = UpdateValueIfNeeded(false);
|
||||
if (success && m_type_sp)
|
||||
return m_value.GetValueByteSize(GetClangAST(), NULL);
|
||||
else
|
||||
|
@ -109,7 +109,7 @@ ValueObjectDynamicValue::UpdateValue ()
|
|||
SetValueIsValid (false);
|
||||
m_error.Clear();
|
||||
|
||||
if (!m_parent->UpdateValueIfNeeded())
|
||||
if (!m_parent->UpdateValueIfNeeded(false))
|
||||
{
|
||||
// The dynamic value failed to get an error, pass the error along
|
||||
if (m_error.Success() && m_parent->GetError().Fail())
|
||||
|
|
|
@ -63,6 +63,30 @@ public:
|
|||
virtual lldb::ThreadPlanSP
|
||||
GetStepThroughTrampolinePlan (Thread &thread, bool stop_others);
|
||||
|
||||
virtual bool
|
||||
IsValidISA(ObjCISA isa)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ObjCISA
|
||||
GetISA(ValueObject& valobj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ConstString
|
||||
GetActualTypeName(ObjCISA isa)
|
||||
{
|
||||
return ConstString(NULL);
|
||||
}
|
||||
|
||||
virtual ObjCISA
|
||||
GetParentClass(ObjCISA isa)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Static Functions
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -72,6 +72,31 @@ public:
|
|||
{
|
||||
return eAppleObjC_V1;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
IsValidISA(ObjCISA isa)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ObjCISA
|
||||
GetISA(ValueObject& valobj)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual ConstString
|
||||
GetActualTypeName(ObjCISA isa)
|
||||
{
|
||||
return ConstString(NULL);
|
||||
}
|
||||
|
||||
virtual ObjCISA
|
||||
GetParentClass(ObjCISA isa)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
private:
|
||||
|
|
|
@ -563,4 +563,90 @@ AppleObjCRuntimeV2::GetByteOffsetForIvar (ClangASTType &parent_ast_type, const c
|
|||
return ivar_offset;
|
||||
}
|
||||
|
||||
lldb_private::ObjCLanguageRuntime::ObjCISA
|
||||
AppleObjCRuntimeV2::GetISA(ValueObject& valobj)
|
||||
{
|
||||
if (ClangASTType::GetMinimumLanguage(valobj.GetClangAST(),valobj.GetClangType()) != lldb::eLanguageTypeObjC)
|
||||
return 0;
|
||||
|
||||
uint32_t offset = 0;
|
||||
uint64_t isa_pointer = valobj.GetDataExtractor().GetPointer(&offset);
|
||||
|
||||
uint8_t pointer_size = valobj.GetUpdatePoint().GetProcessSP()->GetAddressByteSize();
|
||||
|
||||
Error error;
|
||||
lldb_private::ObjCLanguageRuntime::ObjCISA isa =
|
||||
valobj.GetUpdatePoint().GetProcessSP()->ReadUnsignedIntegerFromMemory(isa_pointer,
|
||||
pointer_size,
|
||||
0,
|
||||
error);
|
||||
return isa;
|
||||
}
|
||||
|
||||
ConstString
|
||||
AppleObjCRuntimeV2::GetActualTypeName(lldb_private::ObjCLanguageRuntime::ObjCISA isa)
|
||||
{
|
||||
if (!IsValidISA(isa))
|
||||
return ConstString(NULL);
|
||||
|
||||
uint8_t pointer_size = m_process->GetAddressByteSize();
|
||||
Error error;
|
||||
lldb::addr_t rw_pointer = isa + (4 * pointer_size);
|
||||
//printf("rw_pointer: %llx\n", rw_pointer);
|
||||
|
||||
uint64_t data_pointer = m_process->ReadUnsignedIntegerFromMemory(rw_pointer,
|
||||
pointer_size,
|
||||
0,
|
||||
error);
|
||||
if (error.Fail())
|
||||
return ConstString("unknown");
|
||||
|
||||
data_pointer += 8;
|
||||
//printf("data_pointer: %llx\n", data_pointer);
|
||||
uint64_t ro_pointer = m_process->ReadUnsignedIntegerFromMemory(data_pointer,
|
||||
pointer_size,
|
||||
0,
|
||||
error);
|
||||
if (error.Fail())
|
||||
return ConstString("unknown");
|
||||
|
||||
ro_pointer += 12;
|
||||
if (pointer_size == 8)
|
||||
ro_pointer += 4;
|
||||
ro_pointer += pointer_size;
|
||||
//printf("ro_pointer: %llx\n", ro_pointer);
|
||||
uint64_t name_pointer = m_process->ReadUnsignedIntegerFromMemory(ro_pointer,
|
||||
pointer_size,
|
||||
0,
|
||||
error);
|
||||
if (error.Fail())
|
||||
return ConstString("unknown");
|
||||
|
||||
//printf("name_pointer: %llx\n", name_pointer);
|
||||
char* cstr = new char[512];
|
||||
if (m_process->ReadCStringFromMemory(name_pointer, cstr, 512) > 0)
|
||||
return ConstString(cstr);
|
||||
else
|
||||
return ConstString("unknown");
|
||||
}
|
||||
|
||||
lldb_private::ObjCLanguageRuntime::ObjCISA
|
||||
AppleObjCRuntimeV2::GetParentClass(lldb_private::ObjCLanguageRuntime::ObjCISA isa)
|
||||
{
|
||||
if (!IsValidISA(isa))
|
||||
return 0;
|
||||
|
||||
uint8_t pointer_size = m_process->GetAddressByteSize();
|
||||
Error error;
|
||||
lldb::addr_t parent_pointer = isa + pointer_size;
|
||||
//printf("rw_pointer: %llx\n", rw_pointer);
|
||||
|
||||
uint64_t parent_isa = m_process->ReadUnsignedIntegerFromMemory(parent_pointer,
|
||||
pointer_size,
|
||||
0,
|
||||
error);
|
||||
if (error.Fail())
|
||||
return 0;
|
||||
return parent_isa;
|
||||
}
|
||||
|
||||
|
|
|
@ -76,7 +76,21 @@ public:
|
|||
|
||||
virtual size_t
|
||||
GetByteOffsetForIvar (ClangASTType &parent_qual_type, const char *ivar_name);
|
||||
|
||||
|
||||
virtual bool
|
||||
IsValidISA(ObjCISA isa)
|
||||
{
|
||||
return (isa != 0);
|
||||
}
|
||||
|
||||
virtual ObjCISA
|
||||
GetISA(ValueObject& valobj);
|
||||
|
||||
virtual ConstString
|
||||
GetActualTypeName(ObjCISA isa);
|
||||
|
||||
virtual ObjCISA
|
||||
GetParentClass(ObjCISA isa);
|
||||
|
||||
protected:
|
||||
|
||||
|
|
|
@ -159,11 +159,13 @@ ClangASTType::GetEncoding (uint32_t &count)
|
|||
lldb::LanguageType
|
||||
ClangASTType::GetMinimumLanguage ()
|
||||
{
|
||||
return ClangASTType::GetMinimumLanguage (m_type);
|
||||
return ClangASTType::GetMinimumLanguage (m_ast,
|
||||
m_type);
|
||||
}
|
||||
|
||||
lldb::LanguageType
|
||||
ClangASTType::GetMinimumLanguage (lldb::clang_type_t clang_type)
|
||||
ClangASTType::GetMinimumLanguage (clang::ASTContext *ctx,
|
||||
lldb::clang_type_t clang_type)
|
||||
{
|
||||
if (clang_type == NULL)
|
||||
return lldb::eLanguageTypeC;
|
||||
|
@ -182,6 +184,8 @@ ClangASTType::GetMinimumLanguage (lldb::clang_type_t clang_type)
|
|||
return lldb::eLanguageTypeObjC;
|
||||
if (pointee_type->isObjCClassType())
|
||||
return lldb::eLanguageTypeObjC;
|
||||
if (pointee_type.getTypePtr() == ctx->ObjCBuiltinIdTy.getTypePtr())
|
||||
return lldb::eLanguageTypeObjC;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -238,7 +242,8 @@ ClangASTType::GetMinimumLanguage (lldb::clang_type_t clang_type)
|
|||
}
|
||||
break;
|
||||
case clang::Type::Typedef:
|
||||
return GetMinimumLanguage(llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
||||
return GetMinimumLanguage(ctx,
|
||||
llvm::cast<clang::TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
||||
}
|
||||
}
|
||||
return lldb::eLanguageTypeC;
|
||||
|
|
|
@ -286,7 +286,7 @@ class DataFormatterTestCase(TestBase):
|
|||
substrs = ['ACircle',
|
||||
'ARectangle',
|
||||
'ACircle',
|
||||
'ARectangleStar'])
|
||||
'ARectangle'])
|
||||
|
||||
# Check that abruptly deleting an enabled category does not crash us
|
||||
self.runCmd("type category delete RectangleCategory")
|
||||
|
|
|
@ -164,7 +164,7 @@ class DataFormatterTestCase(TestBase):
|
|||
'inline = ',
|
||||
'explicit = ',
|
||||
'content = ',
|
||||
'a very much boring task to write a string this way!!\\xe4\\x8c\\xb3'])
|
||||
'a very much boring task to write a string this way!!\\xcf\\x83'])
|
||||
|
||||
self.expect('frame variable str10 -P 1 -Y',
|
||||
substrs = ['mutable =',
|
||||
|
@ -215,7 +215,7 @@ class DataFormatterTestCase(TestBase):
|
|||
self.expect('frame variable str8',
|
||||
substrs = ['hasVeryLongExtensionThisTime'])
|
||||
self.expect('frame variable str9',
|
||||
substrs = ['a very much boring task to write a string this way!!\\xe4\\x8c\\xb3'])
|
||||
substrs = ['a very much boring task to write a string this way!!\\xcf\\x83'])
|
||||
self.expect('frame variable str10',
|
||||
substrs = ['This is a Unicode string \\xcf\\x83 number 4 right here'])
|
||||
self.expect('frame variable str11',
|
||||
|
@ -224,6 +224,25 @@ class DataFormatterTestCase(TestBase):
|
|||
substrs = ['a.out'])
|
||||
self.expect('frame variable str12',
|
||||
substrs = ['Process Name: a.out Process Id:'])
|
||||
self.expect('frame variable dyn_test', matching=False,
|
||||
substrs = ['Process Name: a.out Process Id:'])
|
||||
self.expect('frame variable dyn_test -d run-target',
|
||||
substrs = ['(id, dynamic type:',
|
||||
'Process Name: a.out Process Id:'])
|
||||
|
||||
|
||||
# check that we can format stuff out of the expression parser
|
||||
self.expect('expression ((id)@"Hello")', matching=False,
|
||||
substrs = ['Hello'])
|
||||
|
||||
self.expect('expression -d true -- ((id)@"Hello")',
|
||||
substrs = ['Hello'])
|
||||
|
||||
self.expect('expr -d true -- label1',
|
||||
substrs = ['Process Name'])
|
||||
|
||||
self.expect('expr -d true -- @"Hello"',
|
||||
substrs = ['Hello'])
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
|
|
|
@ -117,6 +117,8 @@ int main (int argc, const char * argv[])
|
|||
NSString *processID = [NSString stringWithFormat:@"%d", [[NSProcessInfo processInfo] processIdentifier]];
|
||||
NSString *str12 = [NSString stringWithFormat:@"%@ %@ %@ %@", label1, processName, label2, processID];
|
||||
|
||||
id dyn_test = str12;
|
||||
|
||||
// Set break point at this line.
|
||||
[pool drain];
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue