Skip to content

Commit c90cb6e

Browse files
[lldb] colorize symbols in image lookup with a regex pattern (llvm#69422)
Fixes llvm#57372 Previously some work has already been done on this. A PR was generated but it remained in review: https://reviews.llvm.org/D136462 In short previous approach was following: Changing the symbol names (making the searched part colorized) -> printing them -> restoring the symbol names back in their original form. The reviewers suggested that instead of changing the symbol table, this colorization should be done in the dump functions itself. Our strategy involves passing the searched regex pattern to the existing dump functions responsible for printing information about the searched symbol. This pattern is propagated until it reaches the line in the dump functions responsible for displaying symbol information on screen. At this point, we've introduced a new function called "PutCStringColorHighlighted," which takes the searched pattern, a prefix and suffix, and the text and applies colorization to highlight the pattern in the output. This approach aims to streamline the symbol search process to improve readability of search results. Co-authored-by: José L. Junior <[email protected]>
1 parent faecc73 commit c90cb6e

File tree

13 files changed

+239
-35
lines changed

13 files changed

+239
-35
lines changed

lldb/include/lldb/Core/Address.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
#include "lldb/lldb-private-enumerations.h"
1515
#include "lldb/lldb-types.h"
1616

17+
#include "llvm/ADT/StringRef.h"
18+
1719
#include <cstddef>
1820
#include <cstdint>
1921

@@ -237,6 +239,12 @@ class Address {
237239
/// contains the address, otherwise dumping the range that contains the
238240
/// address.
239241
///
242+
/// \param[in] pattern
243+
/// An optional regex pattern to match against the description. If
244+
/// specified, parts of the description matching this pattern may be
245+
/// highlighted or processed differently. If this parameter is an empty
246+
/// string or not provided, no highlighting is applied.
247+
///
240248
/// \return
241249
/// Returns \b true if the address was able to be displayed.
242250
/// File and load addresses may be unresolved and it may not be
@@ -246,8 +254,8 @@ class Address {
246254
/// \see Address::DumpStyle
247255
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
248256
DumpStyle fallback_style = DumpStyleInvalid,
249-
uint32_t addr_byte_size = UINT32_MAX,
250-
bool all_ranges = false) const;
257+
uint32_t addr_byte_size = UINT32_MAX, bool all_ranges = false,
258+
llvm::StringRef pattern = "") const;
251259

252260
AddressClass GetAddressClass() const;
253261

lldb/include/lldb/Core/Debugger.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
321321

322322
llvm::StringRef GetAutosuggestionAnsiSuffix() const;
323323

324+
llvm::StringRef GetRegexMatchAnsiPrefix() const;
325+
326+
llvm::StringRef GetRegexMatchAnsiSuffix() const;
327+
324328
bool GetShowDontUsePoHint() const;
325329

326330
bool GetUseSourceCache() const;

lldb/include/lldb/Symbol/Symbol.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,8 @@ class Symbol : public SymbolContextScope {
174174

175175
void SetFlags(uint32_t flags) { m_flags = flags; }
176176

177-
void GetDescription(Stream *s, lldb::DescriptionLevel level,
178-
Target *target) const;
177+
void GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target,
178+
llvm::StringRef pattern = "") const;
179179

180180
bool IsSynthetic() const { return m_is_synthetic; }
181181

lldb/include/lldb/Symbol/SymbolContext.h

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,19 @@ class SymbolContext {
145145
/// is dumped if this flag is \b true, otherwise the line info
146146
/// of the actual inlined function is dumped.
147147
///
148+
/// \param[in] pattern
149+
/// An optional regex pattern to match against the stop context
150+
/// description. If specified, parts of the description matching this
151+
/// pattern may be highlighted or processed differently. If this parameter
152+
/// is an empty string or not provided, no highlighting is applied.
153+
///
148154
/// \return
149155
/// \b true if some text was dumped, \b false otherwise.
150156
bool DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
151157
const Address &so_addr, bool show_fullpaths,
152158
bool show_module, bool show_inlined_frames,
153-
bool show_function_arguments,
154-
bool show_function_name) const;
159+
bool show_function_arguments, bool show_function_name,
160+
llvm::StringRef pattern = "") const;
155161

156162
/// Get the address range contained within a symbol context.
157163
///
@@ -217,8 +223,8 @@ class SymbolContext {
217223
/// The symbol that was found, or \b nullptr if none was found.
218224
const Symbol *FindBestGlobalDataSymbol(ConstString name, Status &error);
219225

220-
void GetDescription(Stream *s, lldb::DescriptionLevel level,
221-
Target *target) const;
226+
void GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target,
227+
llvm::StringRef pattern = "") const;
222228

