[Lldb-commits] [lldb] c90cb6e - [lldb] colorize symbols in image lookup with a regex pattern (#69422)

via lldb-commits lldb-commits at lists.llvm.org
Fri Dec 8 03:09:09 PST 2023


Author: taalhaataahir0102
Date: 2023-12-08T11:09:04Z
New Revision: c90cb6eee8296953c097fcc9fc6e61f739c0dad3

URL: https://github.com/llvm/llvm-project/commit/c90cb6eee8296953c097fcc9fc6e61f739c0dad3
DIFF: https://github.com/llvm/llvm-project/commit/c90cb6eee8296953c097fcc9fc6e61f739c0dad3.diff

LOG: [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 at 10xengineers.ai>

Added: 
    lldb/test/Shell/Commands/command-image-lookup-color.test

Modified: 
    lldb/include/lldb/Core/Address.h
    lldb/include/lldb/Core/Debugger.h
    lldb/include/lldb/Symbol/Symbol.h
    lldb/include/lldb/Symbol/SymbolContext.h
    lldb/include/lldb/Utility/Stream.h
    lldb/source/Commands/CommandObjectTarget.cpp
    lldb/source/Core/Address.cpp
    lldb/source/Core/CoreProperties.td
    lldb/source/Core/Debugger.cpp
    lldb/source/Symbol/Symbol.cpp
    lldb/source/Symbol/SymbolContext.cpp
    lldb/source/Utility/Stream.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Core/Address.h b/lldb/include/lldb/Core/Address.h
index b19e694427546f..725b5d9f91d3d5 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 @@ class Address {
   ///     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 
diff erently. 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 @@ class Address {
   /// \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 e4ee94809cf1a0..c6d603ca5dcde0 100644
--- a/lldb/include/lldb/Core/Debugger.h
+++ b/lldb/include/lldb/Core/Debugger.h
@@ -321,6 +321,10 @@ class Debugger : public std::enable_shared_from_this<Debugger>,
 
   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 44a2d560010fe4..e6c0b495bcf28c 100644
--- a/lldb/include/lldb/Symbol/Symbol.h
+++ b/lldb/include/lldb/Symbol/Symbol.h
@@ -174,8 +174,8 @@ class Symbol : public SymbolContextScope {
 
   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 b0f5ffead2a165..26f3bac09a9626 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -145,13 +145,19 @@ class SymbolContext {
   ///     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 
diff erently. 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 @@ class SymbolContext {
   ///     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 1a5fd343e4df0d..20c55ac4597ae6 100644
--- a/lldb/include/lldb/Utility/Stream.h
+++ b/lldb/include/lldb/Utility/Stream.h
@@ -231,6 +231,40 @@ class Stream {
   ///     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 58785cde3ec7c6..63232c221ad1db 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 189d50fe962a65..d86fb1520a896b 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 
diff erent 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 0e0f468d3ecd76..8d81967bdb50a4 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 398265dca1cb71..97311b4716ac2f 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 26b4c4d62ad9c2..0d20d11b8c4ffe 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 63968ec2d15067..9fd40b5ca567f8 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 af28a49a1f0c2b..62e061e9d09c07 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 00000000000000..5082f891132817
--- /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


        


More information about the lldb-commits mailing list