[Scummvm-git-logs] scummvm master -> d8fa25e3e74285e7882b68f980cc084e13da4c9b

sev- noreply at scummvm.org
Tue Jan 6 23:44:13 UTC 2026


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
d8fa25e3e7 DEVTOOLS: Add LLDB pretty-printers


Commit: d8fa25e3e74285e7882b68f980cc084e13da4c9b
    https://github.com/scummvm/scummvm/commit/d8fa25e3e74285e7882b68f980cc084e13da4c9b
Author: Dries Harnie (dries at harnie.be)
Date: 2026-01-07T02:44:08+03:00

Commit Message:
DEVTOOLS: Add LLDB pretty-printers

Changed paths:
  A devtools/lldb_pretty_printers.py


diff --git a/devtools/lldb_pretty_printers.py b/devtools/lldb_pretty_printers.py
new file mode 100644
index 00000000000..236705e3a50
--- /dev/null
+++ b/devtools/lldb_pretty_printers.py
@@ -0,0 +1,206 @@
+'''
+This file contains LLDB pretty-printers for common ScummVM data types.
+To enable it, add the following line to the .lldbinit file for this project:
+
+    command script import devtools.lldb_pretty_printers
+
+LLDB disallows loading .lldbinit files from source directories by default, so
+you may need to add the following to your global ~/.lldbinit:
+
+    settings set target.load-cwd-lldbinit true
+
+
+'''
+from dataclasses import dataclass
+import lldb
+
+
+class ArrayProvider:
+    '''Formatter for Common::Array'''
+    def __init__(self, valobj, internal_dict):
+        self.valobj = valobj
+        self.data_type = self.valobj.GetChildMemberWithName("_storage").GetType().GetPointeeType()
+        self.data_size = self.data_type.GetByteSize()
+        self.update()
+
+    def update(self):
+        self.size = \
+            self.valobj.GetChildMemberWithName("_size").GetValueAsUnsigned()
+        return False
+
+    def num_children(self, _max_children=None):
+        return self.size
+
+    def has_children(self):
+        return self.size > 0
+
+    def get_child_index(self, name):
+        try:
+            return int(name.lstrip("[").rstrip("]"))
+        except ValueError:
+            return -1
+
+    def get_child_at_index(self, index):
+        if index < 0:
+            return None
+        if index >= self.num_children():
+            return None
+        base = self.valobj.GetChildMemberWithName("_storage")
+        offset = index * self.data_size
+        return base.CreateChildAtOffset(
+            f"[{index}]", offset, self.data_type
+        )
+
+
+class HashMapProvider:
+    '''Formatter for Common::HashMap'''
+    def __init__(self, valobj, internal_dict):
+        self.valobj = valobj
+        self.update()
+
+    def update(self):
+        self.children_with_values = []
+        self.size = \
+            self.valobj.GetChildMemberWithName("_size").GetValueAsUnsigned()
+        self.mask = \
+            self.valobj.GetChildMemberWithName("_mask").GetValueAsUnsigned()
+        self.storage = self.valobj.GetChildMemberWithName("_storage")
+        for i in range(self.mask + 1):
+            child = self.storage.GetChildAtIndex(i, lldb.eNoDynamicValues, True)
+            if child.GetValueAsUnsigned() != 0:
+                self.children_with_values.append(child)
+        return False
+
+    def num_children(self, _max_children=None):
+        return self.size
+
+    def has_children(self):
+        return self.size > 0
+
+    def get_child_index(self, name):
+        return next((c for c in self.children_with_values if c.GetName() == name), -1)
+
+    def get_child_at_index(self, index):
+        if index < 0:
+            return None
+        if index >= self.num_children():
+            return None
+
+        return self.children_with_values[index].Dereference()
+
+
+class ListProvider:
+    '''Formatter for Common::List'''
+    def __init__(self, valobj, internal_dict):
+        self.valobj = valobj
+        self.element_type = self.valobj.GetType().GetTemplateArgumentType(0)
+        self.node_offset = self.valobj.GetType().FindDirectNestedType("NodeBase").GetByteSize()
+        self.update()
+
+    def update(self):
+        self.anchor = self.valobj.GetChildMemberWithName("_anchor")
+
+        self.size = 0
+        cur = self.anchor
+        while True:
+            cur = cur.GetChildMemberWithName("_next").Dereference()
+            if cur.AddressOf().GetValueAsUnsigned() == self.anchor.AddressOf().GetValueAsUnsigned():
+                break
+            self.size = self.size + 1
+        return False
+
+    def num_children(self, _max_children=None):
+        return self.size
+
+    def has_children(self):
+        _prev = self.anchor.GetChildMemberWithName("_prev").GetValueAsUnsigned()
+        _next = self.anchor.AddressOf().GetValueAsUnsigned()
+        return _prev != _next
+
+    def get_child_index(self, name):
+        try:
+            return int(name.lstrip("[").rstrip("]"))
+        except:
+            return -1
+
+    def get_child_at_index(self, index):
+        if index < 0 or index >= self.size:
+            return None
+
+        cur = self.anchor
+        for _ in range(index):
+            cur = cur.GetChildMemberWithName("_next").Dereference()
+
+        return cur.CreateChildAtOffset(f'[{index}]', self.node_offset, self.element_type)
+
+
+def array_summary(valobj, internal):
+    size = valobj.GetNonSyntheticValue().GetChildMemberWithName('_size').GetValueAsUnsigned()
+    if size == 0:
+        return "(empty)"
+    if size == 1:
+        return "1 item"
+    return f"{size} items"
+
+
+def construct_matrix_summary(rows, cols):
+    lines = []
+    for r in range(rows):
+        line = " ".join(f'${{var._values[{r*cols+c}]}}' for c in range(cols))
+        lines.append(line)
+    return '[' + "; ".join(lines) + ']'
+
+ at dataclass(frozen=True)
+class Pattern:
+    pattern: str
+
+summaries = {
+    'Common::String': r'${var._str%s}',
+
+    'Common::Rect': r'(${var.left},${var.top}) -> (${var.right}, ${var.bottom})',
+    'Math::Vector2d': r'(${var._values[0]}, ${var._values[1]})',
+    'Math::Vector3d': r'(${var._values[0]}, ${var._values[1]}, ${var._values[2]})',
+    'Math::Vector4d': r'(${var._values[0]}, ${var._values[1]}, ${var._values[2]}, ${var._values[3]})',
+    'Math::Quaternion': r'(${var._values[0]}, ${var._values[1]}, ${var._values[2]}, ${var._values[3]})',
+    'Math::Matrix4': construct_matrix_summary(4,4),
+    'Math::Matrix3': construct_matrix_summary(3,3),
+
+    'Graphics::Surface': r'(${var.w},${var.h}) (bpp=${var.format.bytesPerPixel:d})',
+    Pattern('^Common::HashMap<.*>::Node'): r'\{key: ${var._key}, value: ${var._value}\}',
+    Pattern('^Common::Array<.*>$'): array_summary,
+    Pattern('^Common::List<.*>$'): r'${svar%#} items',
+}
+
+providers = {
+    Pattern('^Common::Array<.*>$'): ArrayProvider,
+    Pattern('^Common::HashMap<.*>$'): HashMapProvider,
+    Pattern('^Common::List<.*>$'): ListProvider,
+}
+
+
+def __lldb_init_module(debugger, unused):
+    #lldb.formatters.Logger._lldb_formatters_debug_level = 2
+    print('Loading ScummVM formatters...')
+    for klass, summary in summaries.items():
+        if callable(summary):
+            summary = f'-F {__name__}.{summary.__name__}'
+        else:
+            summary = f'--summary-string "{summary}"'
+
+        if isinstance(klass, Pattern):
+            debugger.HandleCommand(
+                f'type summary add -x "{klass.pattern}" --category scummvm {summary}'
+            )
+        else:
+            debugger.HandleCommand(
+                f'type summary add "{klass}" --category scummvm {summary}'
+            )
+
+    for klass, provider in providers.items():
+        debugger.HandleCommand(
+            f'type synthetic add -x --category scummvm --python-class {__name__}.{provider.__name__} "{klass.pattern}"'
+        )
+
+    debugger.HandleCommand(
+        r'type category enable scummvm'
+    )




More information about the Scummvm-git-logs mailing list