223229
uint32_t GetResolvedMask() const;
224230

lldb/include/lldb/Utility/Stream.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,40 @@ class Stream {
231231
/// The string to be output to the stream.
232232
size_t PutCString(llvm::StringRef cstr);
233233

234+
/// Output a C string to the stream with color highlighting.
235+
///
236+
/// Print a C string \a text to the stream, applying color highlighting to
237+
/// the portions of the string that match the regex pattern \a pattern. The
238+
/// pattern is matched as many times as possible throughout the string. If \a
239+
/// pattern is nullptr, then no highlighting is applied.
240+
///
241+
/// The highlighting is applied by enclosing the matching text in ANSI color
242+
/// codes. The \a prefix parameter specifies the ANSI code to start the color
243+
/// (the standard value is assumed to be 'ansi.fg.red', representing red
244+
/// foreground), and the \a suffix parameter specifies the ANSI code to end
245+
/// the color (the standard value is assumed to be 'ansi.normal', resetting to
246+
/// default text style). These constants should be defined appropriately in
247+
/// your environment.
248+
///
249+
/// \param[in] text
250+
/// The string to be output to the stream.
251+
///
252+
/// \param[in] pattern
253+
/// The regex pattern to match against the \a text string. Portions of \a
254+
/// text matching this pattern will be colorized. If this parameter is
255+
/// nullptr, highlighting is not performed.
256+
/// \param[in] prefix
257+
/// The ANSI color code to start colorization. This is
258+
/// environment-dependent.
259+
/// \param[in] suffix
260+
/// The ANSI color code to end colorization. This is
261+
/// environment-dependent.
262+
263+
void PutCStringColorHighlighted(llvm::StringRef text,
264+
llvm::StringRef pattern = "",
265+
llvm::StringRef prefix = "",
266+
llvm::StringRef suffix = "");
267+
234268
/// Output and End of Line character to the stream.
235269
size_t EOL();
236270

lldb/source/Commands/CommandObjectTarget.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include "CommandObjectTarget.h"
1010

11+
#include "lldb/Core/Address.h"
1112
#include "lldb/Core/Debugger.h"
1213
#include "lldb/Core/IOHandler.h"
1314
#include "lldb/Core/Module.h"
@@ -1532,7 +1533,7 @@ static void DumpOsoFilesTable(Stream &strm,
15321533

15331534
static void DumpAddress(ExecutionContextScope *exe_scope,
15341535
const Address &so_addr, bool verbose, bool all_ranges,
1535-
Stream &strm) {
1536+
Stream &strm, llvm::StringRef pattern = "") {
15361537
strm.IndentMore();
15371538
strm.Indent(" Address: ");
15381539
so_addr.Dump(&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
@@ -1542,13 +1543,14 @@ static void DumpAddress(ExecutionContextScope *exe_scope,
15421543
strm.Indent(" Summary: ");
15431544
const uint32_t save_indent = strm.GetIndentLevel();
15441545
strm.SetIndentLevel(save_indent + 13);
1545-
so_addr.Dump(&strm, exe_scope, Address::DumpStyleResolvedDescription);
1546+
so_addr.Dump(&strm, exe_scope, Address::DumpStyleResolvedDescription,
1547+
Address::DumpStyleInvalid, UINT32_MAX, false, pattern);
15461548
strm.SetIndentLevel(save_indent);
15471549
// Print out detailed address information when verbose is enabled
15481550
if (verbose) {
15491551
strm.EOL();
15501552
so_addr.Dump(&strm, exe_scope, Address::DumpStyleDetailedSymbolContext,
1551-
Address::DumpStyleInvalid, UINT32_MAX, all_ranges);
1553+
Address::DumpStyleInvalid, UINT32_MAX, all_ranges, pattern);
15521554
}
15531555
strm.IndentLess();
15541556
}
@@ -1593,6 +1595,7 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
15931595
return 0;
15941596

15951597
SymbolContext sc;
1598+
const bool use_color = interpreter.GetDebugger().GetUseColor();
15961599
std::vector<uint32_t> match_indexes;
15971600
ConstString symbol_name(name);
15981601
uint32_t num_matches = 0;
@@ -1618,12 +1621,19 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
16181621
if (symbol->ValueIsAddress()) {
16191622
DumpAddress(
16201623
interpreter.GetExecutionContext().GetBestExecutionContextScope(),
1621-
symbol->GetAddressRef(), verbose, all_ranges, strm);
1624+
symbol->GetAddressRef(), verbose, all_ranges, strm,
1625+
use_color && name_is_regex ? name : nullptr);
16221626
strm.EOL();
16231627
} else {
16241628
strm.IndentMore();
16251629
strm.Indent(" Name: ");
1626-
strm.PutCString(symbol->GetDisplayName().GetStringRef());
1630+
llvm::StringRef ansi_prefix =
1631+
interpreter.GetDebugger().GetRegexMatchAnsiPrefix();
1632+
llvm::StringRef ansi_suffix =
1633+
interpreter.GetDebugger().GetRegexMatchAnsiSuffix();
1634+
strm.PutCStringColorHighlighted(
1635+
symbol->GetDisplayName().GetStringRef(),
1636+
use_color ? name : nullptr, ansi_prefix, ansi_suffix);
16271637
strm.EOL();
16281638
strm.Indent(" Value: ");
16291639
strm.Printf("0x%16.16" PRIx64 "\n", symbol->GetRawValue());

lldb/source/Core/Address.cpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "lldb/Core/Address.h"
10+
#include "lldb/Core/Debugger.h"
1011
#include "lldb/Core/Declaration.h"
1112
#include "lldb/Core/DumpDataExtractor.h"
1213
#include "lldb/Core/Module.h"
@@ -28,6 +29,7 @@
2829
#include "lldb/Target/Process.h"
2930
#include "lldb/Target/SectionLoadList.h"
3031
#include "lldb/Target/Target.h"
32+
#include "lldb/Utility/AnsiTerminal.h"
3133
#include "lldb/Utility/ConstString.h"
3234
#include "lldb/Utility/DataExtractor.h"
3335
#include "lldb/Utility/Endian.h"
@@ -405,7 +407,7 @@ bool Address::GetDescription(Stream &s, Target &target,
405407

406408
bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
407409
DumpStyle fallback_style, uint32_t addr_size,
408-
bool all_ranges) const {
410+
bool all_ranges, llvm::StringRef pattern) const {
409411
// If the section was nullptr, only load address is going to work unless we
410412
// are trying to deref a pointer
411413
SectionSP section_sp(GetSection());
@@ -501,7 +503,6 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
501503
pointer_size = target->GetArchitecture().GetAddressByteSize();
502504
else if (module_sp)
503505
pointer_size = module_sp->GetArchitecture().GetAddressByteSize();
504-
505506
bool showed_info = false;
506507
if (section_sp) {
507508
SectionType sect_type = section_sp->GetType();
@@ -515,7 +516,12 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
515516
if (symbol) {
516517
const char *symbol_name = symbol->GetName().AsCString();
517518
if (symbol_name) {
518-
s->PutCString(symbol_name);
519+
llvm::StringRef ansi_prefix =
520+
target->GetDebugger().GetRegexMatchAnsiPrefix();
521+
llvm::StringRef ansi_suffix =
522+
target->GetDebugger().GetRegexMatchAnsiSuffix();
523+
s->PutCStringColorHighlighted(symbol_name, pattern,
524+
ansi_prefix, ansi_suffix);
519525
addr_t delta =
520526
file_Addr - symbol->GetAddressRef().GetFileAddress();
521527
if (delta)
@@ -643,7 +649,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
643649
pointer_sc.symbol != nullptr) {
644650
s->PutCString(": ");
645651
pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false,
646-
false, true, true);
652+
false, true, true, pattern);
647653
}
648654
}
649655
}
@@ -682,19 +688,22 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
682688
// address.
683689
sc.DumpStopContext(s, exe_scope, *this, show_fullpaths,
684690
show_module, show_inlined_frames,
685-
show_function_arguments, show_function_name);
691+
show_function_arguments, show_function_name,
692+
pattern);
686693
} else {
687694
// We found a symbol but it was in a different section so it
688695
// isn't the symbol we should be showing, just show the section
689696
// name + offset
690-
Dump(s, exe_scope, DumpStyleSectionNameOffset);
697+
Dump(s, exe_scope, DumpStyleSectionNameOffset, DumpStyleInvalid,
698+
UINT32_MAX, false, pattern);
691699
}
692700
}
693701
}
694702
}
695703
} else {
696704
if (fallback_style != DumpStyleInvalid)
697-
return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
705+
return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size,
706+
false, pattern);
698707
return false;
699708
}
700709
break;
@@ -715,7 +724,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
715724
sc.symbol->GetAddressRef().GetSection() != GetSection())
716725
sc.symbol = nullptr;
717726
}
718-
sc.GetDescription(s, eDescriptionLevelBrief, target);
727+
sc.GetDescription(s, eDescriptionLevelBrief, target, pattern);
719728

