diff --git a/doc/int128.adoc b/doc/int128.adoc index 30806c28..b8128044 100644 --- a/doc/int128.adoc +++ b/doc/int128.adoc @@ -20,6 +20,8 @@ Matt Borland include::int128/overview.adoc[] +include::int128/printer.adoc[] + include::int128/api_reference.adoc[] include::int128/file_structure.adoc[] diff --git a/doc/int128/printer.adoc b/doc/int128/printer.adoc new file mode 100644 index 00000000..9b8df8e1 --- /dev/null +++ b/doc/int128/printer.adoc @@ -0,0 +1,21 @@ +//// +Copyright 2025 Matt Borland +Distributed under the Boost Software License, Version 1.0. +https://www.boost.org/LICENSE_1_0.txt +//// + +[#pretty_printer] += Pretty Printers +:idprefix: pretty_printers_ + +The library contains a pretty printer for LLDB in the `extra/` folder. +To use this, add the following line to your `~/.lldbinit` file: + +[source] +---- +command script import /path/to/int128/extra/int128_printer.py +---- + +If this is successful, you should see the following message in your debugger upon startup: + +"int128_t and uint128_t pretty printers loaded successfully" diff --git a/extra/int128_printer.py b/extra/int128_printer.py new file mode 100644 index 00000000..ade3095c --- /dev/null +++ b/extra/int128_printer.py @@ -0,0 +1,115 @@ +# int128_printer.py +# +# Struct definitions: +# struct uint128_t { std::uint64_t low; std::uint64_t high; }; +# struct int128_t { std::uint64_t low; std::int64_t high; }; +# +# On big endian machines the word order is reversed + +import lldb + +def uint128_summary(valobj, internal_dict): + """ + Custom summary for uint128_t type (unsigned). + Displays as decimal (base 10). + """ + try: + val = valobj.GetNonSyntheticValue() + high = val.GetChildMemberWithName("high").GetValueAsUnsigned() + low = val.GetChildMemberWithName("low").GetValueAsUnsigned() + + value = (high << 64) | low + return str(value) + except Exception as e: + return f"" + +def int128_summary(valobj, internal_dict): + """ + Custom summary for int128_t type (signed). + Displays as decimal (base 10). + """ + try: + val = valobj.GetNonSyntheticValue() + # high is std::int64_t, so use GetValueAsSigned() + high = val.GetChildMemberWithName("high").GetValueAsSigned() + # low is std::uint64_t, so use GetValueAsUnsigned() + low = val.GetChildMemberWithName("low").GetValueAsUnsigned() + + value = (high << 64) + low + return str(value) + except Exception as e: + return f"" + +def __lldb_init_module(debugger, internal_dict): + uint128_pattern = r"^(const )?(boost::int128::uint128_t|(\w+::)*uint128_t)( &| \*)?$" + int128_pattern = r"^(const )?(boost::int128::int128_t|(\w+::)*int128_t)( &| \*)?$" + + debugger.HandleCommand( + f'type summary add -x "{uint128_pattern}" -e -F int128_printer.uint128_summary' + ) + debugger.HandleCommand( + f'type synthetic add -x "{uint128_pattern}" -l int128_printer.Uint128SyntheticProvider' + ) + + debugger.HandleCommand( + f'type summary add -x "{int128_pattern}" -e -F int128_printer.int128_summary' + ) + debugger.HandleCommand( + f'type synthetic add -x "{int128_pattern}" -l int128_printer.Int128SyntheticProvider' + ) + + print("int128_t and uint128_t pretty printers loaded successfully") + +class Uint128SyntheticProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def num_children(self): + return 2 + + def get_child_index(self, name): + if name == "low": + return 0 + elif name == "high": + return 1 + return -1 + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName("low") + elif index == 1: + return self.valobj.GetChildMemberWithName("high") + return None + + def update(self): + pass + + def has_children(self): + return True + +class Int128SyntheticProvider: + def __init__(self, valobj, internal_dict): + self.valobj = valobj + + def num_children(self): + return 2 + + def get_child_index(self, name): + if name == "low": + return 0 + elif name == "high": + return 1 + return -1 + + def get_child_at_index(self, index): + if index == 0: + return self.valobj.GetChildMemberWithName("low") + elif index == 1: + return self.valobj.GetChildMemberWithName("high") + return None + + def update(self): + pass + + def has_children(self): + return True