[Lldb-commits] [lldb] [lldb] colorize symbols in image lookup (PR #69422)

José Lira Junior via lldb-commits lldb-commits at lists.llvm.org
Mon Nov 27 09:57:52 PST 2023


https://github.com/junior-jl updated https://github.com/llvm/llvm-project/pull/69422

>From c416443a93f7113a7f57d337682ec4862438522d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20L=2E=20Junior?= <josejunior at 10xengineers.ai>
Date: Tue, 7 Nov 2023 16:57:18 -0300
Subject: [PATCH 1/2] [lldb] colorize symbols in image lookup

This creates the method PutCStringColorHighlighted for Stream class,
which highlights searched symbols in red color for the image lookup command.

A new shell test was added to verify functionality. Relevant methods were
updated to accept the searched pattern/symbol as a parameter.

Co-authored-by: Talha <talha.tahir at 10xengineers.ai>
---
 lldb/include/lldb/Core/Address.h              |  4 +-
 lldb/include/lldb/Symbol/Symbol.h             |  4 +-
 lldb/include/lldb/Symbol/SymbolContext.h      |  8 ++--
 lldb/include/lldb/Utility/Stream.h            | 16 ++++++++
 lldb/source/Commands/CommandObjectTarget.cpp  | 16 +++++---
 lldb/source/Core/Address.cpp                  | 21 ++++++----
 lldb/source/Symbol/Symbol.cpp                 | 18 ++++++---
 lldb/source/Symbol/SymbolContext.cpp          | 16 +++++---
 lldb/source/Utility/Stream.cpp                | 28 +++++++++++++
 .../Commands/command-image-lookup-color.test  | 39 +++++++++++++++++++
 10 files changed, 138 insertions(+), 32 deletions(-)
 create mode 100644 lldb/test/Shell/Commands/command-image-lookup-color.test

diff --git a/lldb/include/lldb/Core/Address.h b/lldb/include/lldb/Core/Address.h
index b19e694427546f8b..c3f2832be424efd8 100644
--- a/lldb/include/lldb/Core/Address.h
+++ b/lldb/include/lldb/Core/Address.h
@@ -246,8 +246,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,
+            const char *pattern = nullptr) const;
 
   AddressClass GetAddressClass() const;
 
diff --git a/lldb/include/lldb/Symbol/Symbol.h b/lldb/include/lldb/Symbol/Symbol.h
index 44a2d560010fe403..0e41cd95e0ef17d2 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,
+                      const char *pattern = nullptr) 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 b0f5ffead2a16569..9567c3f4384c1752 100644
--- a/lldb/include/lldb/Symbol/SymbolContext.h
+++ b/lldb/include/lldb/Symbol/SymbolContext.h
@@ -150,8 +150,8 @@ class SymbolContext {
   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,
+                       const char *pattern = nullptr) const;
 
   /// Get the address range contained within a symbol context.
   ///
@@ -217,8 +217,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,
+                      const char *pattern = nullptr) const;
 
   uint32_t GetResolvedMask() const;
 
diff --git a/lldb/include/lldb/Utility/Stream.h b/lldb/include/lldb/Utility/Stream.h
index 1a5fd343e4df0dc9..8e3fd48dfe705799 100644
--- a/lldb/include/lldb/Utility/Stream.h
+++ b/lldb/include/lldb/Utility/Stream.h
@@ -231,6 +231,22 @@ 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 red 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.
+  ///
+  /// \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.
+  void PutCStringColorHighlighted(llvm::StringRef text, const char *pattern);
+
   /// 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 58785cde3ec7c63c..991194972e02442b 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, const char *pattern = nullptr) {
   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;
+  bool use_color = interpreter.GetDebugger().GetUseColor();
   std::vector<uint32_t> match_indexes;
   ConstString symbol_name(name);
   uint32_t num_matches = 0;
@@ -1618,12 +1621,15 @@ 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 : nullptr);
           strm.EOL();
         } else {
           strm.IndentMore();
           strm.Indent("    Name: ");
-          strm.PutCString(symbol->GetDisplayName().GetStringRef());
+          strm.PutCStringColorHighlighted(
+              symbol->GetDisplayName().GetStringRef(),
+              use_color ? name : nullptr);
           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 189d50fe962a651c..4a05a744e02300f4 100644
--- a/lldb/source/Core/Address.cpp
+++ b/lldb/source/Core/Address.cpp
@@ -28,6 +28,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 +406,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, const char *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());
@@ -515,7 +516,7 @@ 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);
+                  s->PutCStringColorHighlighted(symbol_name, pattern);
                   addr_t delta =
                       file_Addr - symbol->GetAddressRef().GetFileAddress();
                   if (delta)
@@ -643,7 +644,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 +683,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 +719,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 +767,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/Symbol/Symbol.cpp b/lldb/source/Symbol/Symbol.cpp
index 26b4c4d62ad9c246..af47dc51d9ee9cd5 100644
--- a/lldb/source/Symbol/Symbol.cpp
+++ b/lldb/source/Symbol/Symbol.cpp
@@ -8,6 +8,7 @@
 
 #include "lldb/Symbol/Symbol.h"
 
+#include "lldb/Core/Address.h"
 #include "lldb/Core/Module.h"
 #include "lldb/Core/ModuleSpec.h"
 #include "lldb/Core/Section.h"
@@ -225,7 +226,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, const char *pattern) const {
   s->Printf("id = {0x%8.8x}", m_uid);
 
   if (m_addr_range.GetBaseAddress().GetSection()) {
@@ -252,11 +253,16 @@ 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());
+  if (ConstString demangled = m_mangled.GetDemangledName()) {
+    s->Printf(", name=\"");
+    s->PutCStringColorHighlighted(demangled.GetStringRef(), pattern);
+    s->Printf("\"");
+  }
+  if (ConstString mangled_name = m_mangled.GetMangledName()) {
+    s->Printf(", mangled=\"");
+    s->PutCStringColorHighlighted(mangled_name.GetStringRef(), pattern);
+    s->Printf("\"");
+  }
 }
 
 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 63968ec2d1506705..21064b1fd1b3838d 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,
