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....@gmail.com> Date: Thu, 8 Feb 2024 13:59:12 -0800 Subject: [PATCH 1/5] [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....@gmail.com> Date: Tue, 13 Feb 2024 13:26:35 -0800 Subject: [PATCH 2/5] 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....@gmail.com> Date: Tue, 13 Feb 2024 14:40:10 -0800 Subject: [PATCH 3/5] 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....@gmail.com> Date: Wed, 14 Feb 2024 10:12:00 -0800 Subject: [PATCH 4/5] 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: >From 24a0bb43b0d5571ad35d2819cc39028eb7c21654 Mon Sep 17 00:00:00 2001 From: Dave Lee <davelee....@gmail.com> Date: Tue, 19 Mar 2024 16:06:05 -0700 Subject: [PATCH 5/5] Switch from printf to llvm::format --- lldb/docs/use/variable.rst | 16 +++---- lldb/source/Core/FormatEntity.cpp | 46 ++++++++++--------- .../TestCustomPrintfSummary.py | 2 +- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/lldb/docs/use/variable.rst b/lldb/docs/use/variable.rst index d197c89a99e579..e9175b25336ba9 100644 --- a/lldb/docs/use/variable.rst +++ b/lldb/docs/use/variable.rst @@ -460,14 +460,14 @@ 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. +Additionally, custom output can be achieved by using an LLVM format string, +commencing with the ``:`` marker. To illustrate, compare ``${var.byte%x}`` and +``${var.byte:x-}``. The former uses lldb's builtin hex formatting (``x``), +which unconditionally inserts a ``0x`` prefix, and also zero pads the value to +match the size of the type. The latter uses ``llvm::formatv`` 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: diff --git a/lldb/source/Core/FormatEntity.cpp b/lldb/source/Core/FormatEntity.cpp index ad93da58d2502c..fb5758bcb31471 100644 --- a/lldb/source/Core/FormatEntity.cpp +++ b/lldb/source/Core/FormatEntity.cpp @@ -658,27 +658,31 @@ static char ConvertValueObjectStyleToChar( return '\0'; } -static bool DumpValueWithPrintf(Stream &s, llvm::StringRef format, - ValueObject &target) { +static bool DumpValueWithLLVMFormat(Stream &s, llvm::StringRef options, + ValueObject &target) { + std::string formatted; + std::string llvm_format = ("{0:" + options + "}").str(); + auto type_info = target.GetTypeInfo(); if (type_info & eTypeIsInteger) { if (type_info & eTypeIsSigned) { bool success = false; auto integer = target.GetValueAsSigned(0, &success); - if (success) { - s.Printf(format.data(), integer); - return true; - } + if (success) + formatted = llvm::formatv(llvm_format.data(), integer); } else { bool success = false; auto integer = target.GetValueAsUnsigned(0, &success); - if (success) { - s.Printf(format.data(), integer); - return true; - } + if (success) + formatted = llvm::formatv(llvm_format.data(), integer); } } - return false; + + if (formatted.empty()) + return false; + + s.Write(formatted.data(), formatted.size()); + return true; } static bool DumpValue(Stream &s, const SymbolContext *sc, @@ -751,9 +755,12 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, return RunScriptFormatKeyword(s, sc, exe_ctx, valobj, entry.string.c_str()); } - llvm::StringRef subpath(entry.string); + auto split = llvm::StringRef(entry.string).split(':'); + auto subpath = split.first; + auto llvm_format = split.second; + // simplest case ${var}, just print valobj's value - if (entry.string.empty()) { + if (subpath.empty()) { if (entry.printf_format.empty() && entry.fmt == eFormatDefault && entry.number == ValueObject::eValueObjectRepresentationStyleValue) was_plain_var = true; @@ -762,7 +769,7 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, target = valobj; } else // this is ${var.something} or multiple .something nested { - if (entry.string[0] == '[') + if (subpath[0] == '[') was_var_indexed = true; ScanBracketedRange(subpath, close_bracket_index, var_name_final_if_array_range, index_lower, @@ -770,14 +777,11 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, Status error; - const std::string &expr_path = entry.string; - - LLDB_LOGF(log, "[Debugger::FormatPrompt] symbol to expand: %s", - expr_path.c_str()); + LLDB_LOG(log, "[Debugger::FormatPrompt] symbol to expand: {0}", subpath); target = valobj - ->GetValueForExpressionPath(expr_path.c_str(), &reason_to_stop, + ->GetValueForExpressionPath(subpath, &reason_to_stop, &final_value_type, options, &what_next) .get(); @@ -906,8 +910,8 @@ static bool DumpValue(Stream &s, const SymbolContext *sc, } if (!is_array_range) { - if (!entry.printf_format.empty()) { - if (DumpValueWithPrintf(s, entry.printf_format, *target)) { + if (!llvm_format.empty()) { + if (DumpValueWithLLVMFormat(s, llvm_format, *target)) { LLDB_LOGF(log, "dumping using printf format"); return true; } else { 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 index 7d196c66caaa79..caf072cebdf303 100644 --- a/lldb/test/API/functionalities/data-formatter/custom-printf-summary/TestCustomPrintfSummary.py +++ b/lldb/test/API/functionalities/data-formatter/custom-printf-summary/TestCustomPrintfSummary.py @@ -7,5 +7,5 @@ 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.runCmd("type summary add -s '${var.ubyte:x-2}${var.sbyte:x-2}!' Bytes") self.expect("v bytes", substrs=[" = 1001!"]) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits