forked from OSchip/llvm-project
several improvements to "type summary":
- type names can now be regular expressions (exact matching is done first, and is faster) - integral (and floating) types can be printed as bitfields, i.e. ${var[low-high]} will extract bits low thru high of the value and print them - array subscripts are supported, both for arrays and for pointers. the syntax is ${*var[low-high]}, or ${*var[]} to print the whole array (the latter only works for statically sized arrays) - summary is now printed by default when a summary string references a variable. if that variable's type has no summary, value is printed instead. to force value, you can use %V as a format specifier - basic support for ObjectiveC: - ObjectiveC inheritance chains are now walked through - %@ can be specified as a summary format, to print the ObjectiveC runtime description for an object - some bug fixes llvm-svn: 134293
This commit is contained in:
parent
bf15d2b311
commit
0a3958e046
|
@ -476,48 +476,82 @@ public:
|
|||
|
||||
class ValueFormats
|
||||
{
|
||||
public:
|
||||
static bool
|
||||
Get(ValueObject& vobj, ValueFormat::SharedPointer &entry);
|
||||
|
||||
static void
|
||||
Add(const ConstString &type, const ValueFormat::SharedPointer &entry);
|
||||
|
||||
static bool
|
||||
Delete(const ConstString &type);
|
||||
|
||||
static void
|
||||
Clear();
|
||||
|
||||
static void
|
||||
LoopThrough(FormatManager::ValueCallback callback, void* callback_baton);
|
||||
|
||||
static uint32_t GetCurrentRevision();
|
||||
public:
|
||||
static bool
|
||||
Get(ValueObject& vobj, ValueFormat::SharedPointer &entry);
|
||||
|
||||
static void
|
||||
Add(const ConstString &type, const ValueFormat::SharedPointer &entry);
|
||||
|
||||
static bool
|
||||
Delete(const ConstString &type);
|
||||
|
||||
static void
|
||||
Clear();
|
||||
|
||||
static void
|
||||
LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton);
|
||||
|
||||
static uint32_t
|
||||
GetCurrentRevision();
|
||||
|
||||
static uint32_t
|
||||
GetCount();
|
||||
};
|
||||
|
||||
class SummaryFormats
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
static bool
|
||||
Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry);
|
||||
|
||||
static bool
|
||||
Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry);
|
||||
|
||||
static void
|
||||
Add(const ConstString &type, const SummaryFormat::SharedPointer &entry);
|
||||
|
||||
static bool
|
||||
Delete(const ConstString &type);
|
||||
|
||||
static void
|
||||
Clear();
|
||||
|
||||
static void
|
||||
LoopThrough(FormatManager::SummaryCallback callback, void* callback_baton);
|
||||
|
||||
static uint32_t
|
||||
GetCurrentRevision();
|
||||
static void
|
||||
Add(const ConstString &type, const SummaryFormat::SharedPointer &entry);
|
||||
|
||||
static bool
|
||||
Delete(const ConstString &type);
|
||||
|
||||
static void
|
||||
Clear();
|
||||
|
||||
static void
|
||||
LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton);
|
||||
|
||||
static uint32_t
|
||||
GetCurrentRevision();
|
||||
|
||||
static uint32_t
|
||||
GetCount();
|
||||
};
|
||||
|
||||
class RegexSummaryFormats
|
||||
{
|
||||
public:
|
||||
|
||||
static bool
|
||||
Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry);
|
||||
|
||||
static void
|
||||
Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry);
|
||||
|
||||
static bool
|
||||
Delete(const ConstString &type);
|
||||
|
||||
static void
|
||||
Clear();
|
||||
|
||||
static void
|
||||
LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton);
|
||||
|
||||
static uint32_t
|
||||
GetCurrentRevision();
|
||||
|
||||
static uint32_t
|
||||
GetCount();
|
||||
};
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace lldb_private
|
||||
|
|
|
@ -33,6 +33,10 @@ namespace std
|
|||
#include <stack>
|
||||
|
||||
// Other libraries and framework includes
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/AST/DeclObjC.h"
|
||||
|
||||
// Project includes
|
||||
#include "lldb/lldb-public.h"
|
||||
#include "lldb/lldb-enumerations.h"
|
||||
|
@ -40,6 +44,7 @@ namespace std
|
|||
#include "lldb/Core/Communication.h"
|
||||
#include "lldb/Core/InputReaderStack.h"
|
||||
#include "lldb/Core/Listener.h"
|
||||
#include "lldb/Core/RegularExpression.h"
|
||||
#include "lldb/Core/StreamFile.h"
|
||||
#include "lldb/Core/SourceManager.h"
|
||||
#include "lldb/Core/UserID.h"
|
||||
|
@ -49,9 +54,6 @@ namespace std
|
|||
#include "lldb/Target/Platform.h"
|
||||
#include "lldb/Target/TargetList.h"
|
||||
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Type.h"
|
||||
|
||||
namespace lldb_private {
|
||||
|
||||
class IFormatChangeListener
|
||||
|
@ -72,12 +74,22 @@ struct SummaryFormat
|
|||
bool m_dont_show_value;
|
||||
bool m_show_members_oneliner;
|
||||
bool m_cascades;
|
||||
SummaryFormat(std::string f = "", bool c = false, bool nochildren = true, bool novalue = true, bool oneliner = false) :
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
SummaryFormat(std::string f = "",
|
||||
bool c = false,
|
||||
bool nochildren = true,
|
||||
bool novalue = true,
|
||||
bool oneliner = false,
|
||||
bool skipptr = false,
|
||||
bool skipref = false) :
|
||||
m_format(f),
|
||||
m_dont_show_children(nochildren),
|
||||
m_dont_show_value(novalue),
|
||||
m_show_members_oneliner(oneliner),
|
||||
m_cascades(c)
|
||||
m_cascades(c),
|
||||
m_skip_references(skipref),
|
||||
m_skip_pointers(skipptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -100,6 +112,8 @@ struct SummaryFormat
|
|||
}
|
||||
|
||||
typedef lldb::SharedPtr<SummaryFormat>::Type SharedPointer;
|
||||
typedef bool(*SummaryCallback)(void*, const char*, const SummaryFormat::SharedPointer&);
|
||||
typedef bool(*RegexSummaryCallback)(void*, lldb::RegularExpressionSP, const SummaryFormat::SharedPointer&);
|
||||
|
||||
};
|
||||
|
||||
|
@ -107,13 +121,21 @@ struct ValueFormat
|
|||
{
|
||||
lldb::Format m_format;
|
||||
bool m_cascades;
|
||||
ValueFormat (lldb::Format f = lldb::eFormatInvalid, bool c = false) :
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
ValueFormat (lldb::Format f = lldb::eFormatInvalid,
|
||||
bool c = false,
|
||||
bool skipptr = false,
|
||||
bool skipref = false) :
|
||||
m_format (f),
|
||||
m_cascades (c)
|
||||
m_cascades (c),
|
||||
m_skip_references(skipref),
|
||||
m_skip_pointers(skipptr)
|
||||
{
|
||||
}
|
||||
|
||||
typedef lldb::SharedPtr<ValueFormat>::Type SharedPointer;
|
||||
typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
|
||||
|
||||
~ValueFormat()
|
||||
{
|
||||
|
@ -160,7 +182,7 @@ public:
|
|||
}
|
||||
|
||||
bool
|
||||
Delete(const MapKeyType& type)
|
||||
Delete(const char* type)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
MapIterator iter = m_map.find(type);
|
||||
|
@ -197,6 +219,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
GetCount()
|
||||
{
|
||||
return m_map.size();
|
||||
}
|
||||
|
||||
~FormatNavigator()
|
||||
{
|
||||
}
|
||||
|
@ -210,7 +238,7 @@ private:
|
|||
DISALLOW_COPY_AND_ASSIGN(FormatNavigator);
|
||||
|
||||
bool
|
||||
Get(const MapKeyType &type, MapValueType& entry)
|
||||
Get(const char* type, MapValueType& entry)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
MapIterator iter = m_map.find(type);
|
||||
|
@ -228,16 +256,62 @@ private:
|
|||
return false;
|
||||
clang::QualType type = q_type.getUnqualifiedType();
|
||||
type.removeLocalConst(); type.removeLocalVolatile(); type.removeLocalRestrict();
|
||||
ConstString name(type.getAsString().c_str());
|
||||
const clang::Type* typePtr = type.getTypePtrOrNull();
|
||||
if (!typePtr)
|
||||
return false;
|
||||
ConstString name(ClangASTType::GetTypeNameForQualType(type).c_str());
|
||||
//printf("trying to get format for VO name %s of type %s\n",vobj.GetName().AsCString(),name.AsCString());
|
||||
if (Get(name.GetCString(), entry))
|
||||
return true;
|
||||
// look for a "base type", whatever that means
|
||||
const clang::Type* typePtr = type.getTypePtrOrNull();
|
||||
if (!typePtr)
|
||||
return false;
|
||||
if (typePtr->isReferenceType())
|
||||
return Get(vobj,type.getNonReferenceType(),entry);
|
||||
{
|
||||
if (Get(vobj,type.getNonReferenceType(),entry) && !entry->m_skip_references)
|
||||
return true;
|
||||
}
|
||||
if (typePtr->isPointerType())
|
||||
{
|
||||
if (Get(vobj, typePtr->getPointeeType(), entry) && !entry->m_skip_pointers)
|
||||
return true;
|
||||
}
|
||||
if (typePtr->isObjCObjectPointerType())
|
||||
{
|
||||
/*
|
||||
for some reason, C++ can quite easily obtain the type hierarchy for a ValueObject
|
||||
even if the VO represent a pointer-to-class, as long as the typePtr is right
|
||||
Objective-C on the other hand cannot really complete an @interface when
|
||||
the VO refers to a pointer-to-@interface
|
||||
*/
|
||||
Error error;
|
||||
ValueObject* target = vobj.Dereference(error).get();
|
||||
if(error.Fail() || !target)
|
||||
return false;
|
||||
if (Get(*target, typePtr->getPointeeType(), entry) && !entry->m_skip_pointers)
|
||||
return true;
|
||||
}
|
||||
const clang::ObjCObjectType *objc_class_type = typePtr->getAs<clang::ObjCObjectType>();
|
||||
if (objc_class_type)
|
||||
{
|
||||
//printf("working with ObjC\n");
|
||||
clang::ASTContext *ast = vobj.GetClangAST();
|
||||
if (ClangASTContext::GetCompleteType(ast, vobj.GetClangType()) && !objc_class_type->isObjCId())
|
||||
{
|
||||
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
||||
if(class_interface_decl)
|
||||
{
|
||||
//printf("down here\n");
|
||||
clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
|
||||
//printf("one further step and we're there...\n");
|
||||
if(superclass_interface_decl)
|
||||
{
|
||||
//printf("the end is here\n");
|
||||
clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl));
|
||||
if (Get(vobj, ivar_qual_type, entry) && entry->m_cascades)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// for C++ classes, navigate up the hierarchy
|
||||
if (typePtr->isRecordType())
|
||||
{
|
||||
|
@ -245,15 +319,7 @@ private:
|
|||
if (record)
|
||||
{
|
||||
if (!record->hasDefinition())
|
||||
// dummy call to do the complete
|
||||
ClangASTContext::GetNumChildren(vobj.GetClangAST(), vobj.GetClangType(), false);
|
||||
clang::IdentifierInfo *info = record->getIdentifier();
|
||||
if (info) {
|
||||
// this is the class name, plain and simple
|
||||
ConstString id_info(info->getName().str().c_str());
|
||||
if (Get(id_info.GetCString(), entry))
|
||||
return true;
|
||||
}
|
||||
ClangASTContext::GetCompleteType(vobj.GetClangAST(), vobj.GetClangType());
|
||||
if (record->hasDefinition())
|
||||
{
|
||||
clang::CXXRecordDecl::base_class_iterator pos,end;
|
||||
|
@ -287,25 +353,34 @@ private:
|
|||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
bool
|
||||
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Get(const char* key,
|
||||
SummaryFormat::SharedPointer& value);
|
||||
|
||||
template<>
|
||||
bool
|
||||
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Delete(const char* type);
|
||||
|
||||
class FormatManager : public IFormatChangeListener
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
typedef bool(*ValueCallback)(void*, const char*, const ValueFormat::SharedPointer&);
|
||||
typedef bool(*SummaryCallback)(void*, const char*, const SummaryFormat::SharedPointer&);
|
||||
|
||||
private:
|
||||
|
||||
typedef std::map<const char*, ValueFormat::SharedPointer> ValueMap;
|
||||
typedef std::map<const char*, SummaryFormat::SharedPointer> SummaryMap;
|
||||
typedef std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer> RegexSummaryMap;
|
||||
|
||||
typedef FormatNavigator<ValueMap, ValueCallback> ValueNavigator;
|
||||
typedef FormatNavigator<SummaryMap, SummaryCallback> SummaryNavigator;
|
||||
typedef FormatNavigator<ValueMap, ValueFormat::ValueCallback> ValueNavigator;
|
||||
typedef FormatNavigator<SummaryMap, SummaryFormat::SummaryCallback> SummaryNavigator;
|
||||
typedef FormatNavigator<RegexSummaryMap, SummaryFormat::RegexSummaryCallback> RegexSummaryNavigator;
|
||||
|
||||
ValueNavigator m_value_nav;
|
||||
SummaryNavigator m_summary_nav;
|
||||
RegexSummaryNavigator m_regex_summary_nav;
|
||||
|
||||
uint32_t m_last_revision;
|
||||
|
||||
|
@ -314,6 +389,7 @@ public:
|
|||
FormatManager() :
|
||||
m_value_nav(this),
|
||||
m_summary_nav(this),
|
||||
m_regex_summary_nav(this),
|
||||
m_last_revision(0)
|
||||
{
|
||||
}
|
||||
|
@ -321,6 +397,8 @@ public:
|
|||
|
||||
ValueNavigator& Value() { return m_value_nav; }
|
||||
SummaryNavigator& Summary() { return m_summary_nav; }
|
||||
RegexSummaryNavigator& RegexSummary() { return m_regex_summary_nav; }
|
||||
|
||||
|
||||
static bool
|
||||
GetFormatFromCString (const char *format_cstr,
|
||||
|
|
|
@ -149,6 +149,9 @@ public:
|
|||
//------------------------------------------------------------------
|
||||
bool
|
||||
IsValid () const;
|
||||
|
||||
bool
|
||||
operator < (const RegularExpression& rhs) const;
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------
|
||||
|
|
|
@ -70,6 +70,13 @@ public:
|
|||
eDereferencePointers = 1,
|
||||
eHonorPointers,
|
||||
};
|
||||
|
||||
enum ValueObjectRepresentationStyle
|
||||
{
|
||||
eDisplayValue,
|
||||
eDisplaySummary,
|
||||
eDisplayLanguageSpecific
|
||||
};
|
||||
|
||||
class EvaluationPoint
|
||||
{
|
||||
|
@ -344,6 +351,10 @@ public:
|
|||
|
||||
const char *
|
||||
GetObjectDescription ();
|
||||
|
||||
const char *
|
||||
GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display = eDisplaySummary,
|
||||
lldb::Format custom_format = lldb::eFormatInvalid);
|
||||
|
||||
bool
|
||||
GetValueIsValid () const;
|
||||
|
@ -352,7 +363,7 @@ public:
|
|||
GetValueDidChange ();
|
||||
|
||||
bool
|
||||
UpdateValueIfNeeded ();
|
||||
UpdateValueIfNeeded (bool update_format = true);
|
||||
|
||||
void
|
||||
UpdateFormatsIfNeeded();
|
||||
|
@ -525,7 +536,8 @@ protected:
|
|||
m_children_count_valid:1,
|
||||
m_old_value_valid:1,
|
||||
m_pointers_point_to_load_addrs:1,
|
||||
m_is_deref_of_parent:1;
|
||||
m_is_deref_of_parent:1,
|
||||
m_is_array_item_for_pointer:1;
|
||||
|
||||
friend class ClangExpressionDeclMap; // For GetValue
|
||||
friend class ClangExpressionVariable; // For SetName
|
||||
|
|
|
@ -351,6 +351,7 @@ namespace lldb {
|
|||
eArgTypeExprFormat,
|
||||
eArgTypeFilename,
|
||||
eArgTypeFormat,
|
||||
eArgTypeFormatString,
|
||||
eArgTypeFrameIndex,
|
||||
eArgTypeFullName,
|
||||
eArgTypeFunctionName,
|
||||
|
|
|
@ -53,6 +53,7 @@ namespace lldb {
|
|||
typedef SharedPtr<lldb_private::Platform>::Type PlatformSP;
|
||||
typedef SharedPtr<lldb_private::Process>::Type ProcessSP;
|
||||
typedef SharedPtr<lldb_private::RegisterContext>::Type RegisterContextSP;
|
||||
typedef SharedPtr<lldb_private::RegularExpression>::Type RegularExpressionSP;
|
||||
typedef SharedPtr<lldb_private::Section>::Type SectionSP;
|
||||
typedef SharedPtr<lldb_private::SearchFilter>::Type SearchFilterSP;
|
||||
typedef SharedPtr<lldb_private::StackFrame>::Type StackFrameSP;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "lldb/Core/ConstString.h"
|
||||
#include "lldb/Core/Debugger.h"
|
||||
#include "lldb/Core/FormatManager.h"
|
||||
#include "lldb/Core/RegularExpression.h"
|
||||
#include "lldb/Core/State.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandObject.h"
|
||||
|
@ -54,11 +55,14 @@ private:
|
|||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'c':
|
||||
case 'C':
|
||||
m_cascade = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
|
||||
break;
|
||||
case 'f':
|
||||
error = Args::StringToFormat(option_arg, m_format, NULL);
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
break;
|
||||
|
@ -71,6 +75,7 @@ private:
|
|||
OptionParsingStarting ()
|
||||
{
|
||||
m_cascade = true;
|
||||
m_format = eFormatInvalid;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
|
@ -86,6 +91,7 @@ private:
|
|||
// Instance variables to hold the values for command options.
|
||||
|
||||
bool m_cascade;
|
||||
lldb::Format m_format;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
@ -103,21 +109,14 @@ public:
|
|||
"Add a new formatting style for a type.",
|
||||
NULL), m_options (interpreter)
|
||||
{
|
||||
CommandArgumentEntry format_arg;
|
||||
CommandArgumentData format_style_arg;
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
format_style_arg.arg_type = eArgTypeFormat;
|
||||
format_style_arg.arg_repetition = eArgRepeatPlain;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatPlus;
|
||||
|
||||
format_arg.push_back (format_style_arg);
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (format_arg);
|
||||
|
||||
m_arguments.push_back (type_arg);
|
||||
}
|
||||
|
||||
|
@ -130,40 +129,27 @@ public:
|
|||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
if (argc < 2)
|
||||
if (argc < 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes two or more args.\n", m_cmd_name.c_str());
|
||||
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* format_cstr = command.GetArgumentAtIndex(0);
|
||||
|
||||
if (!format_cstr || !format_cstr[0])
|
||||
if(m_options.m_format == eFormatInvalid)
|
||||
{
|
||||
result.AppendError("empty format strings not allowed");
|
||||
result.AppendErrorWithFormat ("%s needs a valid format.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
lldb::Format format;
|
||||
Error error;
|
||||
ValueFormatSP entry;
|
||||
|
||||
error = Args::StringToFormat(format_cstr, format, NULL);
|
||||
ValueFormat::SharedPointer entry;
|
||||
|
||||
entry.reset(new ValueFormat(format,m_options.m_cascade));
|
||||
entry.reset(new ValueFormat(m_options.m_format,m_options.m_cascade));
|
||||
|
||||
if (error.Fail())
|
||||
{
|
||||
result.AppendError(error.AsCString());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
// now I have a valid format, let's add it to every type
|
||||
|
||||
for(int i = 1; i < argc; i++) {
|
||||
for(int i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
ConstString typeCS(typeA);
|
||||
if (typeCS)
|
||||
|
@ -179,13 +165,13 @@ public:
|
|||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
OptionDefinition
|
||||
CommandObjectTypeFormatAdd::CommandOptions::g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_ALL, false, "cascade", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
|
||||
{ LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
|
||||
{ LLDB_OPT_SET_ALL, false, "format", 'f', required_argument, NULL, 0, eArgTypeFormat, "The format to use to display this type."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
|
@ -411,25 +397,31 @@ private:
|
|||
|
||||
switch (short_option)
|
||||
{
|
||||
case 'c':
|
||||
case 'C':
|
||||
m_cascade = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for cascade: %s.\n", option_arg);
|
||||
break;
|
||||
case 'h':
|
||||
m_no_children = !Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for nochildren: %s.\n", option_arg);
|
||||
case 'e':
|
||||
m_no_children = false;
|
||||
break;
|
||||
case 'v':
|
||||
m_no_value = !Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for novalue: %s.\n", option_arg);
|
||||
m_no_value = true;
|
||||
break;
|
||||
case 'o':
|
||||
m_one_liner = Args::StringToBoolean(option_arg, true, &success);
|
||||
if (!success)
|
||||
error.SetErrorStringWithFormat("Invalid value for oneliner: %s.\n", option_arg);
|
||||
case 'c':
|
||||
m_one_liner = true;
|
||||
break;
|
||||
case 'f':
|
||||
m_format_string = std::string(option_arg);
|
||||
break;
|
||||
case 'p':
|
||||
m_skip_pointers = true;
|
||||
break;
|
||||
case 'r':
|
||||
m_skip_references = true;
|
||||
break;
|
||||
case 'x':
|
||||
m_regex = true;
|
||||
break;
|
||||
default:
|
||||
error.SetErrorStringWithFormat ("Unrecognized option '%c'.\n", short_option);
|
||||
|
@ -446,6 +438,9 @@ private:
|
|||
m_no_children = true;
|
||||
m_no_value = false;
|
||||
m_one_liner = false;
|
||||
m_skip_references = false;
|
||||
m_skip_pointers = false;
|
||||
m_regex = false;
|
||||
}
|
||||
|
||||
const OptionDefinition*
|
||||
|
@ -464,6 +459,10 @@ private:
|
|||
bool m_no_children;
|
||||
bool m_no_value;
|
||||
bool m_one_liner;
|
||||
bool m_skip_references;
|
||||
bool m_skip_pointers;
|
||||
bool m_regex;
|
||||
std::string m_format_string;
|
||||
};
|
||||
|
||||
CommandOptions m_options;
|
||||
|
@ -481,21 +480,14 @@ public:
|
|||
"Add a new summary style for a type.",
|
||||
NULL), m_options (interpreter)
|
||||
{
|
||||
CommandArgumentEntry format_arg;
|
||||
CommandArgumentData format_style_arg;
|
||||
CommandArgumentEntry type_arg;
|
||||
CommandArgumentData type_style_arg;
|
||||
|
||||
format_style_arg.arg_type = eArgTypeFormat;
|
||||
format_style_arg.arg_repetition = eArgRepeatPlain;
|
||||
|
||||
type_style_arg.arg_type = eArgTypeName;
|
||||
type_style_arg.arg_repetition = eArgRepeatPlus;
|
||||
|
||||
format_arg.push_back (format_style_arg);
|
||||
type_arg.push_back (type_style_arg);
|
||||
|
||||
m_arguments.push_back (format_arg);
|
||||
m_arguments.push_back (type_arg);
|
||||
}
|
||||
|
||||
|
@ -508,34 +500,29 @@ public:
|
|||
{
|
||||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
// we support just one custom syntax: type summary add -o yes typeName
|
||||
// anything else, must take the usual route
|
||||
// e.g. type summary add -o yes "" type1 type2 ... typeN
|
||||
|
||||
bool isValidShortcut = m_options.m_one_liner && (argc == 1);
|
||||
bool isValid = (argc >= 2);
|
||||
|
||||
if (!isValidShortcut && !isValid)
|
||||
if (argc < 1)
|
||||
{
|
||||
result.AppendErrorWithFormat ("%s takes two or more args.\n", m_cmd_name.c_str());
|
||||
result.AppendErrorWithFormat ("%s takes one or more args.\n", m_cmd_name.c_str());
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* format_cstr = (isValidShortcut ? "" : command.GetArgumentAtIndex(0));
|
||||
|
||||
if ( (!format_cstr || !format_cstr[0]) && !m_options.m_one_liner )
|
||||
if(!m_options.m_one_liner && m_options.m_format_string.empty())
|
||||
{
|
||||
result.AppendError("empty summary strings not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char* format_cstr = (m_options.m_one_liner ? "" : m_options.m_format_string.c_str());
|
||||
|
||||
Error error;
|
||||
|
||||
SummaryFormat::SharedPointer entry(new SummaryFormat(format_cstr,m_options.m_cascade,
|
||||
m_options.m_no_children,m_options.m_no_value,
|
||||
m_options.m_one_liner));
|
||||
m_options.m_one_liner,
|
||||
m_options.m_skip_pointers,
|
||||
m_options.m_skip_references));
|
||||
|
||||
if (error.Fail())
|
||||
{
|
||||
|
@ -546,17 +533,31 @@ public:
|
|||
|
||||
// now I have a valid format, let's add it to every type
|
||||
|
||||
for(int i = (isValidShortcut ? 0 : 1); i < argc; i++) {
|
||||
for(int i = 0; i < argc; i++) {
|
||||
const char* typeA = command.GetArgumentAtIndex(i);
|
||||
ConstString typeCS(typeA);
|
||||
if (typeCS)
|
||||
Debugger::SummaryFormats::Add(typeCS, entry);
|
||||
else
|
||||
if(!typeA || typeA[0] == '\0')
|
||||
{
|
||||
result.AppendError("empty typenames not allowed");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
ConstString typeCS(typeA);
|
||||
if(!m_options.m_regex)
|
||||
{
|
||||
Debugger::SummaryFormats::Add(typeCS, entry);
|
||||
}
|
||||
else
|
||||
{
|
||||
RegularExpressionSP typeRX(new RegularExpression());
|
||||
if(!typeRX->Compile(typeA))
|
||||
{
|
||||
result.AppendError("regex format error (maybe this is not really a regex?)");
|
||||
result.SetStatus(eReturnStatusFailed);
|
||||
return false;
|
||||
}
|
||||
Debugger::RegexSummaryFormats::Delete(typeCS);
|
||||
Debugger::RegexSummaryFormats::Add(typeRX, entry);
|
||||
}
|
||||
}
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
|
@ -567,10 +568,14 @@ public:
|
|||
OptionDefinition
|
||||
CommandObjectTypeSummaryAdd::CommandOptions::g_option_table[] =
|
||||
{
|
||||
{ LLDB_OPT_SET_ALL, false, "cascade", 'c', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
|
||||
{ LLDB_OPT_SET_ALL, false, "show-children", 'h', required_argument, NULL, 0, eArgTypeBoolean, "If true, print children."},
|
||||
{ LLDB_OPT_SET_ALL, false, "show-value", 'v', required_argument, NULL, 0, eArgTypeBoolean, "If true, print value."},
|
||||
{ LLDB_OPT_SET_ALL, false, "one-liner", 'o', required_argument, NULL, 0, eArgTypeBoolean, "If true, just print a one-line preformatted summary."},
|
||||
{ LLDB_OPT_SET_ALL, false, "cascade", 'C', required_argument, NULL, 0, eArgTypeBoolean, "If true, cascade to derived typedefs."},
|
||||
{ LLDB_OPT_SET_ALL, false, "no-value", 'v', no_argument, NULL, 0, eArgTypeBoolean, "Don't show the value, just show the summary, for this type."},
|
||||
{ LLDB_OPT_SET_ALL, false, "skip-pointers", 'p', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for pointers-to-type objects."},
|
||||
{ LLDB_OPT_SET_ALL, false, "skip-references", 'r', no_argument, NULL, 0, eArgTypeBoolean, "Don't use this format for references-to-type objects."},
|
||||
{ LLDB_OPT_SET_ALL, false, "regex", 'x', no_argument, NULL, 0, eArgTypeBoolean, "Type names are actually regular expressions."},
|
||||
{ LLDB_OPT_SET_1 , true, "inline-children", 'c', no_argument, NULL, 0, eArgTypeBoolean, "If true, inline all child values into summary string."},
|
||||
{ LLDB_OPT_SET_2 , true, "format-string", 'f', required_argument, NULL, 0, eArgTypeFormatString, "Format string used to display text and object contents."},
|
||||
{ LLDB_OPT_SET_2, false, "expand", 'e', no_argument, NULL, 0, eArgTypeBoolean, "Expand aggregate data types to show children on separate lines."},
|
||||
{ 0, false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
|
||||
};
|
||||
|
||||
|
@ -626,8 +631,9 @@ public:
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (Debugger::SummaryFormats::Delete(typeCS))
|
||||
bool delete_summary = Debugger::SummaryFormats::Delete(typeCS);
|
||||
bool delete_regex = Debugger::RegexSummaryFormats::Delete(typeCS);
|
||||
if (delete_summary || delete_regex)
|
||||
{
|
||||
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
||||
return result.Succeeded();
|
||||
|
@ -666,6 +672,7 @@ public:
|
|||
Execute (Args& command, CommandReturnObject &result)
|
||||
{
|
||||
Debugger::SummaryFormats::Clear();
|
||||
Debugger::RegexSummaryFormats::Clear();
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
@ -677,6 +684,7 @@ public:
|
|||
//-------------------------------------------------------------------------
|
||||
|
||||
bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
|
||||
bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry);
|
||||
|
||||
class CommandObjectTypeSummaryList;
|
||||
|
||||
|
@ -688,6 +696,14 @@ struct CommandObjectTypeSummaryList_LoopCallbackParam {
|
|||
RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
|
||||
};
|
||||
|
||||
struct CommandObjectTypeRXSummaryList_LoopCallbackParam {
|
||||
CommandObjectTypeSummaryList* self;
|
||||
CommandReturnObject* result;
|
||||
RegularExpression* regex;
|
||||
CommandObjectTypeRXSummaryList_LoopCallbackParam(CommandObjectTypeSummaryList* S, CommandReturnObject* R,
|
||||
RegularExpression* X = NULL) : self(S), result(R), regex(X) {}
|
||||
};
|
||||
|
||||
class CommandObjectTypeSummaryList : public CommandObject
|
||||
{
|
||||
public:
|
||||
|
@ -718,6 +734,7 @@ public:
|
|||
const size_t argc = command.GetArgumentCount();
|
||||
|
||||
CommandObjectTypeSummaryList_LoopCallbackParam *param;
|
||||
CommandObjectTypeRXSummaryList_LoopCallbackParam *rxparam;
|
||||
|
||||
if (argc == 1) {
|
||||
RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
|
||||
|
@ -728,6 +745,24 @@ public:
|
|||
param = new CommandObjectTypeSummaryList_LoopCallbackParam(this,&result);
|
||||
Debugger::SummaryFormats::LoopThrough(CommandObjectTypeSummaryList_LoopCallback, param);
|
||||
delete param;
|
||||
|
||||
if(Debugger::RegexSummaryFormats::GetCount() == 0)
|
||||
{
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
||||
result.GetOutputStream().Printf("Regex-based summaries (slower):\n");
|
||||
if (argc == 1) {
|
||||
RegularExpression* regex = new RegularExpression(command.GetArgumentAtIndex(0));
|
||||
regex->Compile(command.GetArgumentAtIndex(0));
|
||||
rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result,regex);
|
||||
}
|
||||
else
|
||||
rxparam = new CommandObjectTypeRXSummaryList_LoopCallbackParam(this,&result);
|
||||
Debugger::RegexSummaryFormats::LoopThrough(CommandObjectTypeRXSummaryList_LoopCallback, rxparam);
|
||||
delete rxparam;
|
||||
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
return result.Succeeded();
|
||||
}
|
||||
|
@ -742,18 +777,21 @@ private:
|
|||
{
|
||||
if (regex == NULL || regex->Execute(type))
|
||||
{
|
||||
result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s\n", type,
|
||||
result->GetOutputStream().Printf ("%s: `%s`%s%s%s%s%s%s\n", type,
|
||||
entry->m_format.c_str(),
|
||||
entry->m_cascades ? "" : " (not cascading)",
|
||||
entry->m_dont_show_children ? "" : " (show children)",
|
||||
entry->m_dont_show_value ? "" : " (show value)",
|
||||
entry->m_show_members_oneliner ? " (one-line printout)" : "");
|
||||
entry->m_dont_show_value ? " (hide value)" : "",
|
||||
entry->m_show_members_oneliner ? " (one-line printout)" : "",
|
||||
entry->m_skip_pointers ? " (skip pointers)" : "",
|
||||
entry->m_skip_references ? " (skip references)" : "");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool CommandObjectTypeSummaryList_LoopCallback(void* pt2self, const char* type, const SummaryFormat::SharedPointer& entry);
|
||||
|
||||
friend bool CommandObjectTypeRXSummaryList_LoopCallback(void* pt2self, lldb::RegularExpressionSP regex, const SummaryFormat::SharedPointer& entry);
|
||||
|
||||
};
|
||||
|
||||
bool
|
||||
|
@ -766,6 +804,15 @@ CommandObjectTypeSummaryList_LoopCallback (
|
|||
return param->self->LoopCallback(type, entry, param->regex, param->result);
|
||||
}
|
||||
|
||||
bool
|
||||
CommandObjectTypeRXSummaryList_LoopCallback (
|
||||
void* pt2self,
|
||||
lldb::RegularExpressionSP regex,
|
||||
const SummaryFormat::SharedPointer& entry)
|
||||
{
|
||||
CommandObjectTypeRXSummaryList_LoopCallbackParam* param = (CommandObjectTypeRXSummaryList_LoopCallbackParam*)pt2self;
|
||||
return param->self->LoopCallback(regex->GetText(), entry, param->regex, param->result);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -796,7 +843,7 @@ class CommandObjectTypeSummary : public CommandObjectMultiword
|
|||
public:
|
||||
CommandObjectTypeSummary (CommandInterpreter &interpreter) :
|
||||
CommandObjectMultiword (interpreter,
|
||||
"type format",
|
||||
"type summary",
|
||||
"A set of commands for editing variable summary display options",
|
||||
"type summary [<sub-command-options>] ")
|
||||
{
|
||||
|
|
|
@ -791,15 +791,201 @@ Debugger::FormatPrompt
|
|||
case '*':
|
||||
{
|
||||
if (!vobj) break;
|
||||
var_name_begin++;
|
||||
lldb::clang_type_t pointer_clang_type = vobj->GetClangType();
|
||||
clang_type_t elem_or_pointee_clang_type;
|
||||
const Flags type_flags (ClangASTContext::GetTypeInfo (pointer_clang_type,
|
||||
vobj->GetClangAST(),
|
||||
&elem_or_pointee_clang_type));
|
||||
if (type_flags.Test (ClangASTContext::eTypeIsPointer))
|
||||
bool is_pointer = type_flags.Test (ClangASTContext::eTypeIsPointer),
|
||||
is_array = type_flags.Test (ClangASTContext::eTypeIsArray);
|
||||
if ( is_array ||
|
||||
( is_pointer && ::strchr(var_name_begin,'[') && ::strchr(var_name_begin,'[') < var_name_end )
|
||||
)
|
||||
{
|
||||
if (ClangASTContext::IsCharType (elem_or_pointee_clang_type))
|
||||
const char* var_name_final;
|
||||
char* close_bracket_position = NULL;
|
||||
const char* percent_position = NULL;
|
||||
const char* targetvalue;
|
||||
lldb::Format custom_format = eFormatInvalid;
|
||||
int index_lower = -1;
|
||||
int index_higher = -1;
|
||||
ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary;
|
||||
{
|
||||
percent_position = ::strchr(var_name_begin,'%');
|
||||
if(!percent_position || percent_position > var_name_end)
|
||||
var_name_final = var_name_end;
|
||||
else
|
||||
{
|
||||
var_name_final = percent_position;
|
||||
char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
|
||||
memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
// if this is a V, print the value using the default format
|
||||
if(*format_name == 'V')
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
// a good custom format tells us to print the value using it
|
||||
else
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const char* open_bracket_position = ::strchr(var_name_begin,'[');
|
||||
if(open_bracket_position && open_bracket_position < var_name_final)
|
||||
{
|
||||
// TODO: pick a way to say "all entries". this will make more sense once
|
||||
// regex typenames are in place. now, you need to be size-aware anyways
|
||||
char* separator_position = ::strchr(open_bracket_position,'-'); // might be NULL if this is a simple var[N] bitfield
|
||||
close_bracket_position = ::strchr(open_bracket_position,']');
|
||||
// as usual, we assume that [] will come before %
|
||||
//printf("trying to expand a []\n");
|
||||
var_name_final = open_bracket_position;
|
||||
if(close_bracket_position - open_bracket_position == 1)
|
||||
{
|
||||
if(is_array)
|
||||
{
|
||||
index_lower = 0;
|
||||
index_higher = vobj->GetNumChildren() - 1;
|
||||
}
|
||||
else
|
||||
break; // cannot auto-determine size for pointers
|
||||
}
|
||||
else if (separator_position == NULL || separator_position > var_name_end)
|
||||
{
|
||||
char *end = NULL;
|
||||
index_lower = ::strtoul (open_bracket_position+1, &end, 0);
|
||||
index_higher = index_lower;
|
||||
//printf("got to read low=%d high same\n",bitfield_lower);
|
||||
}
|
||||
else if(close_bracket_position && close_bracket_position < var_name_end)
|
||||
{
|
||||
char *end = NULL;
|
||||
index_lower = ::strtoul (open_bracket_position+1, &end, 0);
|
||||
index_higher = ::strtoul (separator_position+1, &end, 0);
|
||||
//printf("got to read low=%d high=%d\n",bitfield_lower,bitfield_higher);
|
||||
}
|
||||
else
|
||||
break;
|
||||
if (index_lower > index_higher)
|
||||
{
|
||||
int temp = index_lower;
|
||||
index_lower = index_higher;
|
||||
index_higher = temp;
|
||||
}
|
||||
//*((char*)open_bracket_position) = '\0';
|
||||
//printf("variable name is %s\n",var_name_begin);
|
||||
//*((char*)open_bracket_position) = '[';
|
||||
}
|
||||
}
|
||||
|
||||
// if you just type a range, lldb will do the "right thing" in picking
|
||||
// a reasonable display for the array entries. you can override this by
|
||||
// giving other input (e.g. ${*var[1-3].member1%uint8_t[]}) and they
|
||||
// will be honored
|
||||
char* special_directions = NULL;
|
||||
if (close_bracket_position && (var_name_end-close_bracket_position > 1))
|
||||
{
|
||||
int base_len = var_name_end-close_bracket_position;
|
||||
special_directions = new char[8+base_len];
|
||||
special_directions[0] = '$';
|
||||
special_directions[1] = '{';
|
||||
special_directions[2] = 'v';
|
||||
special_directions[3] = 'a';
|
||||
special_directions[4] = 'r';
|
||||
memcpy(special_directions+5, close_bracket_position+1, base_len);
|
||||
special_directions[base_len+7] = '\0';
|
||||
printf("%s\n",special_directions);
|
||||
}
|
||||
|
||||
// let us display items index_lower thru index_higher of this array
|
||||
s.PutChar('[');
|
||||
var_success = true;
|
||||
const char* expr_path = NULL;
|
||||
const char* ptr_deref_format = "%s[%d]";
|
||||
char* ptr_deref_buffer = new char[1024];
|
||||
StreamString expr_path_string;
|
||||
|
||||
if(is_pointer)
|
||||
{
|
||||
vobj->GetExpressionPath(expr_path_string, true, ValueObject::eHonorPointers);
|
||||
expr_path = expr_path_string.GetData();
|
||||
}
|
||||
|
||||
for(;index_lower<=index_higher;index_lower++)
|
||||
{
|
||||
ValueObject* item;
|
||||
|
||||
if(is_array)
|
||||
item = vobj->GetChildAtIndex(index_lower, true).get();
|
||||
else
|
||||
{
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to deref in phase 0: %s\n",expr_path);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
::sprintf(ptr_deref_buffer, ptr_deref_format, expr_path, index_lower);
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to deref in phase 1: %s\n",ptr_deref_buffer);
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
lldb::VariableSP var_sp;
|
||||
Error error;
|
||||
item = exe_ctx->frame->GetValueForVariableExpressionPath (ptr_deref_buffer,
|
||||
eNoDynamicValues,
|
||||
0,
|
||||
var_sp,
|
||||
error).get();
|
||||
if (error.Fail())
|
||||
{
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("ERROR: %s\n",error.AsCString("unknown"));
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!special_directions)
|
||||
{
|
||||
targetvalue = item->GetPrintableRepresentation(val_obj_display, custom_format);
|
||||
if(targetvalue)
|
||||
s.PutCString(targetvalue);
|
||||
var_success &= (targetvalue != NULL);
|
||||
if(custom_format != eFormatInvalid)
|
||||
item->SetFormat(eFormatDefault);
|
||||
}
|
||||
else
|
||||
{
|
||||
var_success &= FormatPrompt(special_directions, sc, exe_ctx, addr, s, NULL, item);
|
||||
}
|
||||
|
||||
if(index_lower < index_higher)
|
||||
s.PutChar(',');
|
||||
}
|
||||
s.PutChar(']');
|
||||
break;
|
||||
|
||||
}
|
||||
else if (is_pointer)
|
||||
{
|
||||
var_name_begin++;
|
||||
uint32_t offset = 0;
|
||||
DataExtractor read_for_null = vobj->GetDataExtractor();
|
||||
if (read_for_null.GetPointer(&offset) == 0)
|
||||
break;
|
||||
if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type) )
|
||||
{
|
||||
Error error;
|
||||
realvobj = vobj;
|
||||
vobj = vobj->Dereference(error).get();
|
||||
if(!vobj || error.Fail())
|
||||
break;
|
||||
}
|
||||
else if (ClangASTContext::IsCharType (elem_or_pointee_clang_type))
|
||||
{
|
||||
StreamString sstr;
|
||||
ExecutionContextScope *exe_scope = vobj->GetExecutionContextScope();
|
||||
|
@ -849,7 +1035,7 @@ Debugger::FormatPrompt
|
|||
break;
|
||||
}
|
||||
}
|
||||
else /*if (ClangASTContext::IsAggregateType (elem_or_pointee_clang_type)) or this is some other pointer type*/
|
||||
else /*some other pointer type*/
|
||||
{
|
||||
Error error;
|
||||
realvobj = vobj;
|
||||
|
@ -864,7 +1050,7 @@ Debugger::FormatPrompt
|
|||
case 'v':
|
||||
{
|
||||
const char* targetvalue;
|
||||
bool use_summary = false;
|
||||
ValueObject::ValueObjectRepresentationStyle val_obj_display = ValueObject::eDisplaySummary;
|
||||
ValueObject* target;
|
||||
lldb::Format custom_format = eFormatInvalid;
|
||||
int bitfield_lower = -1;
|
||||
|
@ -872,12 +1058,16 @@ Debugger::FormatPrompt
|
|||
if (!vobj) break;
|
||||
// simplest case ${var}, just print vobj's value
|
||||
if (::strncmp (var_name_begin, "var}", strlen("var}")) == 0)
|
||||
{
|
||||
target = vobj;
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
else if (::strncmp(var_name_begin,"var%",strlen("var%")) == 0)
|
||||
{
|
||||
// this is a variable with some custom format applied to it
|
||||
const char* var_name_final;
|
||||
target = vobj;
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
{
|
||||
const char* percent_position = ::strchr(var_name_begin,'%'); // TODO: make this a constant
|
||||
//if(!percent_position || percent_position > var_name_end)
|
||||
|
@ -887,9 +1077,14 @@ Debugger::FormatPrompt
|
|||
var_name_final = percent_position;
|
||||
char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
|
||||
memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
|
||||
FormatManager::GetFormatFromCString(format_name,
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format); // if this fails, custom_format is reset to invalid
|
||||
custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
}
|
||||
delete format_name;
|
||||
//}
|
||||
}
|
||||
|
@ -899,7 +1094,7 @@ Debugger::FormatPrompt
|
|||
// this is a bitfield variable
|
||||
const char *var_name_final;
|
||||
target = vobj;
|
||||
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
{
|
||||
const char* percent_position = ::strchr(var_name_begin,'%');
|
||||
if(!percent_position || percent_position > var_name_end)
|
||||
|
@ -909,10 +1104,15 @@ Debugger::FormatPrompt
|
|||
var_name_final = percent_position;
|
||||
char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
|
||||
memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
|
||||
FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format); // if this fails, custom_format is reset to invalid
|
||||
delete format_name;
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
delete format_name;
|
||||
break;
|
||||
}
|
||||
else
|
||||
delete format_name;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -943,7 +1143,11 @@ Debugger::FormatPrompt
|
|||
else
|
||||
break;
|
||||
if(bitfield_lower > bitfield_higher)
|
||||
break;
|
||||
{
|
||||
int temp = bitfield_lower;
|
||||
bitfield_lower = bitfield_higher;
|
||||
bitfield_higher = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -966,10 +1170,20 @@ Debugger::FormatPrompt
|
|||
var_name_final = percent_position;
|
||||
char* format_name = new char[var_name_end-var_name_final]; format_name[var_name_end-var_name_final-1] = '\0';
|
||||
memcpy(format_name, var_name_final+1, var_name_end-var_name_final-1);
|
||||
FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format); // if this fails, custom_format is reset to invalid
|
||||
delete format_name;
|
||||
if ( !FormatManager::GetFormatFromCString(format_name,
|
||||
true,
|
||||
custom_format) )
|
||||
{
|
||||
// if this is an @ sign, print ObjC description
|
||||
if(*format_name == '@')
|
||||
val_obj_display = ValueObject::eDisplayLanguageSpecific;
|
||||
// if this is a V, print the value using the default format
|
||||
if(*format_name == 'V')
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
// a good custom format tells us to print the value using it
|
||||
else
|
||||
val_obj_display = ValueObject::eDisplayValue;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -999,7 +1213,11 @@ Debugger::FormatPrompt
|
|||
else
|
||||
break;
|
||||
if(bitfield_lower > bitfield_higher)
|
||||
break;
|
||||
{
|
||||
int temp = bitfield_lower;
|
||||
bitfield_lower = bitfield_higher;
|
||||
bitfield_higher = temp;
|
||||
}
|
||||
//*((char*)open_bracket_position) = '\0';
|
||||
//printf("variable name is %s\n",var_name_begin);
|
||||
//*((char*)open_bracket_position) = '[';
|
||||
|
@ -1010,9 +1228,13 @@ Debugger::FormatPrompt
|
|||
lldb::VariableSP var_sp;
|
||||
StreamString sstring;
|
||||
vobj->GetExpressionPath(sstring, true, ValueObject::eHonorPointers);
|
||||
//printf("name to expand in phase 0: %s\n",sstring.GetData());
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to expand in phase 0: %s\n",sstring.GetData());
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
sstring.PutRawBytes(var_name_begin+3, var_name_final-var_name_begin-3);
|
||||
//printf("name to expand in phase 1: %s\n",sstring.GetData());
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("name to expand in phase 1: %s\n",sstring.GetData());
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
std::string name = std::string(sstring.GetData());
|
||||
target = exe_ctx->frame->GetValueForVariableExpressionPath (name.c_str(),
|
||||
eNoDynamicValues,
|
||||
|
@ -1021,17 +1243,14 @@ Debugger::FormatPrompt
|
|||
error).get();
|
||||
if (error.Fail())
|
||||
{
|
||||
//printf("ERROR: %s\n",error.AsCString("unknown"));
|
||||
#ifdef VERBOSE_FORMATPROMPT_OUTPUT
|
||||
printf("ERROR: %s\n",error.AsCString("unknown"));
|
||||
#endif //VERBOSE_FORMATPROMPT_OUTPUT
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
if(*(var_name_end+1)=='s')
|
||||
{
|
||||
use_summary = true;
|
||||
var_name_end++;
|
||||
}
|
||||
if (bitfield_lower >= 0)
|
||||
{
|
||||
//printf("trying to print a []\n");
|
||||
|
@ -1046,16 +1265,8 @@ Debugger::FormatPrompt
|
|||
}
|
||||
else
|
||||
{
|
||||
//printf("here I come 1\n");
|
||||
// format this as usual
|
||||
if(custom_format != eFormatInvalid)
|
||||
target->SetFormat(custom_format);
|
||||
//printf("here I come 2\n");
|
||||
if(!use_summary)
|
||||
targetvalue = target->GetValueAsCString();
|
||||
else
|
||||
targetvalue = target->GetSummaryAsCString();
|
||||
//printf("here I come 3\n");
|
||||
targetvalue = target->GetPrintableRepresentation(val_obj_display, custom_format);
|
||||
if(targetvalue)
|
||||
s.PutCString(targetvalue);
|
||||
var_success = targetvalue;
|
||||
|
@ -1634,7 +1845,7 @@ Debugger::ValueFormats::Clear()
|
|||
}
|
||||
|
||||
void
|
||||
Debugger::ValueFormats::LoopThrough(FormatManager::ValueCallback callback, void* callback_baton)
|
||||
Debugger::ValueFormats::LoopThrough(ValueFormat::ValueCallback callback, void* callback_baton)
|
||||
{
|
||||
GetFormatManager().Value().LoopThrough(callback, callback_baton);
|
||||
}
|
||||
|
@ -1645,6 +1856,11 @@ Debugger::ValueFormats::GetCurrentRevision()
|
|||
return GetFormatManager().GetCurrentRevision();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Debugger::ValueFormats::GetCount()
|
||||
{
|
||||
return GetFormatManager().Value().GetCount();
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::SummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry)
|
||||
|
@ -1671,7 +1887,7 @@ Debugger::SummaryFormats::Clear()
|
|||
}
|
||||
|
||||
void
|
||||
Debugger::SummaryFormats::LoopThrough(FormatManager::SummaryCallback callback, void* callback_baton)
|
||||
Debugger::SummaryFormats::LoopThrough(SummaryFormat::SummaryCallback callback, void* callback_baton)
|
||||
{
|
||||
GetFormatManager().Summary().LoopThrough(callback, callback_baton);
|
||||
}
|
||||
|
@ -1682,6 +1898,54 @@ Debugger::SummaryFormats::GetCurrentRevision()
|
|||
return GetFormatManager().GetCurrentRevision();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Debugger::SummaryFormats::GetCount()
|
||||
{
|
||||
return GetFormatManager().Summary().GetCount();
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::RegexSummaryFormats::Get(ValueObject& vobj, SummaryFormat::SharedPointer &entry)
|
||||
{
|
||||
return GetFormatManager().RegexSummary().Get(vobj,entry);
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::RegexSummaryFormats::Add(const lldb::RegularExpressionSP &type, const SummaryFormat::SharedPointer &entry)
|
||||
{
|
||||
GetFormatManager().RegexSummary().Add(type,entry);
|
||||
}
|
||||
|
||||
bool
|
||||
Debugger::RegexSummaryFormats::Delete(const ConstString &type)
|
||||
{
|
||||
return GetFormatManager().RegexSummary().Delete(type.AsCString());
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::RegexSummaryFormats::Clear()
|
||||
{
|
||||
GetFormatManager().RegexSummary().Clear();
|
||||
}
|
||||
|
||||
void
|
||||
Debugger::RegexSummaryFormats::LoopThrough(SummaryFormat::RegexSummaryCallback callback, void* callback_baton)
|
||||
{
|
||||
GetFormatManager().RegexSummary().LoopThrough(callback, callback_baton);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Debugger::RegexSummaryFormats::GetCurrentRevision()
|
||||
{
|
||||
return GetFormatManager().GetCurrentRevision();
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Debugger::RegexSummaryFormats::GetCount()
|
||||
{
|
||||
return GetFormatManager().RegexSummary().GetCount();
|
||||
}
|
||||
|
||||
#pragma mark Debugger::SettingsController
|
||||
|
||||
//--------------------------------------------------
|
||||
|
|
|
@ -151,3 +151,40 @@ FormatManager::GetFormatAsCString (Format format)
|
|||
return g_format_infos[format].format_name;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Get(const char* key,
|
||||
SummaryFormat::SharedPointer& value)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
MapIterator pos, end = m_map.end();
|
||||
for (pos = m_map.begin(); pos != end; pos++)
|
||||
{
|
||||
lldb::RegularExpressionSP regex = pos->first;
|
||||
if (regex->Execute(key))
|
||||
{
|
||||
value = pos->second;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<>
|
||||
bool
|
||||
FormatNavigator<std::map<lldb::RegularExpressionSP, SummaryFormat::SharedPointer>, SummaryFormat::RegexSummaryCallback>::Delete(const char* type)
|
||||
{
|
||||
Mutex::Locker(m_map_mutex);
|
||||
MapIterator pos, end = m_map.end();
|
||||
for (pos = m_map.begin(); pos != end; pos++)
|
||||
{
|
||||
lldb::RegularExpressionSP regex = pos->first;
|
||||
if ( ::strcmp(type,regex->GetText()) == 0)
|
||||
{
|
||||
m_map.erase(pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -176,4 +176,9 @@ RegularExpression::GetErrorAsCString (char *err_str, size_t err_str_max_len) con
|
|||
return ::regerror (m_comp_err, &m_preg, err_str, err_str_max_len);
|
||||
}
|
||||
|
||||
bool
|
||||
RegularExpression::operator < (const RegularExpression& rhs) const
|
||||
{
|
||||
return (m_re < rhs.m_re);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,7 @@ ValueObject::ValueObject (ValueObject &parent) :
|
|||
m_old_value_valid (false),
|
||||
m_pointers_point_to_load_addrs (false),
|
||||
m_is_deref_of_parent (false),
|
||||
m_is_array_item_for_pointer(false),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_summary_format(),
|
||||
m_last_value_format()
|
||||
|
@ -108,6 +109,7 @@ ValueObject::ValueObject (ExecutionContextScope *exe_scope) :
|
|||
m_old_value_valid (false),
|
||||
m_pointers_point_to_load_addrs (false),
|
||||
m_is_deref_of_parent (false),
|
||||
m_is_array_item_for_pointer(false),
|
||||
m_last_format_mgr_revision(0),
|
||||
m_last_summary_format(),
|
||||
m_last_value_format()
|
||||
|
@ -124,10 +126,11 @@ ValueObject::~ValueObject ()
|
|||
}
|
||||
|
||||
bool
|
||||
ValueObject::UpdateValueIfNeeded ()
|
||||
ValueObject::UpdateValueIfNeeded (bool update_format)
|
||||
{
|
||||
|
||||
UpdateFormatsIfNeeded();
|
||||
if (update_format)
|
||||
UpdateFormatsIfNeeded();
|
||||
|
||||
// If this is a constant value, then our success is predicated on whether
|
||||
// we have an error or not
|
||||
|
@ -191,7 +194,8 @@ ValueObject::UpdateFormatsIfNeeded()
|
|||
if (m_last_value_format.get())
|
||||
m_last_value_format.reset((ValueFormat*)NULL);
|
||||
Debugger::ValueFormats::Get(*this, m_last_value_format);
|
||||
Debugger::SummaryFormats::Get(*this, m_last_summary_format);
|
||||
if (!Debugger::SummaryFormats::Get(*this, m_last_summary_format))
|
||||
Debugger::RegexSummaryFormats::Get(*this, m_last_summary_format);
|
||||
m_last_format_mgr_revision = Debugger::ValueFormats::GetCurrentRevision();
|
||||
m_value_str.clear();
|
||||
m_summary_str.clear();
|
||||
|
@ -493,12 +497,47 @@ ValueObject::GetSummaryAsCString ()
|
|||
ExecutionContext exe_ctx;
|
||||
this->GetExecutionContextScope()->CalculateExecutionContext(exe_ctx);
|
||||
SymbolContext sc = exe_ctx.frame->GetSymbolContext(eSymbolContextEverything);
|
||||
if (Debugger::FormatPrompt(m_last_summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
|
||||
|
||||
if (m_last_summary_format->m_show_members_oneliner)
|
||||
{
|
||||
m_summary_str.swap(s.GetString());
|
||||
return m_summary_str.c_str();
|
||||
const uint32_t num_children = GetNumChildren();
|
||||
if (num_children)
|
||||
{
|
||||
|
||||
s.PutChar('(');
|
||||
|
||||
for (uint32_t idx=0; idx<num_children; ++idx)
|
||||
{
|
||||
ValueObjectSP child_sp(GetChildAtIndex(idx, true));
|
||||
if (child_sp.get())
|
||||
{
|
||||
if (idx)
|
||||
s.PutCString(", ");
|
||||
s.PutCString(child_sp.get()->GetName().AsCString());
|
||||
s.PutChar('=');
|
||||
s.PutCString(child_sp.get()->GetValueAsCString());
|
||||
}
|
||||
}
|
||||
|
||||
s.PutChar(')');
|
||||
|
||||
m_summary_str.swap(s.GetString());
|
||||
return m_summary_str.c_str();
|
||||
}
|
||||
else
|
||||
return "()";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Debugger::FormatPrompt(m_last_summary_format->m_format.c_str(), &sc, &exe_ctx, &sc.line_entry.range.GetBaseAddress(), s, NULL, this))
|
||||
{
|
||||
m_summary_str.swap(s.GetString());
|
||||
return m_summary_str.c_str();
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
clang_type_t clang_type = GetClangType();
|
||||
|
@ -655,12 +694,13 @@ ValueObject::GetSummaryAsCString ()
|
|||
const char *
|
||||
ValueObject::GetObjectDescription ()
|
||||
{
|
||||
if (!m_object_desc_str.empty())
|
||||
return m_object_desc_str.c_str();
|
||||
|
||||
|
||||
if (!UpdateValueIfNeeded ())
|
||||
return NULL;
|
||||
|
||||
|
||||
if (!m_object_desc_str.empty())
|
||||
return m_object_desc_str.c_str();
|
||||
|
||||
ExecutionContextScope *exe_scope = GetExecutionContextScope();
|
||||
if (exe_scope == NULL)
|
||||
return NULL;
|
||||
|
@ -782,6 +822,37 @@ ValueObject::GetValueAsCString ()
|
|||
return m_value_str.c_str();
|
||||
}
|
||||
|
||||
const char *
|
||||
ValueObject::GetPrintableRepresentation(ValueObjectRepresentationStyle val_obj_display,
|
||||
lldb::Format custom_format)
|
||||
{
|
||||
if(custom_format != lldb::eFormatInvalid)
|
||||
SetFormat(custom_format);
|
||||
|
||||
const char * return_value;
|
||||
|
||||
switch(val_obj_display)
|
||||
{
|
||||
case eDisplayValue:
|
||||
return_value = GetValueAsCString();
|
||||
break;
|
||||
case eDisplaySummary:
|
||||
return_value = GetSummaryAsCString();
|
||||
break;
|
||||
case eDisplayLanguageSpecific:
|
||||
return_value = GetObjectDescription();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// try to use the value if the user's choice failed
|
||||
if(!return_value && val_obj_display != eDisplayValue)
|
||||
return_value = GetValueAsCString();
|
||||
|
||||
return return_value;
|
||||
|
||||
}
|
||||
|
||||
addr_t
|
||||
ValueObject::GetAddressOf (AddressType &address_type, bool scalar_is_load_address)
|
||||
{
|
||||
|
@ -1049,6 +1120,8 @@ ValueObject::GetSyntheticArrayMemberFromPointer (int32_t index, bool can_create)
|
|||
{
|
||||
AddSyntheticChild(index_const_str, synthetic_child);
|
||||
synthetic_child_sp = synthetic_child->GetSP();
|
||||
synthetic_child_sp->SetName(index_str);
|
||||
synthetic_child_sp->m_is_array_item_for_pointer = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1165,6 +1238,12 @@ ValueObject::GetExpressionPath (Stream &s, bool qualify_cxx_base_classes, GetExp
|
|||
|
||||
if (parent)
|
||||
parent->GetExpressionPath (s, qualify_cxx_base_classes, epformat);
|
||||
|
||||
// if we are a deref_of_parent just because we are synthetic array
|
||||
// members made up to allow ptr[%d] syntax to work in variable
|
||||
// printing, then add our name ([%d]) to the expression path
|
||||
if(m_is_array_item_for_pointer && epformat == eHonorPointers)
|
||||
s.PutCString(m_name.AsCString());
|
||||
|
||||
if (!IsBaseClass())
|
||||
{
|
||||
|
@ -1312,8 +1391,17 @@ ValueObject::DumpValueObject
|
|||
if (val_cstr && (!entry || entry->DoesPrintValue() || !sum_cstr))
|
||||
s.Printf(" %s", valobj->GetValueAsCString());
|
||||
|
||||
if (sum_cstr)
|
||||
s.Printf(" %s", sum_cstr);
|
||||
if(sum_cstr)
|
||||
{
|
||||
// for some reason, using %@ (ObjC description) in a summary string, makes
|
||||
// us believe we need to reset ourselves, thus invalidating the content of
|
||||
// sum_cstr. Thus, IF we had a valid sum_cstr before, but it is now empty
|
||||
// let us recalculate it!
|
||||
if (sum_cstr[0] == '\0')
|
||||
s.Printf(" %s", valobj->GetSummaryAsCString());
|
||||
else
|
||||
s.Printf(" %s", sum_cstr);
|
||||
}
|
||||
|
||||
if (use_objc)
|
||||
{
|
||||
|
@ -1323,7 +1411,7 @@ ValueObject::DumpValueObject
|
|||
else
|
||||
s.Printf (" [no Objective-C description available]\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (curr_depth < max_depth)
|
||||
|
@ -1360,32 +1448,7 @@ ValueObject::DumpValueObject
|
|||
print_children = false;
|
||||
}
|
||||
|
||||
if (entry && entry->IsOneliner())
|
||||
{
|
||||
const uint32_t num_children = valobj->GetNumChildren();
|
||||
if (num_children)
|
||||
{
|
||||
|
||||
s.PutChar('(');
|
||||
|
||||
for (uint32_t idx=0; idx<num_children; ++idx)
|
||||
{
|
||||
ValueObjectSP child_sp(valobj->GetChildAtIndex(idx, true));
|
||||
if (child_sp.get())
|
||||
{
|
||||
if (idx)
|
||||
s.PutCString(", ");
|
||||
s.PutCString(child_sp.get()->GetName().AsCString());
|
||||
s.PutChar('=');
|
||||
s.PutCString(child_sp.get()->GetValueAsCString());
|
||||
}
|
||||
}
|
||||
|
||||
s.PutChar(')');
|
||||
s.EOL();
|
||||
}
|
||||
}
|
||||
else if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
|
||||
if (print_children && (!entry || entry->DoesPrintChildren() || !sum_cstr))
|
||||
{
|
||||
const uint32_t num_children = valobj->GetNumChildren();
|
||||
if (num_children)
|
||||
|
|
|
@ -80,7 +80,7 @@ ValueObjectDynamicValue::CalculateNumChildren()
|
|||
clang::ASTContext *
|
||||
ValueObjectDynamicValue::GetClangAST ()
|
||||
{
|
||||
const bool success = UpdateValueIfNeeded();
|
||||
const bool success = UpdateValueIfNeeded(false);
|
||||
if (success && m_type_sp)
|
||||
return m_type_sp->GetClangAST();
|
||||
else
|
||||
|
|
|
@ -627,6 +627,37 @@ BreakpointIDRangeHelpTextCallback ()
|
|||
return "A 'breakpoint id list' is a manner of specifying multiple breakpoints. This can be done through several mechanisms. The easiest way is to just enter a space-separated list of breakpoint ids. To specify all the breakpoint locations under a major breakpoint, you can use the major breakpoint number followed by '.*', eg. '5.*' means all the locations under breakpoint 5. You can also indicate a range of breakpoints by using <start-bp-id> - <end-bp-id>. The start-bp-id and end-bp-id for a range can be any valid breakpoint ids. It is not legal, however, to specify a range using specific locations that cross major breakpoint numbers. I.e. 3.2 - 3.7 is legal; 2 - 5 is legal; but 3.2 - 4.4 is not legal.";
|
||||
}
|
||||
|
||||
static const char *
|
||||
FormatHelpTextCallback ()
|
||||
{
|
||||
StreamString sstr;
|
||||
sstr << "One of the format names (or one-character names) that can be used to show a variable's value:\n";
|
||||
for (Format f = eFormatDefault; f < kNumFormats; f = Format(f+1))
|
||||
{
|
||||
char format_char = FormatManager::GetFormatAsFormatChar(f);
|
||||
if (format_char)
|
||||
sstr.Printf("'%c' or ", format_char);
|
||||
|
||||
sstr.Printf ("\"%s\" ; ", FormatManager::GetFormatAsCString(f));
|
||||
}
|
||||
|
||||
sstr.Flush();
|
||||
|
||||
std::string data = sstr.GetString();
|
||||
|
||||
char* help = new char[data.length()+1];
|
||||
|
||||
data.copy(help, data.length());
|
||||
|
||||
return help;
|
||||
}
|
||||
|
||||
static const char *
|
||||
FormatStringHelpTextCallback()
|
||||
{
|
||||
return "Ask me tomorrow";
|
||||
}
|
||||
|
||||
const char *
|
||||
CommandObject::GetArgumentTypeAsCString (const lldb::CommandArgumentType arg_type)
|
||||
{
|
||||
|
@ -662,7 +693,8 @@ CommandObject::g_arguments_data[] =
|
|||
{ eArgTypeExpression, "expr", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
|
||||
{ eArgTypeExprFormat, "expression-format", CommandCompletions::eNoCompletion, NULL, "[ [bool|b] | [bin] | [char|c] | [oct|o] | [dec|i|d|u] | [hex|x] | [float|f] | [cstr|s] ]" },
|
||||
{ eArgTypeFilename, "filename", CommandCompletions::eDiskFileCompletion, NULL, "The name of a file (can include path)." },
|
||||
{ eArgTypeFormat, "format", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
|
||||
{ eArgTypeFormat, "format", CommandCompletions::eNoCompletion, FormatHelpTextCallback, NULL },
|
||||
{ eArgTypeFormatString, "format-string", CommandCompletions::eNoCompletion, FormatStringHelpTextCallback, NULL },
|
||||
{ eArgTypeFrameIndex, "frame-index", CommandCompletions::eNoCompletion, NULL, "Index into a thread's list of frames." },
|
||||
{ eArgTypeFullName, "fullname", CommandCompletions::eNoCompletion, NULL, "Help text goes here." },
|
||||
{ eArgTypeFunctionName, "function-name", CommandCompletions::eNoCompletion, NULL, "The name of a function." },
|
||||
|
|
|
@ -117,21 +117,26 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
|||
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
||||
// We currently can't complete objective C types through the newly added ASTContext
|
||||
// because it only supports TagDecl objects right now...
|
||||
bool is_forward_decl = class_interface_decl->isForwardDecl();
|
||||
if (is_forward_decl && class_interface_decl->hasExternalLexicalStorage())
|
||||
if(class_interface_decl)
|
||||
{
|
||||
if (ast)
|
||||
bool is_forward_decl = class_interface_decl->isForwardDecl();
|
||||
if (is_forward_decl && class_interface_decl->hasExternalLexicalStorage())
|
||||
{
|
||||
ExternalASTSource *external_ast_source = ast->getExternalSource();
|
||||
if (external_ast_source)
|
||||
if (ast)
|
||||
{
|
||||
external_ast_source->CompleteType (class_interface_decl);
|
||||
is_forward_decl = class_interface_decl->isForwardDecl();
|
||||
ExternalASTSource *external_ast_source = ast->getExternalSource();
|
||||
if (external_ast_source)
|
||||
{
|
||||
external_ast_source->CompleteType (class_interface_decl);
|
||||
is_forward_decl = class_interface_decl->isForwardDecl();
|
||||
}
|
||||
}
|
||||
return is_forward_decl == false;
|
||||
}
|
||||
return is_forward_decl == false;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
LEVEL = ../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -1,120 +0,0 @@
|
|||
"""
|
||||
Test lldb data formatter subsystem.
|
||||
"""
|
||||
|
||||
import os, time
|
||||
import unittest2
|
||||
import lldb
|
||||
from lldbtest import *
|
||||
|
||||
class DataFormatterTestCase(TestBase):
|
||||
|
||||
mydir = os.path.join("functionalities", "data-formatter")
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_with_dsym_and_run_command(self):
|
||||
"""Test data formatter commands."""
|
||||
self.buildDsym()
|
||||
self.data_formatter_commands()
|
||||
|
||||
def test_with_dwarf_and_run_command(self):
|
||||
"""Test data formatter commands."""
|
||||
self.buildDwarf()
|
||||
self.data_formatter_commands()
|
||||
|
||||
def setUp(self):
|
||||
# Call super's setUp().
|
||||
TestBase.setUp(self)
|
||||
# Find the line number to break at.
|
||||
self.line = line_number('main.cpp', '// Set break point at this line.')
|
||||
|
||||
def data_formatter_commands(self):
|
||||
"""Test that that file and class static variables display correctly."""
|
||||
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
|
||||
|
||||
self.expect("breakpoint set -f main.cpp -l %d" % self.line,
|
||||
BREAKPOINT_CREATED,
|
||||
startstr = "Breakpoint created: 1: file ='main.cpp', line = %d, locations = 1" %
|
||||
self.line)
|
||||
|
||||
self.runCmd("run", RUN_SUCCEEDED)
|
||||
|
||||
# The stop reason of the thread should be breakpoint.
|
||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||
substrs = ['stopped',
|
||||
'stop reason = breakpoint'])
|
||||
|
||||
self.expect("frame variable",
|
||||
substrs = ['(Speed) SPILookHex = 5.55' # Speed by default is 5.55.
|
||||
]);
|
||||
|
||||
# This is the function to remove the custom formats in order to have a
|
||||
# clean slate for the next test case.
|
||||
def cleanup():
|
||||
self.runCmd('type format clear', check=False)
|
||||
self.runCmd('type summary clear', check=False)
|
||||
|
||||
# Execute the cleanup function during test case tear down.
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
self.runCmd("type format add -c yes x Speed BitField")
|
||||
self.runCmd("type format add -c no c RealNumber")
|
||||
self.runCmd("type format add -c no x Type2")
|
||||
self.runCmd("type format add -c yes c Type1")
|
||||
|
||||
# The type format list should show our custom formats.
|
||||
self.expect("type format list",
|
||||
substrs = ['RealNumber',
|
||||
'Speed',
|
||||
'BitField',
|
||||
'Type1',
|
||||
'Type2'])
|
||||
|
||||
self.expect("frame variable",
|
||||
patterns = ['\(Speed\) SPILookHex = 0x[0-9a-f]+' # Speed should look hex-ish now.
|
||||
]);
|
||||
|
||||
# Now let's delete the 'Speed' custom format.
|
||||
self.runCmd("type format delete Speed")
|
||||
|
||||
# The type format list should not show 'Speed' at this point.
|
||||
self.expect("type format list", matching=False,
|
||||
substrs = ['Speed'])
|
||||
|
||||
# Delete type format for 'Speed', we should expect an error message.
|
||||
self.expect("type format delete Speed", error=True,
|
||||
substrs = ['no custom format for Speed'])
|
||||
|
||||
# For some reason the type system is calling this "struct"
|
||||
self.runCmd("type summary add -o yes \"\" Point")
|
||||
|
||||
self.expect("frame variable iAmSomewhere",
|
||||
substrs = ['x=4',
|
||||
'y=6'])
|
||||
|
||||
self.expect("type summary list",
|
||||
substrs = ['Point',
|
||||
'one-line'])
|
||||
|
||||
self.runCmd("type summary add \"y=${var.y%x}\" Point")
|
||||
|
||||
self.expect("frame variable iAmSomewhere",
|
||||
substrs = ['y=0x'])
|
||||
|
||||
self.runCmd("type summary add \"hello\" Point -h yes")
|
||||
|
||||
self.expect("type summary list",
|
||||
substrs = ['Point',
|
||||
'show children'])
|
||||
|
||||
self.expect("frame variable iAmSomewhere",
|
||||
substrs = ['hello',
|
||||
'x = 4',
|
||||
'}'])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
lldb.SBDebugger.Initialize()
|
||||
atexit.register(lambda: lldb.SBDebugger.Terminate())
|
||||
unittest2.main()
|
|
@ -1,70 +0,0 @@
|
|||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef float RealNumber; // should show as char
|
||||
typedef RealNumber Temperature; // should show as float
|
||||
typedef RealNumber Speed; // should show as hex
|
||||
|
||||
typedef int Counter; // should show as int
|
||||
typedef int BitField; // should show as hex
|
||||
|
||||
typedef BitField SignalMask; // should show as hex
|
||||
typedef BitField Modifiers; // should show as hex
|
||||
|
||||
typedef Counter Accumulator; // should show as int
|
||||
|
||||
typedef int Type1; // should show as char
|
||||
typedef Type1 Type2; // should show as hex
|
||||
typedef Type2 Type3; // should show as char
|
||||
typedef Type3 Type4; // should show as char
|
||||
|
||||
typedef int ChildType; // should show as int
|
||||
typedef int AnotherChildType; // should show as int
|
||||
|
||||
struct Point {
|
||||
int x;
|
||||
int y;
|
||||
Point(int X = 3, int Y = 2) : x(X), y(Y) {}
|
||||
};
|
||||
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
|
||||
int iAmInt = 1;
|
||||
const float& IAmFloat = float(2.45);
|
||||
|
||||
RealNumber RNILookChar = 3.14;
|
||||
Temperature TMILookFloat = 4.97;
|
||||
Speed SPILookHex = 5.55;
|
||||
|
||||
Counter CTILookInt = 6;
|
||||
BitField BFILookHex = 7;
|
||||
SignalMask SMILookHex = 8;
|
||||
Modifiers MFILookHex = 9;
|
||||
|
||||
Accumulator* ACILookInt = new Accumulator(10);
|
||||
|
||||
const Type1& T1ILookChar = 11;
|
||||
Type2 T2ILookHex = 12;
|
||||
Type3 T3ILookChar = 13;
|
||||
Type4 T4ILookChar = 14;
|
||||
|
||||
AnotherChildType AHILookInt = 15;
|
||||
|
||||
Speed* SPPtrILookHex = new Speed(16);
|
||||
|
||||
Point iAmSomewhere(4,6);
|
||||
|
||||
return 0; // Set break point at this line.
|
||||
}
|
||||
|
Loading…
Reference in New Issue