720729
if (sc.block) {
721730
bool can_create = true;
@@ -763,7 +772,8 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
763772
}
764773
} else {
765774
if (fallback_style != DumpStyleInvalid)
766-
return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
775+
return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size,
776+
false, pattern);
767777
return false;
768778
}
769779
break;

lldb/source/Core/CoreProperties.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,14 @@ let Definition = "debugger" in {
203203
Global,
204204
DefaultStringValue<"${ansi.normal}">,
205205
Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">;
206+
def ShowRegexMatchAnsiPrefix: Property<"show-regex-match-ansi-prefix", "String">,
207+
Global,
208+
DefaultStringValue<"${ansi.fg.red}">,
209+
Desc<"When displaying a regex match in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the match.">;
210+
def ShowRegexMatchAnsiSuffix: Property<"show-regex-match-ansi-suffix", "String">,
211+
Global,
212+
DefaultStringValue<"${ansi.normal}">,
213+
Desc<"When displaying a regex match in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the match.">;
206214
def ShowDontUsePoHint: Property<"show-dont-use-po-hint", "Boolean">,
207215
Global,
208216
DefaultTrue,

lldb/source/Core/Debugger.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,18 @@ llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
453453
idx, g_debugger_properties[idx].default_cstr_value);
454454
}
455455

