Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions doc/modules/ROOT/pages/debugger.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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
====
Expand Down
172 changes: 172 additions & 0 deletions extra/decimal_printer_gdb.py
Original file line number Diff line number Diff line change
@@ -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"<invalid decimal32_t: {e}>"

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"<invalid decimal64_t: {e}>"

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"<invalid decimal128_t: {e}>"

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"<invalid decimal_fast32_t: {e}>"

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"<invalid decimal_fast64_t: {e}>"

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"<invalid decimal_fast128_t: {e}>"

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")
24 changes: 12 additions & 12 deletions extra/decimal_printer.py → extra/decimal_printer_lldb.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down