+                                    const char *pattern) const {
   bool dumped_something = false;
   if (show_module && module_sp) {
     if (show_fullpaths)
@@ -95,7 +97,7 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
       if (!name)
         name = function->GetName();
       if (name)
-        name.Dump(s);
+        s->PutCStringColorHighlighted(name.GetStringRef(), pattern);
     }
 
     if (addr.IsValid()) {
@@ -163,7 +165,11 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
       dumped_something = true;
       if (symbol->GetType() == eSymbolTypeTrampoline)
         s->PutCString("symbol stub for: ");
-      symbol->GetName().Dump(s);
+      if (pattern)
+        s->PutCStringColorHighlighted(symbol->GetName().GetStringRef(),
+                                      pattern);
+      else
+        symbol->GetName().Dump(s);
     }
 
     if (addr.IsValid() && symbol->ValueIsAddress()) {
@@ -186,7 +192,7 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
 }
 
 void SymbolContext::GetDescription(Stream *s, lldb::DescriptionLevel level,
-                                   Target *target) const {
+                                   Target *target, const char *pattern) const {
   if (module_sp) {
     s->Indent("     Module: file = \"");
     module_sp->GetFileSpec().Dump(s->AsRawOstream());
@@ -246,7 +252,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 af28a49a1f0c2b5a..04679d9b017b117b 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,32 @@ size_t Stream::PutCString(llvm::StringRef str) {
   return bytes_written;
 }
 
+void Stream::PutCStringColorHighlighted(llvm::StringRef text,
+                                        const char *pattern) {
+  if (!pattern) {
+    PutCString(text);
+    return;
+  }
+
+  // If pattern is not nullptr, we should use color
+  llvm::Regex reg_pattern(pattern);
+  llvm::SmallVector<llvm::StringRef, 1> matches;
+  llvm::StringRef remaining = text;
+  std::string format_str = lldb_private::ansi::FormatAnsiTerminalCodes(
+      "${ansi.fg.red}%s${ansi.normal}");
+  size_t last_pos = 0;
+  while (reg_pattern.match(remaining, &matches)) {
+    llvm::StringRef match = matches[0];
+    size_t match_start_pos = match.data() - remaining.data();
+    Write(remaining.data(), match_start_pos);
+    Printf(format_str.c_str(), match.str().c_str());
+    last_pos = match_start_pos + match.size();
+    remaining = remaining.drop_front(last_pos);
+  }
+  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 0000000000000000..a58f05680762b671
--- /dev/null
+++ b/lldb/test/Shell/Commands/command-image-lookup-color.test
@@ -0,0 +1,39 @@
+# 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
+# CHECK1:         Summary: {{.+}}`{{.+}}31mma{{.+}}0min at main.c:2
+
+# 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
+# CHECK2:         Summary: {{.+}}`{{.+}}31mfoo{{.+}}0m at main.c:1
+
+# 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
+# CHECK3:         Summary: {{.+}}`{{.+}}31mma{{.+}}0min at main.c:2
+
+# Checking tail match
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -r -s .*o$' | FileCheck %s --check-prefix CHECK4
+# CHECK4:         Summary: {{.+}}`{{.+}}31mfoo{{.+}}0m at main.c:1
+
+# 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 CHECK5
+# CHECK5-NOT: {{[0-9]+}} symbols match the regular expression
+
+# Checking search which find more than 1 symbol
+
+# RUN: %lldb %t -b -o 'settings set use-color true' -o 'image lookup -r -s foo|main' | FileCheck %s --check-prefix CHECK6
+# CHECK6:         Name: {{.+}}31mmain{{.+}}0m.c
+# CHECK6:         Summary: {{.+}}`{{.+}}31mfoo{{.+}}0m at main.c:1
+# CHECK6:         Summary: {{.+}}`{{.+}}31mmain{{.+}}0m at main.c:2
+
+# 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 CHECK7
+# CHECK7:         Summary: {{.+}}`{{.+}}31mma{{.+}}0mi{{.+}}31mn{{.+}}0m at main.c:2
\ No newline at end of file

>From c6b19ad628b6d51607a6d5428688fc3a443b5629 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20L=2E=20Junior?= <josejunior at 10xengineers.ai>
Date: Mon, 27 Nov 2023 14:44:00 -0300
Subject: [PATCH 2/2] remove unnecessary condition

---
 lldb/source/Symbol/SymbolContext.cpp | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/lldb/source/Symbol/SymbolContext.cpp b/lldb/source/Symbol/SymbolContext.cpp
index 21064b1fd1b3838d..b70e02743cec6f3c 100644
--- a/lldb/source/Symbol/SymbolContext.cpp
+++ b/lldb/source/Symbol/SymbolContext.cpp
@@ -165,11 +165,7 @@ bool SymbolContext::DumpStopContext(Stream *s, ExecutionContextScope *exe_scope,
       dumped_something = true;
       if (symbol->GetType() == eSymbolTypeTrampoline)
         s->PutCString("symbol stub for: ");
-      if (pattern)
-        s->PutCStringColorHighlighted(symbol->GetName().GetStringRef(),
-                                      pattern);
-      else
-        symbol->GetName().Dump(s);
+      s->PutCStringColorHighlighted(symbol->GetName().GetStringRef(), pattern);
     }
 
     if (addr.IsValid() && symbol->ValueIsAddress()) {



More information about the lldb-commits mailing list