[Lldb-commits] [lldb] [lldb] Support custom printf formatting for variables (PR #81196)

Dave Lee via lldb-commits lldb-commits at lists.llvm.org
Wed Feb 14 10:12:26 PST 2024


https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/81196

>From 81a2034ff2b41e30a1f5b82c86b4d5d4c429ed52 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Thu, 8 Feb 2024 13:59:12 -0800
Subject: [PATCH 1/4] [lldb] Support custom printf formatting for variables

---
 lldb/source/Core/FormatEntity.cpp | 25 +++++++++++++++++++++++--
 1 file changed, 23 insertions(+), 2 deletions(-)

diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index fa5eadc6ff4e9a..0e929203935304 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -883,8 +883,29 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
   }
 
   if (!is_array_range) {
-    LLDB_LOGF(log,
-              "[Debugger::FormatPrompt] dumping ordinary printable output");
+    if (!entry.printf_format.empty()) {
+      auto type_info = target->GetTypeInfo();
+      if (type_info & eTypeIsInteger) {
+        if (type_info & eTypeIsSigned) {
+          bool success = false;
+          auto integer = target->GetValueAsSigned(0, &success);
+          if (success) {
+            LLDB_LOGF(log, "dumping using printf format");
+            s.Printf(entry.printf_format.c_str(), integer);
+            return true;
+          }
+        } else {
+          bool success = false;
+          auto integer = target->GetValueAsUnsigned(0, &success);
+          if (success) {
+            LLDB_LOGF(log, "dumping using printf format");
+            s.Printf(entry.printf_format.c_str(), integer);
+            return true;
+          }
+        }
+      }
+    }
+    LLDB_LOGF(log, "dumping ordinary printable output");
     return target->DumpPrintableRepresentation(s, val_obj_display,
                                                custom_format);
   } else {

>From 335ab1de4b39257e3bbb3bd969a0dd6991747558 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 13 Feb 2024 13:26:35 -0800
Subject: [PATCH 2/4] Factor out DumpValueWithPrintf; Add test

---
 lldb/source/Core/FormatEntity.cpp             | 45 +++++++++++--------
 .../custom-printf-summary/Makefile            |  2 +
 .../TestCustomPrintfSummary.py                | 11 +++++
 .../custom-printf-summary/main.c              | 13 ++++++
 4 files changed, 52 insertions(+), 19 deletions(-)
 create mode 100644 lldb/test/API/functionalities/data-formatter/custom-printf-summary/Makefile
 create mode 100644 lldb/test/API/functionalities/data-formatter/custom-printf-summary/TestCustomPrintfSummary.py
 create mode 100644 lldb/test/API/functionalities/data-formatter/custom-printf-summary/main.c

diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 0e929203935304..57a05507d844cf 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -658,6 +658,25 @@ static char ConvertValueObjectStyleToChar(
   return '\0';
 }
 
+static bool DumpValueWithPrintf(Stream &s, llvm::StringRef format,
+                                ValueObject &target) {
+  auto type_info = target.GetTypeInfo();
+  if (type_info & eTypeIsInteger) {
+    if (type_info & eTypeIsSigned) {
+      if (auto integer = target.GetValueAsSigned()) {
+        s.Printf(format.data(), *integer);
+        return true;
+      }
+    } else {
+      if (auto integer = target.GetValueAsUnsigned()) {
+        s.Printf(format.data(), *integer);
+        return true;
+      }
+    }
+  }
+  return false;
+}
+
 static bool DumpValue(Stream &s, const SymbolContext *sc,
                       const ExecutionContext *exe_ctx,
                       const FormatEntity::Entry &entry, ValueObject *valobj) {
@@ -884,25 +903,13 @@ static bool DumpValue(Stream &s, const SymbolContext *sc,
 
   if (!is_array_range) {
     if (!entry.printf_format.empty()) {
-      auto type_info = target->GetTypeInfo();
-      if (type_info & eTypeIsInteger) {
-        if (type_info & eTypeIsSigned) {
-          bool success = false;
-          auto integer = target->GetValueAsSigned(0, &success);
-          if (success) {
-            LLDB_LOGF(log, "dumping using printf format");
-            s.Printf(entry.printf_format.c_str(), integer);
-            return true;
-          }
-        } else {
-          bool success = false;
-          auto integer = target->GetValueAsUnsigned(0, &success);
-          if (success) {
-            LLDB_LOGF(log, "dumping using printf format");
-            s.Printf(entry.printf_format.c_str(), integer);
-            return true;
-          }
-        }
+      if (DumpValueWithPrintf(s, entry.printf_format, *target)) {
+        LLDB_LOGF(log, "dumping using printf format");
+        return true;
+      } else {
+        LLDB_LOG(log,
+                 "unsupported printf format '{0}' - for type info flags {1}",
+                 entry.printf_format, target->GetTypeInfo());
       }
     }
     LLDB_LOGF(log, "dumping ordinary printable output");
diff --git a/lldb/test/API/functionalities/data-formatter/custom-printf-summary/Makefile b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/Makefile
new file mode 100644
index 00000000000000..c9319d6e6888a4
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/Makefile
@@ -0,0 +1,2 @@
+C_SOURCES := main.c
+include Makefile.rules
diff --git a/lldb/test/API/functionalities/data-formatter/custom-printf-summary/TestCustomPrintfSummary.py b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/TestCustomPrintfSummary.py
new file mode 100644
index 00000000000000..7d196c66caaa79
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/TestCustomPrintfSummary.py
@@ -0,0 +1,11 @@
+import lldb
+from lldbsuite.test.lldbtest import *
+import lldbsuite.test.lldbutil as lldbutil
+
+
+class TestCase(TestBase):
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(self, "break here", lldb.SBFileSpec("main.c"))
+        self.runCmd("type summary add -s '${var.ubyte%%2.2X}${var.sbyte%%2.2X}!' Bytes")
+        self.expect("v bytes", substrs=[" = 1001!"])
diff --git a/lldb/test/API/functionalities/data-formatter/custom-printf-summary/main.c b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/main.c
new file mode 100644
index 00000000000000..8f92b9dafd32f3
--- /dev/null
+++ b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/main.c
@@ -0,0 +1,13 @@
+#include <stdint.h>
+#include <stdio.h>
+
+struct Bytes {
+  uint8_t ubyte;
+  int8_t sbyte;
+};
+
+int main() {
+  struct Bytes bytes = {0x10, 0x01};
+  (void)bytes;
+  printf("break here\n");
+}

>From 678ab3360f790a0a1d3c3631fe406b790e4c16dd Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Tue, 13 Feb 2024 14:40:10 -0800
Subject: [PATCH 3/4] Use main line API

---
 lldb/source/Core/FormatEntity.cpp | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp
index 57a05507d844cf..ad93da58d2502c 100644
--- a/lldb/source/Core/FormatEntity.cpp
+++ b/lldb/source/Core/FormatEntity.cpp
@@ -663,13 +663,17 @@ static bool DumpValueWithPrintf(Stream &s, llvm::StringRef format,
   auto type_info = target.GetTypeInfo();
   if (type_info & eTypeIsInteger) {
     if (type_info & eTypeIsSigned) {
-      if (auto integer = target.GetValueAsSigned()) {
-        s.Printf(format.data(), *integer);
+      bool success = false;
+      auto integer = target.GetValueAsSigned(0, &success);
+      if (success) {
+        s.Printf(format.data(), integer);
         return true;
       }
     } else {
-      if (auto integer = target.GetValueAsUnsigned()) {
-        s.Printf(format.data(), *integer);
+      bool success = false;
+      auto integer = target.GetValueAsUnsigned(0, &success);
+      if (success) {
+        s.Printf(format.data(), integer);
         return true;
       }
     }

>From bb4a2782631b86f4e7205beeb77297c56359c461 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 14 Feb 2024 10:12:00 -0800
Subject: [PATCH 4/4] Mention printf formatting in variable.rst

---
 lldb/docs/use/variable.rst | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst
index 8eaed6405315b4..d197c89a99e579 100644
--- a/lldb/docs/use/variable.rst
+++ b/lldb/docs/use/variable.rst
@@ -460,6 +460,15 @@ summary strings, regardless of the format they have applied to their types. To
 do that, you can use %format inside an expression path, as in ${var.x->x%u},
 which would display the value of x as an unsigned integer.
 
+Additionally, custom output can be achieved by using a printf format string
+after the ``%`` marker. When a summary string contains two ``%`` markers, then
+it is using a custom printf format. To illustrate, compare ``${var.byte%x}``
+and ``${var.byte%%x}``. The former uses lldb's hex formatting (``x``), which
+automatically includes a ``0x`` prefix, and also zero pads the value to match
+the size of the type. The latter uses printf formatting (``%x``), and will
+print only the hex value, with no ``0x`` prefix, and no padding. This raw
+control is useful when composing multiple pieces into a larger whole.
+
 You can also use some other special format markers, not available for formats
 themselves, but which carry a special meaning when used in this context:
 



More information about the lldb-commits mailing list