import gdb
import gdb.printing
import re
SMOL_INLINE_SIZE_RE = re.compile(r".*::_V(\d+)$")
def _read_utf8(mem):
try:
return mem.tobytes().decode("utf-8", errors="replace")
except Exception:
return repr(mem.tobytes())
def _active_variant(enum_val):
fields = enum_val.type.fields()
if len(fields) < 2:
return None, None
variant_field = fields[1]
return variant_field.name, enum_val[variant_field]
class SmolStrProvider:
def __init__(self, val):
self.val = val
def to_string(self):
try:
repr_enum = self.val["__0"]
except Exception:
return "<SmolStr: missing __0>"
variant_name, variant_val = _active_variant(repr_enum)
if not variant_name:
return "<SmolStr: unknown variant>"
if variant_name == "Inline":
try:
inline_len_val = variant_val["len"]
m = SMOL_INLINE_SIZE_RE.match(str(inline_len_val))
if not m:
return "<SmolStr Inline: bad len>"
length = int(m.group(1))
buf = variant_val["buf"]
data = bytes(int(buf[i]) for i in range(length))
return data.decode("utf-8", errors="replace")
except Exception as e:
return f"<SmolStr Inline error: {e}>"
if variant_name == "Static":
try:
return variant_val["__0"]
except Exception as e:
return f"<SmolStr Static error: {e}>"
if variant_name == "Heap":
try:
inner = variant_val["__0"]["ptr"]["pointer"]
data_ptr = inner["data_ptr"]
length = int(inner["length"])
sizeof_AtomicUsize = gdb.lookup_type(
"core::sync::atomic::AtomicUsize"
).sizeof
header_size = sizeof_AtomicUsize * 2 data_arr = int(data_ptr) + header_size
mem = gdb.selected_inferior().read_memory(data_arr, length)
return _read_utf8(mem)
except Exception as e:
return f"<SmolStr Heap error: {e}>"
return f"<SmolStr: unhandled variant {variant_name}>"
def display_hint(self):
return "string"
class SmolStrSubPrinter(gdb.printing.SubPrettyPrinter):
def __init__(self):
super(SmolStrSubPrinter, self).__init__("SmolStr")
def __call__(self, val):
if not self.enabled:
return None
try:
t = val.type.strip_typedefs()
if t.code == gdb.TYPE_CODE_STRUCT and t.name == "smol_str::SmolStr":
return SmolStrProvider(val)
except Exception:
pass
return None
class SmolStrPrettyPrinter(gdb.printing.PrettyPrinter):
def __init__(self):
super(SmolStrPrettyPrinter, self).__init__("smol_str", [])
self.subprinters = []
self._sp = SmolStrSubPrinter()
self.subprinters.append(self._sp)
def __call__(self, val):
for sp in self.subprinters:
pp = sp(val)
if pp is not None:
return pp
return None
printer = SmolStrPrettyPrinter()
def register_printers(objfile=None):
gdb.printing.register_pretty_printer(objfile, printer, replace=True)
register_printers()