From 58fe72ab83ab6490b9a09e71f5762f2a12bd2c5a Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Sun, 30 Aug 2026 17:30:35 +0200 Subject: kstd/gdb: add error_code and result printers --- libs/kstd/gdb/__init__.py | 10 ++++--- libs/kstd/gdb/error_code.py | 66 +++++++++++++++++++++++++++++++++++++++++++++ libs/kstd/gdb/result.py | 51 +++++++++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 libs/kstd/gdb/error_code.py create mode 100644 libs/kstd/gdb/result.py (limited to 'libs/kstd') diff --git a/libs/kstd/gdb/__init__.py b/libs/kstd/gdb/__init__.py index 0cdafffd..018b31f2 100644 --- a/libs/kstd/gdb/__init__.py +++ b/libs/kstd/gdb/__init__.py @@ -1,15 +1,17 @@ import gdb.printing -from .units import KstdBytesPrinter -from .vector import KstdVectorPrinter -from .string import KstdStringPrinter +from .error_code import KstdErrorCodePrinter +from .result import KstdResultPrinter from .smart_pointers import ( KstdUniquePtrPrinter, KstdSharedPtrPrinter, KstdObserverPtrPrinter, KstdWeakPtrPrinter, ) +from .string import KstdStringPrinter +from .units import KstdBytesPrinter +from .vector import KstdVectorPrinter def build_pretty_printers(): @@ -22,6 +24,8 @@ def build_pretty_printers(): pp.add_printer("observer_ptr", "^kstd::observer_ptr<.*>$", KstdObserverPtrPrinter) pp.add_printer("bytes", "^kstd::basic_unit<.*, kstd::bytes_tag, .*>$", KstdBytesPrinter) pp.add_printer("offset", "^kstd::basic_unit<.*, kstd::byte_offset_tag, .*>$", KstdBytesPrinter) + pp.add_printer("error_code", "^kstd::error_code$", KstdErrorCodePrinter) + pp.add_printer("result", "^std::expected<.*, kstd::error_code>$", KstdResultPrinter) return pp diff --git a/libs/kstd/gdb/error_code.py b/libs/kstd/gdb/error_code.py new file mode 100644 index 00000000..1569f59a --- /dev/null +++ b/libs/kstd/gdb/error_code.py @@ -0,0 +1,66 @@ +import gdb + + +class KstdErrorCodePrinter(gdb.ValuePrinter): + def __init__(self, val): + self.__val = val + + def _error_value(self): + return int(self.__val["m_value"]) + + def _category_name(self): + try: + category_pointer = self.__val["m_category"] + if int(category_pointer) == 0: + return "" + category = category_pointer.dereference() + try: + dynamic = category.dynamic_type + name = str(dynamic) + except gdb.error: + name = str(category.type) + name = name.replace("(anonymous namespace)::", "") + if name.endswith("_t"): + name = name[:-2] + return name + except (gdb.error, AttributeError): + return "?" + + def _message(self): + try: + category_pointer = self.__val["m_category"] + if int(category_pointer) == 0: + return None + value = self._error_value() + address = int(category_pointer) + result = gdb.parse_and_eval( + f"((kstd::error_category const *){address:#x})->message({value})" + ) + try: + ptr = result["_M_str"] + length = int(result["_M_len"]) + if int(ptr) != 0 and length > 0: + return ptr.string(length=length) + except (gdb.error, AttributeError, KeyError): + pass + return str(result) + except (gdb.error, RuntimeError): + return None + + def to_string(self): + value = self._error_value() + category = self._category_name() + msg = self._message() + if msg is not None: + return f"{category}:{value} ({msg})" + return f"{category}:{value}" + + def children(self): + yield ("value", self.__val["m_value"]) + category_pointer = self.__val["m_category"] + if int(category_pointer) != 0: + yield ("category", category_pointer.dereference()) + + def display_hint(self): + return None + diff --git a/libs/kstd/gdb/result.py b/libs/kstd/gdb/result.py new file mode 100644 index 00000000..8cef0fed --- /dev/null +++ b/libs/kstd/gdb/result.py @@ -0,0 +1,51 @@ +import gdb + +from .error_code import KstdErrorCodePrinter + + +class KstdResultPrinter(gdb.ValuePrinter): + def __init__(self, val): + self.__val = val + self.__has_value = bool(val["_M_has_value"]) + try: + t = val.type.template_argument(0) + self.__is_void = t.code == gdb.TYPE_CODE_VOID + except (gdb.error, AttributeError): + self.__is_void = False + + @property + def _error_code(self): + return self.__val["_M_unex"] + + @property + def _value(self): + return self.__val["_M_val"] + + def _format_value(self, gdb_value): + printer = gdb.default_visualizer(gdb_value) + if printer is not None: + return printer.to_string() + s = str(gdb_value) + if s.startswith("{"): + return str(gdb_value.type.strip_typedefs()) + return s + + def _format_error(self, error_code_val): + printer = KstdErrorCodePrinter(error_code_val) + return printer.to_string() + + def to_string(self): + if not self.__has_value: + return f"failure: {self._format_error(self._error_code)}" + if self.__is_void: + return "success" + return f"success: {self._format_value(self._value)}" + + def children(self): + if not self.__has_value: + yield ("error", self._error_code) + elif not self.__is_void: + yield ("value", self._value) + + def display_hint(self): + return None -- cgit v1.2.3