456+
llvm::StringRef Debugger::GetRegexMatchAnsiPrefix() const {
457+
const uint32_t idx = ePropertyShowRegexMatchAnsiPrefix;
458+
return GetPropertyAtIndexAs<llvm::StringRef>(
459+
idx, g_debugger_properties[idx].default_cstr_value);
460+
}
461+
462+
llvm::StringRef Debugger::GetRegexMatchAnsiSuffix() const {
463+
const uint32_t idx = ePropertyShowRegexMatchAnsiSuffix;
464+
return GetPropertyAtIndexAs<llvm::StringRef>(
465+
idx, g_debugger_properties[idx].default_cstr_value);
466+
}
467+
456468
bool Debugger::GetShowDontUsePoHint() const {
457469
const uint32_t idx = ePropertyShowDontUsePoHint;
458470
return GetPropertyAtIndexAs<bool>(

lldb/source/Symbol/Symbol.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
#include "lldb/Symbol/Symbol.h"
1010

11+
#include "lldb/Core/Address.h"
12+
#include "lldb/Core/Debugger.h"
1113
#include "lldb/Core/Module.h"
1214
#include "lldb/Core/ModuleSpec.h"
1315
#include "lldb/Core/Section.h"
@@ -225,7 +227,7 @@ bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }
225227
bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }
226228

227229
void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level,
228-
Target *target) const {
230+
Target *target, llvm::StringRef pattern) const {
229231
s->Printf("id = {0x%8.8x}", m_uid);
230232

231233
if (m_addr_range.GetBaseAddress().GetSection()) {
@@ -252,11 +254,20 @@ void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level,
252254
s->Printf(", value = 0x%16.16" PRIx64,
253255
m_addr_range.GetBaseAddress().GetOffset());
254256
}
255-
ConstString demangled = GetMangled().GetDemangledName();
256-
if (demangled)
257-
s->Printf(", name=\"%s\"", demangled.AsCString());
258-
if (m_mangled.GetMangledName())
259-
s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString());
257+
llvm::StringRef ansi_prefix = target->GetDebugger().GetRegexMatchAnsiPrefix();
258+
llvm::StringRef ansi_suffix = target->GetDebugger().GetRegexMatchAnsiSuffix();
259+
if (ConstString demangled = m_mangled.GetDemangledName()) {
260+
s->PutCString(", name=\"");
261+
s->PutCStringColorHighlighted(demangled.GetStringRef(), pattern,
262+
ansi_prefix, ansi_suffix);
263+
s->PutCString("\"");
264+
}
265+
if (ConstString mangled_name = m_mangled.GetMangledName()) {
266+
s->PutCString(", mangled=\"");
267+
s->PutCStringColorHighlighted(mangled_name.GetStringRef(), pattern,
268+
ansi_prefix, ansi_suffix);
269+
s->PutCString("\"");
270+
}
260271
}
261272

262273
void Symbol::Dump(Stream *s, Target *target, uint32_t index,

0 commit comments

Comments
 (0)