https://github.com/ZequanWu updated https://github.com/llvm/llvm-project/pull/138209
>From dcb5b2596267d908dea1474164a1fadf1cd23aef Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Thu, 1 May 2025 14:51:24 -0700 Subject: [PATCH 1/4] [lldb][Formatters] Add --pointer-match-depth option to "type summary add" command. --- lldb/include/lldb/API/SBTypeSummary.h | 4 + .../lldb/DataFormatters/FormatClasses.h | 10 +- .../lldb/DataFormatters/FormatManager.h | 3 +- .../lldb/DataFormatters/FormattersContainer.h | 8 +- lldb/include/lldb/DataFormatters/TypeFormat.h | 5 + .../include/lldb/DataFormatters/TypeSummary.h | 17 ++- .../lldb/DataFormatters/TypeSynthetic.h | 5 + lldb/source/API/SBTypeSummary.cpp | 16 +++ lldb/source/Commands/CommandObjectType.cpp | 27 +++-- lldb/source/Commands/Options.td | 4 + lldb/source/DataFormatters/FormatManager.cpp | 40 ++++--- .../source/DataFormatters/TypeCategoryMap.cpp | 5 +- lldb/source/DataFormatters/TypeSummary.cpp | 37 ++++--- .../data-formatter-ptr-matching/Makefile | 4 + .../TestDataFormatterPtrMatching.py | 101 ++++++++++++++++++ .../data-formatter-ptr-matching/main.cpp | 32 ++++++ 16 files changed, 266 insertions(+), 52 deletions(-) create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py create mode 100644 lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp diff --git a/lldb/include/lldb/API/SBTypeSummary.h b/lldb/include/lldb/API/SBTypeSummary.h index 40fa146b4e31b..b6869e53a39e7 100644 --- a/lldb/include/lldb/API/SBTypeSummary.h +++ b/lldb/include/lldb/API/SBTypeSummary.h @@ -109,6 +109,10 @@ class SBTypeSummary { void SetFunctionCode(const char *data); + uint32_t GetPtrMatchDepth(); + + void SetPtrMatchDepth(uint32_t ptr_match_depth); + uint32_t GetOptions(); void SetOptions(uint32_t); diff --git a/lldb/include/lldb/DataFormatters/FormatClasses.h b/lldb/include/lldb/DataFormatters/FormatClasses.h index a6bc3a3542536..89d74649ecc64 100644 --- a/lldb/include/lldb/DataFormatters/FormatClasses.h +++ b/lldb/include/lldb/DataFormatters/FormatClasses.h @@ -76,9 +76,10 @@ class FormattersMatchCandidate { FormattersMatchCandidate(ConstString name, ScriptInterpreter *script_interpreter, TypeImpl type, - Flags flags) + Flags flags, uint32_t ptr_stripped_depth = 0) : m_type_name(name), m_script_interpreter(script_interpreter), - m_type(type), m_flags(flags) {} + m_type(type), m_flags(flags), m_ptr_stripped_depth(ptr_stripped_depth) { + } ~FormattersMatchCandidate() = default; @@ -96,6 +97,8 @@ class FormattersMatchCandidate { bool DidStripTypedef() const { return m_flags.stripped_typedef; } + uint32_t GetPtrStrippedDepth() const { return m_ptr_stripped_depth; } + template <class Formatter> bool IsMatch(const std::shared_ptr<Formatter> &formatter_sp) const { if (!formatter_sp) @@ -104,6 +107,8 @@ class FormattersMatchCandidate { return false; if (formatter_sp->SkipsPointers() && DidStripPointer()) return false; + if (formatter_sp->GetPtrMatchDepth() < GetPtrStrippedDepth()) + return false; if (formatter_sp->SkipsReferences() && DidStripReference()) return false; return true; @@ -116,6 +121,7 @@ class FormattersMatchCandidate { ScriptInterpreter *m_script_interpreter; TypeImpl m_type; Flags m_flags; + uint32_t m_ptr_stripped_depth; }; typedef std::vector<FormattersMatchCandidate> FormattersMatchVector; diff --git a/lldb/include/lldb/DataFormatters/FormatManager.h b/lldb/include/lldb/DataFormatters/FormatManager.h index db2fe99c44caf..9e24f7b722407 100644 --- a/lldb/include/lldb/DataFormatters/FormatManager.h +++ b/lldb/include/lldb/DataFormatters/FormatManager.h @@ -180,7 +180,8 @@ class FormatManager : public IFormatChangeListener { lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries, FormattersMatchCandidate::Flags current_flags, - bool root_level = false); + bool root_level = false, + uint32_t ptr_stripped_depth = 0); std::atomic<uint32_t> m_last_revision; FormatCache m_format_cache; diff --git a/lldb/include/lldb/DataFormatters/FormattersContainer.h b/lldb/include/lldb/DataFormatters/FormattersContainer.h index 7898621fd18af..f7465fc65538d 100644 --- a/lldb/include/lldb/DataFormatters/FormattersContainer.h +++ b/lldb/include/lldb/DataFormatters/FormattersContainer.h @@ -193,12 +193,10 @@ template <typename ValueType> class FormattersContainer { bool Get(const FormattersMatchVector &candidates, ValueSP &entry) { for (const FormattersMatchCandidate &candidate : candidates) { if (Get(candidate, entry)) { - if (candidate.IsMatch(entry) == false) { - entry.reset(); - continue; - } else { + if (candidate.IsMatch(entry)) return true; - } + entry.reset(); + continue; } } return false; diff --git a/lldb/include/lldb/DataFormatters/TypeFormat.h b/lldb/include/lldb/DataFormatters/TypeFormat.h index 63d4765bdf270..d242f9083d608 100644 --- a/lldb/include/lldb/DataFormatters/TypeFormat.h +++ b/lldb/include/lldb/DataFormatters/TypeFormat.h @@ -133,6 +133,10 @@ class TypeFormatImpl { void SetOptions(uint32_t value) { m_flags.SetValue(value); } + uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } + + void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } + uint32_t &GetRevision() { return m_my_revision; } enum class Type { eTypeUnknown, eTypeFormat, eTypeEnum }; @@ -150,6 +154,7 @@ class TypeFormatImpl { protected: Flags m_flags; uint32_t m_my_revision = 0; + uint32_t m_ptr_match_depth = 1; private: TypeFormatImpl(const TypeFormatImpl &) = delete; diff --git a/lldb/include/lldb/DataFormatters/TypeSummary.h b/lldb/include/lldb/DataFormatters/TypeSummary.h index f4d5563516ecb..589f68c2ce314 100644 --- a/lldb/include/lldb/DataFormatters/TypeSummary.h +++ b/lldb/include/lldb/DataFormatters/TypeSummary.h @@ -253,6 +253,10 @@ class TypeSummaryImpl { void SetOptions(uint32_t value) { m_flags.SetValue(value); } + uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } + + void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } + // we are using a ValueObject* instead of a ValueObjectSP because we do not // need to hold on to this for extended periods of time and we trust the // ValueObject to stay around for as long as it is required for us to @@ -278,10 +282,12 @@ class TypeSummaryImpl { uint32_t m_my_revision = 0; Flags m_flags; - TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags); + TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags, + uint32_t ptr_match_depth = 1); private: Kind m_kind; + uint32_t m_ptr_match_depth = 1; TypeSummaryImpl(const TypeSummaryImpl &) = delete; const TypeSummaryImpl &operator=(const TypeSummaryImpl &) = delete; }; @@ -292,7 +298,8 @@ struct StringSummaryFormat : public TypeSummaryImpl { FormatEntity::Entry m_format; Status m_error; - StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f); + StringSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *f, + uint32_t ptr_match_depth = 1); ~StringSummaryFormat() override = default; @@ -328,7 +335,8 @@ struct CXXFunctionSummaryFormat : public TypeSummaryImpl { std::string m_description; CXXFunctionSummaryFormat(const TypeSummaryImpl::Flags &flags, Callback impl, - const char *description); + const char *description, + uint32_t ptr_match_depth = 1); ~CXXFunctionSummaryFormat() override = default; @@ -373,7 +381,8 @@ struct ScriptSummaryFormat : public TypeSummaryImpl { ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *function_name, - const char *python_script = nullptr); + const char *python_script = nullptr, + uint32_t ptr_match_depth = 1); ~ScriptSummaryFormat() override = default; diff --git a/lldb/include/lldb/DataFormatters/TypeSynthetic.h b/lldb/include/lldb/DataFormatters/TypeSynthetic.h index c8d7d15588065..37f02fb8f7ce5 100644 --- a/lldb/include/lldb/DataFormatters/TypeSynthetic.h +++ b/lldb/include/lldb/DataFormatters/TypeSynthetic.h @@ -273,9 +273,14 @@ class SyntheticChildren { uint32_t &GetRevision() { return m_my_revision; } + uint32_t GetPtrMatchDepth() { return m_ptr_match_depth; } + + void SetPtrMatchDepth(uint32_t value) { m_ptr_match_depth = value; } + protected: uint32_t m_my_revision = 0; Flags m_flags; + uint32_t m_ptr_match_depth = 1; private: SyntheticChildren(const SyntheticChildren &) = delete; diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp index 856ee0ed3175b..d7acb0670018a 100644 --- a/lldb/source/API/SBTypeSummary.cpp +++ b/lldb/source/API/SBTypeSummary.cpp @@ -230,6 +230,22 @@ const char *SBTypeSummary::GetData() { return nullptr; } +uint32_t SBTypeSummary::GetPtrMatchDepth() { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return 0; + return m_opaque_sp->GetPtrMatchDepth(); +} + +void SBTypeSummary::SetPtrMatchDepth(uint32_t ptr_match_depth) { + LLDB_INSTRUMENT_VA(this); + + if (!IsValid()) + return; + return m_opaque_sp->SetPtrMatchDepth(ptr_match_depth); +} + uint32_t SBTypeSummary::GetOptions() { LLDB_INSTRUMENT_VA(this); diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp index 41630b61c2f0e..19cd3ff2972e9 100644 --- a/lldb/source/Commands/CommandObjectType.cpp +++ b/lldb/source/Commands/CommandObjectType.cpp @@ -51,12 +51,13 @@ class ScriptAddOptions { FormatterMatchType m_match_type; ConstString m_name; std::string m_category; + uint32_t m_ptr_match_depth; ScriptAddOptions(const TypeSummaryImpl::Flags &flags, FormatterMatchType match_type, ConstString name, - std::string catg) + std::string catg, uint32_t m_ptr_match_depth) : m_flags(flags), m_match_type(match_type), m_name(name), - m_category(catg) {} + m_category(catg), m_ptr_match_depth(m_ptr_match_depth) {} typedef std::shared_ptr<ScriptAddOptions> SharedPointer; }; @@ -146,6 +147,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, std::string m_python_function; bool m_is_add_script = false; std::string m_category; + uint32_t m_ptr_match_depth = 1; }; CommandOptions m_options; @@ -211,7 +213,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed, TypeSummaryImplSP script_format; script_format = std::make_shared<ScriptSummaryFormat>( options->m_flags, funct_name_str.c_str(), - lines.CopyList(" ").c_str()); + lines.CopyList(" ").c_str(), options->m_ptr_match_depth); Status error; @@ -1178,6 +1180,13 @@ Status CommandObjectTypeSummaryAdd::CommandOptions::SetOptionValue( case 'p': m_flags.SetSkipPointers(true); break; + case 'd': + if (option_arg.getAsInteger(0, m_ptr_match_depth)) { + error = Status::FromErrorStringWithFormat( + "invalid integer value for option '%c': %s", short_option, + option_arg.data()); + } + break; case 'r': m_flags.SetSkipReferences(true); break; @@ -1266,7 +1275,8 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( (" " + m_options.m_python_function + "(valobj,internal_dict)"); script_format = std::make_shared<ScriptSummaryFormat>( - m_options.m_flags, funct_name, code.c_str()); + m_options.m_flags, funct_name, code.c_str(), + m_options.m_ptr_match_depth); ScriptInterpreter *interpreter = GetDebugger().GetScriptInterpreter(); @@ -1300,12 +1310,13 @@ bool CommandObjectTypeSummaryAdd::Execute_ScriptSummary( std::string code = " " + m_options.m_python_script; script_format = std::make_shared<ScriptSummaryFormat>( - m_options.m_flags, funct_name_str.c_str(), code.c_str()); + m_options.m_flags, funct_name_str.c_str(), code.c_str(), + m_options.m_ptr_match_depth); } else { // Use an IOHandler to grab Python code from the user auto options = std::make_unique<ScriptAddOptions>( m_options.m_flags, m_options.m_match_type, m_options.m_name, - m_options.m_category); + m_options.m_category, m_options.m_ptr_match_depth); for (auto &entry : command.entries()) { if (entry.ref().empty()) { @@ -1380,8 +1391,8 @@ bool CommandObjectTypeSummaryAdd::Execute_StringSummary( return false; } - std::unique_ptr<StringSummaryFormat> string_format( - new StringSummaryFormat(m_options.m_flags, format_cstr)); + std::unique_ptr<StringSummaryFormat> string_format(new StringSummaryFormat( + m_options.m_flags, format_cstr, m_options.m_ptr_match_depth)); if (!string_format) { result.AppendError("summary creation failed"); return false; diff --git a/lldb/source/Commands/Options.td b/lldb/source/Commands/Options.td index 53864ff29327d..9dd7467b4269c 100644 --- a/lldb/source/Commands/Options.td +++ b/lldb/source/Commands/Options.td @@ -1240,6 +1240,10 @@ let Command = "type summary add" in { Desc<"Don't show the value, just show the summary, for this type.">; def type_summary_add_skip_pointers : Option<"skip-pointers", "p">, Desc<"Don't use this format for pointers-to-type objects.">; + def type_summary_add_pointer_match_depth : Option<"pointer-match-depth", "d">, + Arg<"UnsignedInteger">, + Desc<"Specify the maximum pointer depth that this format can be apply to " + "(default to 1). It's only effective when --skip-pointers is not set.">; def type_summary_add_skip_references : Option<"skip-references", "r">, Desc<"Don't use this format for references-to-type objects.">; def type_summary_add_regex : Option<"regex", "x">, diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 3b891cecb1c8b..122f2304ead24 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -174,7 +174,8 @@ void FormatManager::DisableAllCategories() { void FormatManager::GetPossibleMatches( ValueObject &valobj, CompilerType compiler_type, lldb::DynamicValueType use_dynamic, FormattersMatchVector &entries, - FormattersMatchCandidate::Flags current_flags, bool root_level) { + FormattersMatchCandidate::Flags current_flags, bool root_level, + uint32_t ptr_stripped_depth) { compiler_type = compiler_type.GetTypeForFormatters(); ConstString type_name(compiler_type.GetTypeName()); // A ValueObject that couldn't be made correctly won't necessarily have a @@ -190,46 +191,51 @@ void FormatManager::GetPossibleMatches( sstring.Printf("%s:%d", type_name.AsCString(), valobj.GetBitfieldBitSize()); ConstString bitfieldname(sstring.GetString()); entries.push_back({bitfieldname, script_interpreter, - TypeImpl(compiler_type), current_flags}); + TypeImpl(compiler_type), current_flags, + ptr_stripped_depth}); } if (!compiler_type.IsMeaninglessWithoutDynamicResolution()) { entries.push_back({type_name, script_interpreter, TypeImpl(compiler_type), - current_flags}); + current_flags, ptr_stripped_depth}); ConstString display_type_name(compiler_type.GetTypeName()); if (display_type_name != type_name) entries.push_back({display_type_name, script_interpreter, - TypeImpl(compiler_type), current_flags}); + TypeImpl(compiler_type), current_flags, + ptr_stripped_depth}); } for (bool is_rvalue_ref = true, j = true; j && compiler_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) { CompilerType non_ref_type = compiler_type.GetNonReferenceType(); GetPossibleMatches(valobj, non_ref_type, use_dynamic, entries, - current_flags.WithStrippedReference()); + current_flags.WithStrippedReference(), root_level, + ptr_stripped_depth); if (non_ref_type.IsTypedefType()) { CompilerType deffed_referenced_type = non_ref_type.GetTypedefedType(); deffed_referenced_type = is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType() : deffed_referenced_type.GetLValueReferenceType(); // this is not exactly the usual meaning of stripping typedefs - GetPossibleMatches( - valobj, deffed_referenced_type, - use_dynamic, entries, current_flags.WithStrippedTypedef()); + GetPossibleMatches(valobj, deffed_referenced_type, use_dynamic, entries, + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth); } } if (compiler_type.IsPointerType()) { CompilerType non_ptr_type = compiler_type.GetPointeeType(); GetPossibleMatches(valobj, non_ptr_type, use_dynamic, entries, - current_flags.WithStrippedPointer()); + current_flags.WithStrippedPointer(), root_level, + ptr_stripped_depth + 1); if (non_ptr_type.IsTypedefType()) { CompilerType deffed_pointed_type = non_ptr_type.GetTypedefedType().GetPointerType(); // this is not exactly the usual meaning of stripping typedefs GetPossibleMatches(valobj, deffed_pointed_type, use_dynamic, entries, - current_flags.WithStrippedTypedef()); + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth + 1); } } @@ -246,9 +252,9 @@ void FormatManager::GetPossibleMatches( CompilerType deffed_array_type = element_type.GetTypedefedType().GetArrayType(array_size); // this is not exactly the usual meaning of stripping typedefs - GetPossibleMatches( - valobj, deffed_array_type, - use_dynamic, entries, current_flags.WithStrippedTypedef()); + GetPossibleMatches(valobj, deffed_array_type, use_dynamic, entries, + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth); } } @@ -266,7 +272,8 @@ void FormatManager::GetPossibleMatches( if (compiler_type.IsTypedefType()) { CompilerType deffed_type = compiler_type.GetTypedefedType(); GetPossibleMatches(valobj, deffed_type, use_dynamic, entries, - current_flags.WithStrippedTypedef()); + current_flags.WithStrippedTypedef(), root_level, + ptr_stripped_depth); } if (root_level) { @@ -281,7 +288,8 @@ void FormatManager::GetPossibleMatches( if (unqual_compiler_ast_type.GetOpaqueQualType() != compiler_type.GetOpaqueQualType()) GetPossibleMatches(valobj, unqual_compiler_ast_type, use_dynamic, - entries, current_flags); + entries, current_flags, root_level, + ptr_stripped_depth); } while (false); // if all else fails, go to static type @@ -290,7 +298,7 @@ void FormatManager::GetPossibleMatches( if (static_value_sp) GetPossibleMatches(*static_value_sp.get(), static_value_sp->GetCompilerType(), use_dynamic, - entries, current_flags, true); + entries, current_flags, true, ptr_stripped_depth); } } } diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index ce2cf369b5be5..8682e4b7435e4 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -185,12 +185,13 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { for (auto match : match_data.GetMatchesVector()) { LLDB_LOGF( log, - "[%s] candidate match = %s %s %s %s", + "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u", __FUNCTION__, match.GetTypeName().GetCString(), match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", match.DidStripReference() ? "strip-reference" : "no-strip-reference", - match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef"); + match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef", + match.GetPtrStrippedDepth()); } } diff --git a/lldb/source/DataFormatters/TypeSummary.cpp b/lldb/source/DataFormatters/TypeSummary.cpp index 18bf81aedf2cb..6aa290698cd12 100644 --- a/lldb/source/DataFormatters/TypeSummary.cpp +++ b/lldb/source/DataFormatters/TypeSummary.cpp @@ -43,8 +43,9 @@ TypeSummaryOptions::SetCapping(lldb::TypeSummaryCapping cap) { return *this; } -TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags) - : m_flags(flags), m_kind(kind) {} +TypeSummaryImpl::TypeSummaryImpl(Kind kind, const TypeSummaryImpl::Flags &flags, + uint32_t ptr_match_depth) + : m_flags(flags), m_kind(kind), m_ptr_match_depth(ptr_match_depth) {} std::string TypeSummaryImpl::GetSummaryKindName() { switch (m_kind) { @@ -63,8 +64,10 @@ std::string TypeSummaryImpl::GetSummaryKindName() { } StringSummaryFormat::StringSummaryFormat(const TypeSummaryImpl::Flags &flags, - const char *format_cstr) - : TypeSummaryImpl(Kind::eSummaryString, flags), m_format_str() { + const char *format_cstr, + uint32_t ptr_match_depth) + : TypeSummaryImpl(Kind::eSummaryString, flags, ptr_match_depth), + m_format_str() { SetSummaryString(format_cstr); } @@ -117,7 +120,7 @@ bool StringSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, std::string StringSummaryFormat::GetDescription() { StreamString sstr; - sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s", m_format_str.c_str(), + sstr.Printf("`%s`%s%s%s%s%s%s%s%s%s ptr-match-depth=%u", m_format_str.c_str(), m_error.Fail() ? " error: " : "", m_error.Fail() ? m_error.AsCString() : "", Cascades() ? "" : " (not cascading)", @@ -126,15 +129,17 @@ std::string StringSummaryFormat::GetDescription() { IsOneLiner() ? " (one-line printout)" : "", SkipsPointers() ? " (skip pointers)" : "", SkipsReferences() ? " (skip references)" : "", - HideNames(nullptr) ? " (hide member names)" : ""); + HideNames(nullptr) ? " (hide member names)" : "", + GetPtrMatchDepth()); return std::string(sstr.GetString()); } std::string StringSummaryFormat::GetName() { return m_format_str; } CXXFunctionSummaryFormat::CXXFunctionSummaryFormat( - const TypeSummaryImpl::Flags &flags, Callback impl, const char *description) - : TypeSummaryImpl(Kind::eCallback, flags), m_impl(impl), + const TypeSummaryImpl::Flags &flags, Callback impl, const char *description, + uint32_t ptr_match_depth) + : TypeSummaryImpl(Kind::eCallback, flags, ptr_match_depth), m_impl(impl), m_description(description ? description : "") {} bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj, @@ -150,14 +155,15 @@ bool CXXFunctionSummaryFormat::FormatObject(ValueObject *valobj, std::string CXXFunctionSummaryFormat::GetDescription() { StreamString sstr; - sstr.Printf("%s%s%s%s%s%s%s %s", Cascades() ? "" : " (not cascading)", + sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u %s", + Cascades() ? "" : " (not cascading)", !DoesPrintChildren(nullptr) ? "" : " (show children)", !DoesPrintValue(nullptr) ? " (hide value)" : "", IsOneLiner() ? " (one-line printout)" : "", SkipsPointers() ? " (skip pointers)" : "", SkipsReferences() ? " (skip references)" : "", HideNames(nullptr) ? " (hide member names)" : "", - m_description.c_str()); + GetPtrMatchDepth(), m_description.c_str()); return std::string(sstr.GetString()); } @@ -165,8 +171,9 @@ std::string CXXFunctionSummaryFormat::GetName() { return m_description; } ScriptSummaryFormat::ScriptSummaryFormat(const TypeSummaryImpl::Flags &flags, const char *function_name, - const char *python_script) - : TypeSummaryImpl(Kind::eScript, flags), m_function_name(), + const char *python_script, + uint32_t ptr_match_depth) + : TypeSummaryImpl(Kind::eScript, flags, ptr_match_depth), m_function_name(), m_python_script(), m_script_function_sp() { // Take preference in the python script name over the function name. if (function_name) { @@ -211,13 +218,15 @@ bool ScriptSummaryFormat::FormatObject(ValueObject *valobj, std::string &retval, std::string ScriptSummaryFormat::GetDescription() { StreamString sstr; - sstr.Printf("%s%s%s%s%s%s%s\n ", Cascades() ? "" : " (not cascading)", + sstr.Printf("%s%s%s%s%s%s%s ptr-match-depth=%u\n ", + Cascades() ? "" : " (not cascading)", !DoesPrintChildren(nullptr) ? "" : " (show children)", !DoesPrintValue(nullptr) ? " (hide value)" : "", IsOneLiner() ? " (one-line printout)" : "", SkipsPointers() ? " (skip pointers)" : "", SkipsReferences() ? " (skip references)" : "", - HideNames(nullptr) ? " (hide member names)" : ""); + HideNames(nullptr) ? " (hide member names)" : "", + GetPtrMatchDepth()); if (m_python_script.empty()) { if (m_function_name.empty()) { sstr.PutCString("no backing script"); diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile new file mode 100644 index 0000000000000..a149c7f81bfab --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/Makefile @@ -0,0 +1,4 @@ +CXX_SOURCES := main.cpp + +CXXFLAGS_EXTRAS := -O0 +include Makefile.rules diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py new file mode 100644 index 0000000000000..f960526466076 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py @@ -0,0 +1,101 @@ +""" +Test lldb data formatter subsystem. +""" + +import os +import lldb +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + + +class PtrMatchingDataFormatterTestCase(TestBase): + 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 test_summary_with_command(self): + """Test "type summary add" command line option "--pointer-match-depth".""" + self.build() + self.runCmd("file " + self.getBuildArtifact("a.out"), CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line( + self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True + ) + + self.runCmd("run", RUN_SUCCEEDED) + + # 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) + + # By default, --pointer-match-depth is 1. + self.runCmd('type summary add --cascade true -s "MyInt" "Int"') + self.expect("frame variable", patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+\n", + r".* bp_pp = 0x[0-9a-f]+\n", + ]) + + self.runCmd('type summary delete "Int"') + self.runCmd( + 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"') + self.expect("frame variable", patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+ MyInt\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+ MyInt\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+ MyInt\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+ MyInt\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+ MyInt\n", + r".* bp_pp = 0x[0-9a-f]+\n", + ]) + + self.runCmd('type summary delete "Int"') + self.runCmd( + 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"') + self.expect("frame variable", patterns=[ + r".* f = MyFoo\n", + r".* f_p = 0x[0-9a-f]+ MyFoo\n", + r".* f_pp = 0x[0-9a-f]+ MyFoo\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyFoo\n", + r".* b_p = 0x[0-9a-f]+ MyFoo\n", + r".* b_pp = 0x[0-9a-f]+ MyFoo\n", + r".* bp = 0x[0-9a-f]+ MyFoo\n", + r".* bp_p = 0x[0-9a-f]+ MyFoo\n", + r".* bp_pp = 0x[0-9a-f]+\n", + ]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp new file mode 100644 index 0000000000000..5fafae53d1c21 --- /dev/null +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp @@ -0,0 +1,32 @@ +struct Int { + int i; +}; +typedef Int Foo; +typedef Int* FooP; +typedef Foo Bar; +typedef Foo* BarP; + +int main() { + Int i = {42}; + Int* i_p = &i; + Int** i_pp = &i_p; + Int*** i_ppp = &i_pp; + + Foo f = i; + Foo* f_p = &f; + Foo** f_pp = &f_p; + Foo*** f_ppp = &f_pp; + + FooP fp = f_p; + FooP* fp_p = &fp; + FooP** fp_pp = &fp_p; + + Bar b = i; + Bar* b_p = &b; + Bar** b_pp = &b_p; + + BarP bp = b_p; + BarP* bp_p = &bp; + BarP** bp_pp = &bp_p; + return 0; // Set break point at this line. +} >From 91619c0322bc542da14123f173a3c6b34d412feb Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Fri, 2 May 2025 11:52:38 -0700 Subject: [PATCH 2/4] address comments --- lldb/docs/use/variable.rst | 10 ++ lldb/source/API/SBTypeSummary.cpp | 2 +- .../source/DataFormatters/TypeCategoryMap.cpp | 8 +- .../TestDataFormatterPtrMatching.py | 109 ++++++++++-------- .../data-formatter-ptr-matching/main.cpp | 28 ++--- 5 files changed, 86 insertions(+), 71 deletions(-) diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index 3ad71cb93c51d..d6b8b78f01ebe 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -366,6 +366,16 @@ The command to obtain the output shown in the example is: Initially, we will focus on summary strings, and then describe the Python binding mechanism. +Summary Format Matching On Pointers +---------------------- + +When a summary format is registered for a type ``T``, lldb will apply this +format to both ``T`` and ``T*``. -p options could prevent lldb from using this +format to type ``T*``. When -p options is not given, users can use the -d option +to specify how many layer of pointers can be dereferenced at most when matching +the format of type ``T`` (default to 1). It should be noted that the value +object passed to the summary format won't dereferenced at all. + Summary Strings --------------- diff --git a/lldb/source/API/SBTypeSummary.cpp b/lldb/source/API/SBTypeSummary.cpp index d7acb0670018a..58ec068ab9600 100644 --- a/lldb/source/API/SBTypeSummary.cpp +++ b/lldb/source/API/SBTypeSummary.cpp @@ -232,7 +232,7 @@ const char *SBTypeSummary::GetData() { uint32_t SBTypeSummary::GetPtrMatchDepth() { LLDB_INSTRUMENT_VA(this); - + if (!IsValid()) return 0; return m_opaque_sp->GetPtrMatchDepth(); diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index 8682e4b7435e4..81b7e1f2b7d49 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -184,14 +184,12 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { if (log) { for (auto match : match_data.GetMatchesVector()) { LLDB_LOGF( - log, - "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u", - __FUNCTION__, - match.GetTypeName().GetCString(), + log, "[%s] candidate match = %s %s %s %s ptr-stripped-depth=%u", + __FUNCTION__, match.GetTypeName().GetCString(), match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", match.DidStripReference() ? "strip-reference" : "no-strip-reference", match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef", - match.GetPtrStrippedDepth()); + match.GetPtrStrippingDepth()); } } diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py index f960526466076..8de712a749578 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py @@ -38,64 +38,71 @@ def cleanup(): # By default, --pointer-match-depth is 1. self.runCmd('type summary add --cascade true -s "MyInt" "Int"') - self.expect("frame variable", patterns=[ - r".* i = MyInt\n", - r".* i_p = 0x.* MyInt\n", - r".* i_pp = 0x[0-9a-f]+\n", - r".* i_ppp = 0x[0-9a-f]+\n", - r".* f = MyInt\n", - r".* f_p = 0x[0-9a-f]+ MyInt\n", - r".* f_pp = 0x[0-9a-f]+\n", - r".* f_ppp = 0x[0-9a-f]+\n", - r".* fp = 0x[0-9a-f]+ MyInt\n", - r".* fp_p = 0x[0-9a-f]+\n", - r".* fp_pp = 0x[0-9a-f]+\n", - r".* b = MyInt\n", - r".* b_p = 0x[0-9a-f]+ MyInt\n", - r".* b_pp = 0x[0-9a-f]+\n", - r".* bp = 0x[0-9a-f]+ MyInt\n", - r".* bp_p = 0x[0-9a-f]+\n", - r".* bp_pp = 0x[0-9a-f]+\n", + self.expect( + "frame variable", + patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+\n", + r".* bp_pp = 0x[0-9a-f]+\n", ]) self.runCmd('type summary delete "Int"') self.runCmd( 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"') - self.expect("frame variable", patterns=[ - r".* i = MyInt\n", - r".* i_p = 0x.* MyInt\n", - r".* i_pp = 0x[0-9a-f]+ MyInt\n", - r".* i_ppp = 0x[0-9a-f]+\n", - r".* f = MyInt\n", - r".* f_p = 0x[0-9a-f]+ MyInt\n", - r".* f_pp = 0x[0-9a-f]+ MyInt\n", - r".* f_ppp = 0x[0-9a-f]+\n", - r".* fp = 0x[0-9a-f]+ MyInt\n", - r".* fp_p = 0x[0-9a-f]+ MyInt\n", - r".* fp_pp = 0x[0-9a-f]+\n", - r".* b = MyInt\n", - r".* b_p = 0x[0-9a-f]+ MyInt\n", - r".* b_pp = 0x[0-9a-f]+ MyInt\n", - r".* bp = 0x[0-9a-f]+ MyInt\n", - r".* bp_p = 0x[0-9a-f]+ MyInt\n", - r".* bp_pp = 0x[0-9a-f]+\n", + self.expect( + "frame variable", + patterns=[ + r".* i = MyInt\n", + r".* i_p = 0x.* MyInt\n", + r".* i_pp = 0x[0-9a-f]+ MyInt\n", + r".* i_ppp = 0x[0-9a-f]+\n", + r".* f = MyInt\n", + r".* f_p = 0x[0-9a-f]+ MyInt\n", + r".* f_pp = 0x[0-9a-f]+ MyInt\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+ MyInt\n", + r".* fp_p = 0x[0-9a-f]+ MyInt\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyInt\n", + r".* b_p = 0x[0-9a-f]+ MyInt\n", + r".* b_pp = 0x[0-9a-f]+ MyInt\n", + r".* bp = 0x[0-9a-f]+ MyInt\n", + r".* bp_p = 0x[0-9a-f]+ MyInt\n", + r".* bp_pp = 0x[0-9a-f]+\n", ]) self.runCmd('type summary delete "Int"') self.runCmd( - 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"') - self.expect("frame variable", patterns=[ - r".* f = MyFoo\n", - r".* f_p = 0x[0-9a-f]+ MyFoo\n", - r".* f_pp = 0x[0-9a-f]+ MyFoo\n", - r".* f_ppp = 0x[0-9a-f]+\n", - r".* fp = 0x[0-9a-f]+\n", - r".* fp_p = 0x[0-9a-f]+\n", - r".* fp_pp = 0x[0-9a-f]+\n", - r".* b = MyFoo\n", - r".* b_p = 0x[0-9a-f]+ MyFoo\n", - r".* b_pp = 0x[0-9a-f]+ MyFoo\n", - r".* bp = 0x[0-9a-f]+ MyFoo\n", - r".* bp_p = 0x[0-9a-f]+ MyFoo\n", - r".* bp_pp = 0x[0-9a-f]+\n", + 'type summary add --cascade true --pointer-match-depth 2 -s "MyFoo" "Foo"' + ) + self.expect( + "frame variable", + patterns=[ + r".* f = MyFoo\n", + r".* f_p = 0x[0-9a-f]+ MyFoo\n", + r".* f_pp = 0x[0-9a-f]+ MyFoo\n", + r".* f_ppp = 0x[0-9a-f]+\n", + r".* fp = 0x[0-9a-f]+\n", + r".* fp_p = 0x[0-9a-f]+\n", + r".* fp_pp = 0x[0-9a-f]+\n", + r".* b = MyFoo\n", + r".* b_p = 0x[0-9a-f]+ MyFoo\n", + r".* b_pp = 0x[0-9a-f]+ MyFoo\n", + r".* bp = 0x[0-9a-f]+ MyFoo\n", + r".* bp_p = 0x[0-9a-f]+ MyFoo\n", + r".* bp_pp = 0x[0-9a-f]+\n", ]) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp index 5fafae53d1c21..2d8c7193b959c 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/main.cpp @@ -2,31 +2,31 @@ struct Int { int i; }; typedef Int Foo; -typedef Int* FooP; +typedef Int *FooP; typedef Foo Bar; -typedef Foo* BarP; +typedef Foo *BarP; int main() { Int i = {42}; - Int* i_p = &i; - Int** i_pp = &i_p; - Int*** i_ppp = &i_pp; + Int *i_p = &i; + Int **i_pp = &i_p; + Int ***i_ppp = &i_pp; Foo f = i; - Foo* f_p = &f; - Foo** f_pp = &f_p; - Foo*** f_ppp = &f_pp; + Foo *f_p = &f; + Foo **f_pp = &f_p; + Foo ***f_ppp = &f_pp; FooP fp = f_p; - FooP* fp_p = &fp; - FooP** fp_pp = &fp_p; + FooP *fp_p = &fp; + FooP **fp_pp = &fp_p; Bar b = i; - Bar* b_p = &b; - Bar** b_pp = &b_p; + Bar *b_p = &b; + Bar **b_pp = &b_p; BarP bp = b_p; - BarP* bp_p = &bp; - BarP** bp_pp = &bp_p; + BarP *bp_p = &bp; + BarP **bp_pp = &bp_p; return 0; // Set break point at this line. } >From 022526721fcf7d917626d004467f121e7cf33a3c Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Fri, 2 May 2025 13:41:24 -0700 Subject: [PATCH 3/4] format --- .../TestDataFormatterPtrMatching.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py index 8de712a749578..ebefe87e913a3 100644 --- a/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py +++ b/lldb/test/API/functionalities/data-formatter/data-formatter-ptr-matching/TestDataFormatterPtrMatching.py @@ -58,11 +58,13 @@ def cleanup(): r".* bp = 0x[0-9a-f]+ MyInt\n", r".* bp_p = 0x[0-9a-f]+\n", r".* bp_pp = 0x[0-9a-f]+\n", - ]) + ], + ) self.runCmd('type summary delete "Int"') self.runCmd( - 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"') + 'type summary add --cascade true --pointer-match-depth 2 -s "MyInt" "Int"' + ) self.expect( "frame variable", patterns=[ @@ -83,7 +85,8 @@ def cleanup(): r".* bp = 0x[0-9a-f]+ MyInt\n", r".* bp_p = 0x[0-9a-f]+ MyInt\n", r".* bp_pp = 0x[0-9a-f]+\n", - ]) + ], + ) self.runCmd('type summary delete "Int"') self.runCmd( @@ -105,4 +108,5 @@ def cleanup(): r".* bp = 0x[0-9a-f]+ MyFoo\n", r".* bp_p = 0x[0-9a-f]+ MyFoo\n", r".* bp_pp = 0x[0-9a-f]+\n", - ]) + ], + ) >From d6ca5bc643ee2be77febbde219fcfd011f855483 Mon Sep 17 00:00:00 2001 From: Zequan Wu <zequa...@google.com> Date: Fri, 2 May 2025 15:26:10 -0700 Subject: [PATCH 4/4] fix name --- lldb/source/DataFormatters/TypeCategoryMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/source/DataFormatters/TypeCategoryMap.cpp b/lldb/source/DataFormatters/TypeCategoryMap.cpp index 81b7e1f2b7d49..c318e1d2d1354 100644 --- a/lldb/source/DataFormatters/TypeCategoryMap.cpp +++ b/lldb/source/DataFormatters/TypeCategoryMap.cpp @@ -189,7 +189,7 @@ void TypeCategoryMap::Get(FormattersMatchData &match_data, ImplSP &retval) { match.DidStripPointer() ? "strip-pointers" : "no-strip-pointers", match.DidStripReference() ? "strip-reference" : "no-strip-reference", match.DidStripTypedef() ? "strip-typedef" : "no-strip-typedef", - match.GetPtrStrippingDepth()); + match.GetPtrStrippedDepth()); } } _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits