Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

[lldb][Formatters] Add --pointer-match-depth option to type summary add command. #138209

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
May 28, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions 14 lldb/docs/use/variable.rst
Original file line number Diff line number Diff line change
Expand Up @@ -366,6 +366,20 @@ 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
----------------------

A summary formatter for a type ``T`` might or might not be appropriate to use
for pointers to that type. If the formatter is only appropriate for the type and
not its pointers, use the ``-p`` option to restrict it to match SBValues of type
``T``. If you want the formatter to also match pointers to the type, you can use
the ``-d`` option to specify how many pointer layers the formatter should match.
The default value is 1, so if you don't specify ``-p`` or ``-d``, your formatter
will be used on SBValues of type ``T`` and ``T*``. If you want to also match
``T**`` set ``-d`` to 2, etc. In all cases, the SBValue passed to the summary
formatter will be the matched ValueObject. lldb doesn't dereference the matched
value down to the SBValue of type ``T`` before passing it to your formatter.

Summary Strings
---------------

Expand Down
4 changes: 4 additions & 0 deletions 4 lldb/include/lldb/API/SBTypeSummary.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 8 additions & 2 deletions 10 lldb/include/lldb/DataFormatters/FormatClasses.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -96,6 +97,8 @@ class FormattersMatchCandidate {

bool DidStripTypedef() const { return m_flags.stripped_typedef; }

uint32_t GetPtrStrippedDepth() const { return m_ptr_stripped_depth; }
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this reads better as GetPtrStrippingDepth than GetPtrStrippedDepth. You aren't asking about something that has been done, but about a thing you are planning to do, so active seems more appropriate.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I meant this FormattersMatchCandidate has been stripped # of pointers from its original type. m_ptr_stripped_depth is from FormatManager::GetPossibleMatches. That's after we stripped the # of pointers from a variable. For int**, after we recurse into GetPossibleMatches twice, we have int and stripped depth being 2.


template <class Formatter>
bool IsMatch(const std::shared_ptr<Formatter> &formatter_sp) const {
if (!formatter_sp)
Expand All @@ -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;
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion 3 lldb/include/lldb/DataFormatters/FormatManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
8 changes: 3 additions & 5 deletions 8 lldb/include/lldb/DataFormatters/FormattersContainer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
5 changes: 5 additions & 0 deletions 5 lldb/include/lldb/DataFormatters/TypeFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 };
Expand All @@ -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;
Expand Down
17 changes: 13 additions & 4 deletions 17 lldb/include/lldb/DataFormatters/TypeSummary.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
};
Expand All @@ -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;

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions 5 lldb/include/lldb/DataFormatters/TypeSynthetic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
16 changes: 16 additions & 0 deletions 16 lldb/source/API/SBTypeSummary.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
27 changes: 19 additions & 8 deletions 27 lldb/source/Commands/CommandObjectType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;

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

Expand Down Expand Up @@ -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()) {
Expand Down Expand Up @@ -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;
Expand Down
4 changes: 4 additions & 0 deletions 4 lldb/source/Commands/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down
Loading
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.