aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortaalhaataahir0102 <77788288+taalhaataahir0102@users.noreply.github.com>2023-12-08 16:09:04 +0500
committerGitHub <noreply@github.com>2023-12-08 11:09:04 +0000
commitc90cb6eee8296953c097fcc9fc6e61f739c0dad3 (patch)
tree8a710839b64e2a6d830b5fcbb025760be6650534
parentfaecc736e2ac3cd8c77bebf41b1ed2e2d8cb575f (diff)
downloadllvm-c90cb6eee8296953c097fcc9fc6e61f739c0dad3.zip
llvm-c90cb6eee8296953c097fcc9fc6e61f739c0dad3.tar.gz
llvm-c90cb6eee8296953c097fcc9fc6e61f739c0dad3.tar.bz2
[lldb] colorize symbols in image lookup with a regex pattern (#69422)
Fixes https://github.com/llvm/llvm-project/issues/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 <josejunior@10xengineers.ai>
-rw-r--r--lldb/include/lldb/Core/Address.h12
-rw-r--r--lldb/include/lldb/Core/Debugger.h4
-rw-r--r--lldb/include/lldb/Symbol/Symbol.h4
-rw-r--r--lldb/include/lldb/Symbol/SymbolContext.h14
-rw-r--r--lldb/include/lldb/Utility/Stream.h34
-rw-r--r--lldb/source/Commands/CommandObjectTarget.cpp20
-rw-r--r--lldb/source/Core/Address.cpp28
-rw-r--r--lldb/source/Core/CoreProperties.td8
-rw-r--r--lldb/source/Core/Debugger.cpp12
-rw-r--r--lldb/source/Symbol/Symbol.cpp23
-rw-r--r--lldb/source/Symbol/SymbolContext.cpp31
-rw-r--r--lldb/source/Utility/Stream.cpp30
-rw-r--r--lldb/test/Shell/Commands/command-image-lookup-color.test54
13 files changed, 239 insertions, 35 deletions
diff --git a/lldb/include/lldb/Core/Address.h b/lldb/include/lldb/Core/Address.h
index b19e694..725b5d9 100644
--- a/lldb/include/lldb/Core/Address.h
+++ b/lldb/include/lldb/Core/Address.h
@@ -14,6 +14,8 @@
#include "lldb/lldb-private-enumerations.h"
#include "lldb/lldb-types.h"
+#include "llvm/ADT/StringRef.h"
+
#include <cstddef>
#include <cstdint>
@@ -237,6 +239,12 @@ public:
/// contains the address, otherwise dumping the range that contains the
/// address.
///
+ /// \param[in] pattern
+ /// An optional regex pattern to match against the description. If
+ /// specified, parts of the description matching this pattern may be
+ /// highlighted or processed differently. If this parameter is an empty
+ /// string or not provided, no highlighting is applied.
+ ///
/// \return
/// Returns \b true if the address was able to be displayed.
/// File and load addresses may be unresolved and it may not be
@@ -246,8 +254,8 @@ public:
/// \see Address::DumpStyle
bool Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
DumpStyle fallback_style = DumpStyleInvalid,
- uint32_t addr_byte_size = UINT32_MAX,
- bool all_ranges = false) const;
+ uint32_t addr_byte_size = UINT32_MAX, bool all_ranges = false,
+ llvm::StringRef pattern = "") const;
AddressClass GetAddressClass() const;
diff --git a/lldb/include/lldb/Core/Debugger.h b/lldb/include/lldb/Core/Debugger.h
index e4ee948..c6d603c 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -321,6 +321,10 @@ public:
llvm::StringRef GetAutosuggestionAnsiSuffix() const;
+ llvm::StringRef GetRegexMatchAnsiPrefix() const;
+
+ llvm::StringRef GetRegexMatchAnsiSuffix() const;
+
bool GetShowDontUsePoHint() const;
bool GetUseSourceCache() const;
diff --git a/lldb/include/lldb/Symbol/Symbol.h b/lldb/include/lldb/Symbol/Symbol.h
index 44a2d56..e6c0b49 100644
--- a/lldb/include/lldb/Symbol/Symbol.h
+++ b/lldb/include/lldb/Symbol/Symbol.h
@@ -174,8 +174,8 @@ public:
void SetFlags(uint32_t flags) { m_flags = flags; }
- void GetDescription(Stream *s, lldb::DescriptionLevel level,
- Target *target) const;
+ void GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target,
+ llvm::StringRef pattern = "") const;
bool IsSynthetic() const { return m_is_synthetic; }
diff --git a/lldb/include/lldb/Symbol/SymbolContext.h b/lldb/include/lldb/Symbol/SymbolContext.h
index b0f5ffe..26f3bac 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -145,13 +145,19 @@ public:
/// is dumped if this flag is \b true, otherwise the line info
/// of the actual inlined function is dumped.
///
+ /// \param[in] pattern
+ /// An optional regex pattern to match against the stop context
+ /// description. If specified, parts of the description matching this
+ /// pattern may be highlighted or processed differently. If this parameter
+ /// is an empty string or not provided, no highlighting is applied.
+ ///
/// \return
/// \b true if some text was dumped, \b false otherwise.
bool DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
const Address &so_addr, bool show_fullpaths,
bool show_module, bool show_inlined_frames,
- bool show_function_arguments,
- bool show_function_name) const;
+ bool show_function_arguments, bool show_function_name,
+ llvm::StringRef pattern = "") const;
/// Get the address range contained within a symbol context.
///
@@ -217,8 +223,8 @@ public:
/// The symbol that was found, or \b nullptr if none was found.
const Symbol *FindBestGlobalDataSymbol(ConstString name, Status &error);
- void GetDescription(Stream *s, lldb::DescriptionLevel level,
- Target *target) const;
+ void GetDescription(Stream *s, lldb::DescriptionLevel level, Target *target,
+ llvm::StringRef pattern = "") const;
uint32_t GetResolvedMask() const;
diff --git a/lldb/include/lldb/Utility/Stream.h b/lldb/include/lldb/Utility/Stream.h
index 1a5fd34..20c55ac 100644
--- a/lldb/include/lldb/Utility/Stream.h
+++ b/lldb/include/lldb/Utility/Stream.h
@@ -231,6 +231,40 @@ public:
/// The string to be output to the stream.
size_t PutCString(llvm::StringRef cstr);
+ /// Output a C string to the stream with color highlighting.
+ ///
+ /// Print a C string \a text to the stream, applying color highlighting to
+ /// the portions of the string that match the regex pattern \a pattern. The
+ /// pattern is matched as many times as possible throughout the string. If \a
+ /// pattern is nullptr, then no highlighting is applied.
+ ///
+ /// The highlighting is applied by enclosing the matching text in ANSI color
+ /// codes. The \a prefix parameter specifies the ANSI code to start the color
+ /// (the standard value is assumed to be 'ansi.fg.red', representing red
+ /// foreground), and the \a suffix parameter specifies the ANSI code to end
+ /// the color (the standard value is assumed to be 'ansi.normal', resetting to
+ /// default text style). These constants should be defined appropriately in
+ /// your environment.
+ ///
+ /// \param[in] text
+ /// The string to be output to the stream.
+ ///
+ /// \param[in] pattern
+ /// The regex pattern to match against the \a text string. Portions of \a
+ /// text matching this pattern will be colorized. If this parameter is
+ /// nullptr, highlighting is not performed.
+ /// \param[in] prefix
+ /// The ANSI color code to start colorization. This is
+ /// environment-dependent.
+ /// \param[in] suffix
+ /// The ANSI color code to end colorization. This is
+ /// environment-dependent.
+
+ void PutCStringColorHighlighted(llvm::StringRef text,
+ llvm::StringRef pattern = "",
+ llvm::StringRef prefix = "",
+ llvm::StringRef suffix = "");
+
/// Output and End of Line character to the stream.
size_t EOL();
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 58785cd..63232c2 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -8,6 +8,7 @@
#include "CommandObjectTarget.h"
+#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/IOHandler.h"
#include "lldb/Core/Module.h"
@@ -1532,7 +1533,7 @@ static void DumpOsoFilesTable(Stream &strm,
static void DumpAddress(ExecutionContextScope *exe_scope,
const Address &so_addr, bool verbose, bool all_ranges,
- Stream &strm) {
+ Stream &strm, llvm::StringRef pattern = "") {
strm.IndentMore();
strm.Indent(" Address: ");
so_addr.Dump(&strm, exe_scope, Address::DumpStyleModuleWithFileAddress);
@@ -1542,13 +1543,14 @@ static void DumpAddress(ExecutionContextScope *exe_scope,
strm.Indent(" Summary: ");
const uint32_t save_indent = strm.GetIndentLevel();
strm.SetIndentLevel(save_indent + 13);
- so_addr.Dump(&strm, exe_scope, Address::DumpStyleResolvedDescription);
+ so_addr.Dump(&strm, exe_scope, Address::DumpStyleResolvedDescription,
+ Address::DumpStyleInvalid, UINT32_MAX, false, pattern);
strm.SetIndentLevel(save_indent);
// Print out detailed address information when verbose is enabled
if (verbose) {
strm.EOL();
so_addr.Dump(&strm, exe_scope, Address::DumpStyleDetailedSymbolContext,
- Address::DumpStyleInvalid, UINT32_MAX, all_ranges);
+ Address::DumpStyleInvalid, UINT32_MAX, all_ranges, pattern);
}
strm.IndentLess();
}
@@ -1593,6 +1595,7 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
return 0;
SymbolContext sc;
+ const bool use_color = interpreter.GetDebugger().GetUseColor();
std::vector<uint32_t> match_indexes;
ConstString symbol_name(name);
uint32_t num_matches = 0;
@@ -1618,12 +1621,19 @@ static uint32_t LookupSymbolInModule(CommandInterpreter &interpreter,
if (symbol->ValueIsAddress()) {
DumpAddress(
interpreter.GetExecutionContext().GetBestExecutionContextScope(),
- symbol->GetAddressRef(), verbose, all_ranges, strm);
+ symbol->GetAddressRef(), verbose, all_ranges, strm,
+ use_color && name_is_regex ? name : nullptr);
strm.EOL();
} else {
strm.IndentMore();
strm.Indent(" Name: ");
- strm.PutCString(symbol->GetDisplayName().GetStringRef());
+ llvm::StringRef ansi_prefix =
+ interpreter.GetDebugger().GetRegexMatchAnsiPrefix();
+ llvm::StringRef ansi_suffix =
+ interpreter.GetDebugger().GetRegexMatchAnsiSuffix();
+ strm.PutCStringColorHighlighted(
+ symbol->GetDisplayName().GetStringRef(),
+ use_color ? name : nullptr, ansi_prefix, ansi_suffix);
strm.EOL();
strm.Indent(" Value: ");
strm.Printf("0x%16.16" PRIx64 "\n", symbol->GetRawValue());
diff --git a/lldb/source/Core/Address.cpp b/lldb/source/Core/Address.cpp
index 189d50f..d86fb15 100644
--- a/lldb/source/Core/Address.cpp
+++ b/lldb/source/Core/Address.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "lldb/Core/Address.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Declaration.h"
#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/Core/Module.h"
@@ -28,6 +29,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/Target.h"
+#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/ConstString.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/Endian.h"
@@ -405,7 +407,7 @@ bool Address::GetDescription(Stream &s, Target &target,
bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
DumpStyle fallback_style, uint32_t addr_size,
- bool all_ranges) const {
+ bool all_ranges, llvm::StringRef pattern) const {
// If the section was nullptr, only load address is going to work unless we
// are trying to deref a pointer
SectionSP section_sp(GetSection());
@@ -501,7 +503,6 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
pointer_size = target->GetArchitecture().GetAddressByteSize();
else if (module_sp)
pointer_size = module_sp->GetArchitecture().GetAddressByteSize();
-
bool showed_info = false;
if (section_sp) {
SectionType sect_type = section_sp->GetType();
@@ -515,7 +516,12 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
if (symbol) {
const char *symbol_name = symbol->GetName().AsCString();
if (symbol_name) {
- s->PutCString(symbol_name);
+ llvm::StringRef ansi_prefix =
+ target->GetDebugger().GetRegexMatchAnsiPrefix();
+ llvm::StringRef ansi_suffix =
+ target->GetDebugger().GetRegexMatchAnsiSuffix();
+ s->PutCStringColorHighlighted(symbol_name, pattern,
+ ansi_prefix, ansi_suffix);
addr_t delta =
file_Addr - symbol->GetAddressRef().GetFileAddress();
if (delta)
@@ -643,7 +649,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
pointer_sc.symbol != nullptr) {
s->PutCString(": ");
pointer_sc.DumpStopContext(s, exe_scope, so_addr, true, false,
- false, true, true);
+ false, true, true, pattern);
}
}
}
@@ -682,19 +688,22 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
// address.
sc.DumpStopContext(s, exe_scope, *this, show_fullpaths,
show_module, show_inlined_frames,
- show_function_arguments, show_function_name);
+ show_function_arguments, show_function_name,
+ pattern);
} else {
// We found a symbol but it was in a different section so it
// isn't the symbol we should be showing, just show the section
// name + offset
- Dump(s, exe_scope, DumpStyleSectionNameOffset);
+ Dump(s, exe_scope, DumpStyleSectionNameOffset, DumpStyleInvalid,
+ UINT32_MAX, false, pattern);
}
}
}
}
} else {
if (fallback_style != DumpStyleInvalid)
- return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size,
+ false, pattern);
return false;
}
break;
@@ -715,7 +724,7 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
sc.symbol->GetAddressRef().GetSection() != GetSection())
sc.symbol = nullptr;
}
- sc.GetDescription(s, eDescriptionLevelBrief, target);
+ sc.GetDescription(s, eDescriptionLevelBrief, target, pattern);
if (sc.block) {
bool can_create = true;
@@ -763,7 +772,8 @@ bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style,
}
} else {
if (fallback_style != DumpStyleInvalid)
- return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size);
+ return Dump(s, exe_scope, fallback_style, DumpStyleInvalid, addr_size,
+ false, pattern);
return false;
}
break;
diff --git a/lldb/source/Core/CoreProperties.td b/lldb/source/Core/CoreProperties.td
index 0e0f468..8d81967 100644
--- a/lldb/source/Core/CoreProperties.td
+++ b/lldb/source/Core/CoreProperties.td
@@ -203,6 +203,14 @@ let Definition = "debugger" in {
Global,
DefaultStringValue<"${ansi.normal}">,
Desc<"When displaying suggestion in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the suggestion.">;
+ def ShowRegexMatchAnsiPrefix: Property<"show-regex-match-ansi-prefix", "String">,
+ Global,
+ DefaultStringValue<"${ansi.fg.red}">,
+ Desc<"When displaying a regex match in a color-enabled terminal, use the ANSI terminal code specified in this format immediately before the match.">;
+ def ShowRegexMatchAnsiSuffix: Property<"show-regex-match-ansi-suffix", "String">,
+ Global,
+ DefaultStringValue<"${ansi.normal}">,
+ Desc<"When displaying a regex match in a color-enabled terminal, use the ANSI terminal code specified in this format immediately after the match.">;
def ShowDontUsePoHint: Property<"show-dont-use-po-hint", "Boolean">,
Global,
DefaultTrue,
diff --git a/lldb/source/Core/Debugger.cpp b/lldb/source/Core/Debugger.cpp
index 398265d..97311b4 100644
--- a/lldb/source/Core/Debugger.cpp
+++ b/lldb/source/Core/Debugger.cpp
@@ -453,6 +453,18 @@ llvm::StringRef Debugger::GetAutosuggestionAnsiSuffix() const {
idx, g_debugger_properties[idx].default_cstr_value);
}
+llvm::StringRef Debugger::GetRegexMatchAnsiPrefix() const {
+ const uint32_t idx = ePropertyShowRegexMatchAnsiPrefix;
+ return GetPropertyAtIndexAs<llvm::StringRef>(
+ idx, g_debugger_properties[idx].default_cstr_value);
+}
+
+llvm::StringRef Debugger::GetRegexMatchAnsiSuffix() const {
+ const uint32_t idx = ePropertyShowRegexMatchAnsiSuffix;
+ return GetPropertyAtIndexAs<llvm::StringRef>(
+ idx, g_debugger_properties[idx].default_cstr_value);
+}
+
bool Debugger::GetShowDontUsePoHint() const {
const uint32_t idx = ePropertyShowDontUsePoHint;
return GetPropertyAtIndexAs<bool>(
diff --git a/lldb/source/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index 26b4c4d..0d20d11 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -8,6 +8,8 @@
#include "lldb/Symbol/Symbol.h"
+#include "lldb/Core/Address.h"
+#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/Section.h"
@@ -225,7 +227,7 @@ bool Symbol::IsTrampoline() const { return m_type == eSymbolTypeTrampoline; }
bool Symbol::IsIndirect() const { return m_type == eSymbolTypeResolver; }
void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level,
- Target *target) const {
+ Target *target, llvm::StringRef pattern) const {
s->Printf("id = {0x%8.8x}", m_uid);
if (m_addr_range.GetBaseAddress().GetSection()) {
@@ -252,11 +254,20 @@ void Symbol::GetDescription(Stream *s, lldb::DescriptionLevel level,
s->Printf(", value = 0x%16.16" PRIx64,
m_addr_range.GetBaseAddress().GetOffset());
}
- ConstString demangled = GetMangled().GetDemangledName();
- if (demangled)
- s->Printf(", name=\"%s\"", demangled.AsCString());
- if (m_mangled.GetMangledName())
- s->Printf(", mangled=\"%s\"", m_mangled.GetMangledName().AsCString());
+ llvm::StringRef ansi_prefix = target->GetDebugger().GetRegexMatchAnsiPrefix();
+ llvm::StringRef ansi_suffix = target->GetDebugger().GetRegexMatchAnsiSuffix();
+ if (ConstString demangled = m_mangled.GetDemangledName()) {
+ s->PutCString(", name=\"");
+ s->PutCStringColorHighlighted(demangled.GetStringRef(), pattern,
+ ansi_prefix, ansi_suffix);
+ s->PutCString("\"");
+ }
+ if (ConstString mangled_name = m_mangled.GetMangledName()) {
+ s->PutCString(", mangled=\"");
+ s->PutCStringColorHighlighted(mangled_name.GetStringRef(), pattern,
+ ansi_prefix, ansi_suffix);
+ s->PutCString("\"");
+ }
}
void Symbol::Dump(Stream *s, Target *target, uint32_t index,
diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp
index 63968ec..9fd40b5 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -8,6 +8,7 @@
#include "lldb/Symbol/SymbolContext.h"
+#include "lldb/Core/Address.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ModuleSpec.h"
@@ -71,7 +72,8 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
const Address &addr, bool show_fullpaths,
bool show_module, bool show_inlined_frames,
bool show_function_arguments,
- bool show_function_name) const {
+ bool show_function_name,
+ llvm::StringRef pattern) const {
bool dumped_something = false;
if (show_module && module_sp) {
if (show_fullpaths)
@@ -81,7 +83,6 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
s->PutChar('`');
dumped_something = true;
}
-
if (function != nullptr) {
SymbolContext inline_parent_sc;
Address inline_parent_addr;
@@ -94,8 +95,16 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
name = function->GetNameNoArguments();
if (!name)
name = function->GetName();
- if (name)
- name.Dump(s);
+ if (name) {
+ llvm::StringRef ansi_prefix;
+ llvm::StringRef ansi_suffix;
+ if (target_sp) {
+ ansi_prefix = target_sp->GetDebugger().GetRegexMatchAnsiPrefix();
+ ansi_suffix = target_sp->GetDebugger().GetRegexMatchAnsiSuffix();
+ }
+ s->PutCStringColorHighlighted(name.GetStringRef(), pattern, ansi_prefix,
+ ansi_suffix);
+ }
}
if (addr.IsValid()) {
@@ -163,7 +172,14 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
dumped_something = true;
if (symbol->GetType() == eSymbolTypeTrampoline)
s->PutCString("symbol stub for: ");
- symbol->GetName().Dump(s);
+ llvm::StringRef ansi_prefix;
+ llvm::StringRef ansi_suffix;
+ if (target_sp) {
+ ansi_prefix = target_sp->GetDebugger().GetRegexMatchAnsiPrefix();
+ ansi_suffix = target_sp->GetDebugger().GetRegexMatchAnsiSuffix();
+ }
+ s->PutCStringColorHighlighted(symbol->GetName().GetStringRef(), pattern,
+ ansi_prefix, ansi_suffix);
}
if (addr.IsValid() && symbol->ValueIsAddress()) {
@@ -186,7 +202,8 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
}
void SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level,
- Target *target) const {
+ Target *target,
+ llvm::StringRef pattern) const {
if (module_sp) {
s->Indent(" Module: file = \"");
module_sp->GetFileSpec().Dump(s->AsRawOstream());
@@ -246,7 +263,7 @@ void SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level,
if (symbol != nullptr) {
s->Indent(" Symbol: ");
- symbol->GetDescription(s, level, target);
+ symbol->GetDescription(s, level, target, pattern);
s->EOL();
}
diff --git a/lldb/source/Utility/Stream.cpp b/lldb/source/Utility/Stream.cpp
index af28a49..62e061e 100644
--- a/lldb/source/Utility/Stream.cpp
+++ b/lldb/source/Utility/Stream.cpp
@@ -8,11 +8,13 @@
#include "lldb/Utility/Stream.h"
+#include "lldb/Utility/AnsiTerminal.h"
#include "lldb/Utility/Endian.h"
#include "lldb/Utility/VASPrintf.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Format.h"
#include "llvm/Support/LEB128.h"
+#include "llvm/Support/Regex.h"
#include <string>
@@ -70,6 +72,34 @@ size_t Stream::PutCString(llvm::StringRef str) {
return bytes_written;
}
+void Stream::PutCStringColorHighlighted(llvm::StringRef text,
+ llvm::StringRef pattern,
+ llvm::StringRef prefix,
+ llvm::StringRef suffix) {
+ // Only apply color formatting when a pattern is present and both prefix and
+ // suffix are specified. In the absence of these conditions, output the text
+ // without color formatting.
+ if (pattern.empty() || (prefix.empty() && suffix.empty())) {
+ PutCString(text);
+ return;
+ }
+
+ llvm::Regex reg_pattern(pattern);
+ llvm::SmallVector<llvm::StringRef, 1> matches;
+ llvm::StringRef remaining = text;
+ std::string format_str = lldb_private::ansi::FormatAnsiTerminalCodes(
+ prefix.str() + "%.*s" + suffix.str());
+ while (reg_pattern.match(remaining, &matches)) {
+ llvm::StringRef match = matches[0];
+ size_t match_start_pos = match.data() - remaining.data();
+ PutCString(remaining.take_front(match_start_pos));
+ Printf(format_str.c_str(), match.size(), match.data());
+ remaining = remaining.drop_front(match_start_pos + match.size());
+ }
+ if (remaining.size())
+ PutCString(remaining);
+}
+
// Print a double quoted NULL terminated C string to the stream using the
// printf format in "format".
void Stream::QuotedCString(const char *cstr, const char *format) {
diff --git a/lldb/test/Shell/Commands/command-image-lookup-color.test b/lldb/test/Shell/Commands/command-image-lookup-color.test
new file mode 100644
index 0000000..5082f89
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-image-lookup-color.test
@@ -0,0 +1,54 @@
+# RUN: %clang_host -g %S/Inputs/main.c -o %t
+
+# Checking simple regex search
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -r -s ma' | FileCheck %s --check-prefix CHECK1
+# CHECK1: Name: {{.+}}31mma{{.+}}0min.c
+
+# Checking complex regex searches
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -r -s main.c|foo' | FileCheck %s --check-prefix CHECK2
+# CHECK2: Name: {{.+}}31mmain.c{{.+}}0m
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -r -s m[abc]' | FileCheck %s --check-prefix CHECK3
+# CHECK3: Name: {{.+}}31mma{{.+}}0min.c
+
+# Checking to ensure that no attempt is made to color anything when there are no matching symbols found
+
+# RUN: %lldb %t -o 'settings set use-color true' -o 'image lookup -r -s IMPPATTERN123456' | FileCheck %s --check-prefix CHECK4
+# CHECK4-NOT: {{[0-9]+}} symbols match the regular expression
+
+# Checking multiple matches on same symbol
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -r -s (ma|n)' | FileCheck %s --check-prefix CHECK5
+# CHECK5: Name: {{.+}}31mma{{.+}}0mi{{.+}}31mn{{.+}}0m.c
+
+# Checking no colorization without regex search
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -s main' | FileCheck %s --check-prefix CHECK6
+# CHECK6: Summary: {{.+}}`main at main.c:2
+
+# Checking no colorization when use-color is false
+
+# RUN: %lldb %t -b -o 'settings set use-color false' -o 'image lookup -r -s ma' | FileCheck %s --check-prefix CHECK7
+# CHECK7: Name: main.c
+
+# Checking for custom colors
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'settings set show-regex-match-ansi-prefix ${ansi.fg.green}' -o 'image lookup -r -s ma' | FileCheck %s --check-prefix CHECK8
+# CHECK8: Name: {{.+}}32mma{{.+}}0min.c
+
+# Checking for functionality when there's prefix but no suffix
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'settings set show-regex-match-ansi-prefix ${ansi.fg.red}' -o 'settings set show-regex-match-ansi-suffix ""' -o 'image lookup -r -s ma' | FileCheck %s --check-prefix CHECK9
+# CHECK9: Name: {{.+}}31mmain.c
+
+# Checking for functionality when there's suffix but no prefix
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'settings set show-regex-match-ansi-prefix ""' -o 'settings set show-regex-match-ansi-suffix ${ansi.fg.red}' -o 'image lookup -r -s ma' | FileCheck %s --check-prefix CHECK10
+# CHECK10: Name: ma{{.+}}31min.c
+
+# Checking for no colorization when there's neither suffix nor prefix
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'settings set show-regex-match-ansi-prefix ""' -o 'settings set show-regex-match-ansi-suffix ""' -o 'image lookup -r -s ma' | FileCheck %s --check-prefix CHECK11
+# CHECK11: Name: main.c