diff --git a/doc/modules/ROOT/pages/debugger.adoc b/doc/modules/ROOT/pages/debugger.adoc index b24dabe6e..4521183a7 100644 --- a/doc/modules/ROOT/pages/debugger.adoc +++ b/doc/modules/ROOT/pages/debugger.adoc @@ -8,15 +8,37 @@ https://www.boost.org/LICENSE_1_0.txt = Debugger Support :idprefix: debug_ -Currently, Boost.Decimal supports pretty printing with LLDB. +Currently, Boost.Decimal supports pretty printing with LLDB and GDB. + +== LLDB + To load the pretty printer, add the following line to your `.lldbinit`: [source] ---- -command script import /path/to/decimal/extra/decimal_printer.py +command script import /path/to/decimal/extra/decimal_printer_lldb.py +---- + +== GDB + +To load the pretty printer, add the following line to your `.gdbinit`: + +[source] +---- +python exec(open("/path/to/decimal/extra/decimal_printer_gdb.py").read()) ---- -Once you have loaded `decimal_printer.py` you can run the following example to see how different values are represented with the pretty printer. +or you can source it manually in GDB: + +[source] +---- +(gdb) source /path/to/decimal/extra/decimal_printer_gdb.py +---- + +== Example + +Once you have loaded a pretty printer, you can run the below example to see how different values are represented with the pretty printer. +This expected output of the example below was taken from LLDB, but the results should be quite similar when using GDB. .The following example can be run with the debugger to show a variety of values ==== diff --git a/extra/decimal_printer_gdb.py b/extra/decimal_printer_gdb.py new file mode 100644 index 000000000..05e2671fe --- /dev/null +++ b/extra/decimal_printer_gdb.py @@ -0,0 +1,172 @@ +# Copyright 2025 Matt Borland +# Distributed under the Boost Software License, Version 1.0. +# https://www.boost.org/LICENSE_1_0.txt + +from detail.decode_ieee_type import decode_decimal32 +from detail.decode_ieee_type import decode_decimal64 +from detail.decode_ieee_type import decode_decimal128 +from detail.decode_fast_type import decode_decimal_fast32 +from detail.decode_fast_type import decode_decimal_fast64 +from detail.decode_fast_type import decode_decimal_fast128 + +import gdb +import gdb.printing + +class Decimal32Printer: + """Pretty printer for decimal32_t type""" + + def __init__(self, val): + self.val = val + + def to_string(self): + try: + bits = int(self.val['bits_']) + return decode_decimal32(bits) + except Exception as e: + return f"" + + def children(self): + yield ('bits_', self.val['bits_']) + + +class Decimal64Printer: + """Pretty printer for decimal64_t type""" + + def __init__(self, val): + self.val = val + + def to_string(self): + try: + bits = int(self.val['bits_']) + return decode_decimal64(bits) + except Exception as e: + return f"" + + def children(self): + yield ('bits_', self.val['bits_']) + + +class Decimal128Printer: + """Pretty printer for decimal128_t type""" + + def __init__(self, val): + self.val = val + + def to_string(self): + try: + bits = self.val['bits_'] + bits_high = int(bits['high']) + bits_low = int(bits['low']) + combined_bits = (bits_high << 64) | bits_low + return decode_decimal128(combined_bits) + except Exception as e: + return f"" + + def children(self): + yield ('bits_', self.val['bits_']) + + +class DecimalFast32Printer: + """Pretty printer for decimal_fast32_t type""" + + def __init__(self, val): + self.val = val + + def to_string(self): + try: + significand = int(self.val['significand_']) + exp = int(self.val['exponent_']) + sign = int(self.val['sign_']) + return decode_decimal_fast32(significand, exp, sign) + except Exception as e: + return f"" + + def children(self): + yield ('significand_', self.val['significand_']) + yield ('exponent_', self.val['exponent_']) + yield ('sign_', self.val['sign_']) + + +class DecimalFast64Printer: + """Pretty printer for decimal_fast64_t type""" + + def __init__(self, val): + self.val = val + + def to_string(self): + try: + significand = int(self.val['significand_']) + exp = int(self.val['exponent_']) + sign = int(self.val['sign_']) + return decode_decimal_fast64(significand, exp, sign) + except Exception as e: + return f"" + + def children(self): + yield ('significand_', self.val['significand_']) + yield ('exponent_', self.val['exponent_']) + yield ('sign_', self.val['sign_']) + + +class DecimalFast128Printer: + """Pretty printer for decimal_fast128_t type""" + + def __init__(self, val): + self.val = val + + def to_string(self): + try: + significand = self.val['significand_'] + bits_high = int(significand['high']) + bits_low = int(significand['low']) + combined_bits = (bits_high << 64) | bits_low + + exp = int(self.val['exponent_']) + sign = int(self.val['sign_']) + + return decode_decimal_fast128(combined_bits, exp, sign) + except Exception as e: + return f"" + + def children(self): + yield ('significand_', self.val['significand_']) + yield ('exponent_', self.val['exponent_']) + yield ('sign_', self.val['sign_']) + + +def build_pretty_printer(): + """Build and return the pretty printer collection""" + pp = gdb.printing.RegexpCollectionPrettyPrinter("boost_decimal") + + # IEEE types + pp.add_printer('decimal32_t', + r'^(const )?(boost::decimal::)?decimal32_t( &| \*)?$', + Decimal32Printer) + pp.add_printer('decimal64_t', + r'^(const )?(boost::decimal::)?decimal64_t( &| \*)?$', + Decimal64Printer) + pp.add_printer('decimal128_t', + r'^(const )?(boost::decimal::)?decimal128_t( &| \*)?$', + Decimal128Printer) + + # Fast types + pp.add_printer('decimal_fast32_t', + r'^(const )?(boost::decimal::)?decimal_fast32_t( &| \*)?$', + DecimalFast32Printer) + pp.add_printer('decimal_fast64_t', + r'^(const )?(boost::decimal::)?decimal_fast64_t( &| \*)?$', + DecimalFast64Printer) + pp.add_printer('decimal_fast128_t', + r'^(const )?(boost::decimal::)?decimal_fast128_t( &| \*)?$', + DecimalFast128Printer) + + return pp + + +def register_printers(objfile=None): + gdb.printing.register_pretty_printer(objfile, build_pretty_printer()) + + +# Auto-register when the module is loaded +register_printers() +print("Boost.Decimal pretty printers loaded successfully") diff --git a/extra/decimal_printer.py b/extra/decimal_printer_lldb.py similarity index 93% rename from extra/decimal_printer.py rename to extra/decimal_printer_lldb.py index b1b7004c7..95861ea6b 100644 --- a/extra/decimal_printer.py +++ b/extra/decimal_printer_lldb.py @@ -119,55 +119,55 @@ def __lldb_init_module(debugger, internal_dict): decimal_fast128_pattern = r"^(const )?(boost::decimal::decimal_fast128_t|(\w+::)*decimal_fast128_t)( &| \*)?$" debugger.HandleCommand( - f'type summary add -x "{decimal32_pattern}" -e -F decimal_printer.decimal32_summary' + f'type summary add -x "{decimal32_pattern}" -e -F decimal_printer_lldb.decimal32_summary' ) debugger.HandleCommand( - f'type synthetic add -x "{decimal32_pattern}" -l decimal_printer.DecimalSyntheticProvider' + f'type synthetic add -x "{decimal32_pattern}" -l decimal_printer_lldb.DecimalSyntheticProvider' ) print("decimal32_t printer loaded successfully") debugger.HandleCommand( - f'type summary add -x "{decimal64_pattern}" -e -F decimal_printer.decimal64_summary' + f'type summary add -x "{decimal64_pattern}" -e -F decimal_printer_lldb.decimal64_summary' ) debugger.HandleCommand( - f'type synthetic add -x "{decimal64_pattern}" -l decimal_printer.DecimalSyntheticProvider' + f'type synthetic add -x "{decimal64_pattern}" -l decimal_printer_lldb.DecimalSyntheticProvider' ) print("decimal64_t printer loaded successfully") debugger.HandleCommand( - f'type summary add -x "{decimal128_pattern}" -e -F decimal_printer.decimal128_summary' + f'type summary add -x "{decimal128_pattern}" -e -F decimal_printer_lldb.decimal128_summary' ) debugger.HandleCommand( - f'type synthetic add -x "{decimal128_pattern}" -l decimal_printer.DecimalSyntheticProvider' + f'type synthetic add -x "{decimal128_pattern}" -l decimal_printer_lldb.DecimalSyntheticProvider' ) print("decimal128_t printer loaded successfully") debugger.HandleCommand( - f'type summary add -x "{decimal_fast32_pattern}" -e -F decimal_printer.decimal_fast32_summary' + f'type summary add -x "{decimal_fast32_pattern}" -e -F decimal_printer_lldb.decimal_fast32_summary' ) debugger.HandleCommand( - f'type synthetic add -x "{decimal_fast32_pattern}" -l decimal_printer.DecimalFastSyntheticProvider' + f'type synthetic add -x "{decimal_fast32_pattern}" -l decimal_printer_lldb.DecimalFastSyntheticProvider' ) print("decimal_fast32_t printer loaded successfully") debugger.HandleCommand( - f'type summary add -x "{decimal_fast64_pattern}" -e -F decimal_printer.decimal_fast64_summary' + f'type summary add -x "{decimal_fast64_pattern}" -e -F decimal_printer_lldb.decimal_fast64_summary' ) debugger.HandleCommand( - f'type synthetic add -x "{decimal_fast64_pattern}" -l decimal_printer.DecimalFastSyntheticProvider' + f'type synthetic add -x "{decimal_fast64_pattern}" -l decimal_printer_lldb.DecimalFastSyntheticProvider' ) print("decimal_fast64_t printer loaded successfully") debugger.HandleCommand( - f'type summary add -x "{decimal_fast128_pattern}" -e -F decimal_printer.decimal_fast128_summary' + f'type summary add -x "{decimal_fast128_pattern}" -e -F decimal_printer_lldb.decimal_fast128_summary' ) debugger.HandleCommand( - f'type synthetic add -x "{decimal_fast128_pattern}" -l decimal_printer.DecimalFastSyntheticProvider' + f'type synthetic add -x "{decimal_fast128_pattern}" -l decimal_printer_lldb.DecimalFastSyntheticProvider' ) print("decimal_fast128_t printer loaded successfully")