[Lldb-commits] [lldb] [lldb] Update formatter_bytecode.py to ABI version 2 (PR #229923)
Dave Lee via lldb-commits
lldb-commits at lists.llvm.org
Wed Oct 7 18:48:30 PDT 2026
https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/229923
>From 03c56def2bd951d50cca2062383ee4dac12bdc7d Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Sun, 4 Oct 2026 07:13:52 -0700
Subject: [PATCH 1/4] [lldb] Update formatter_bytecode.py to ABI version 2
Update the assembler and the Python to bytecode compiler to target the version
2 formatter ABI, in which `self` is a Dictionary owned by LLDB and passed as
the first argument to every synthetic method.
The primary feature of this change is the separation of storage, locals are on
the stack, attributes are stored in the `self` Dictionary. Since locals and
attrs no longer intermingle in the stack, local variables are now allowed in
`__init__` and `update`, and attributes can be reassigned.
In the compiler:
* `self.x = expr` is compiled to `0 pick "x" <expr> dict_set`
* `self.x` is compiled to `0 pick "x" dict_get`
* Arguments and local variables are on the stack above `self`
* An `__init__` that only stores `valobj` is not emitted, since this is
what LLDB does when there is no `@init`
Assisted-by: claude
---
lldb/examples/python/formatter_bytecode.py | 222 +++++++++++++-----
.../RigidArrayLLDBFormatterC.txt | 16 +-
.../RigidArrayLLDBFormatterSwift.txt | 18 +-
3 files changed, 180 insertions(+), 76 deletions(-)
diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index 188f18a351189d..7b1cae4d5f411c 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -25,7 +25,7 @@
from dataclasses import dataclass
from typing import Any, BinaryIO, Optional, Sequence, TextIO, Tuple, Union, cast
-BINARY_VERSION = 1
+BINARY_VERSION = 2
# Types
type_String = 1
@@ -881,19 +881,18 @@ class Compiler(ast.NodeVisitor):
# Variables
The compiler supports two kinds of variables, local variables and attribute
- variables (properties), but there are limitations on both.
+ variables (properties).
- In __init__ and update, local variables are currently *not* supported, but
- attributes can be assigned to. This matches the common case for these
- functions.
+ Attributes are stored in `self`, which in the version 2 ABI is a Dictionary
+ owned by LLDB and passed as the first argument (data[0]) to every synthetic
+ method. Attribute writes (`self.x = expr`) are lowered to `dict_set`, and
+ attribute reads (`self.x`) are lowered to `dict_get`. Attributes can only
+ be assigned to in __init__ and update, which matches the common case.
- In all other function bodies, local variables _are_ supported, but
- attributes can only be read from, *not* assigned to. This also matches the
- common case for these functions.
-
- Variables (local and attributes) are tracked, allowing the compiler to know
- their position in the stack. Variable reads can then be lowered to `pick`
- instructions. See the compiler's `locals` and `attrs` attributes.
+ Local variables (including method arguments) live on the data stack, above
+ `self`. They are tracked, allowing the compiler to know their position in
+ the stack. Local variable reads are then lowered to `pick` instructions.
+ See the compiler's `locals` and `locals_base` attributes.
# Functions
@@ -909,11 +908,13 @@ class Compiler(ast.NodeVisitor):
# oldest/deepest; locals[-1] is the most recently pushed.
locals: list[str]
- # Names of visible attrs in bottom-to-top stack order. Always holds the
- # full combined frame for the method being compiled: grows incrementally
- # during __init__/update, and is set to the combined list before getter
- # methods are compiled.
- attrs: list[str]
+ # Stack index of locals[0]. In synthetic methods, data[0] holds `self`, so
+ # locals start at 1. In top-level functions (summaries), locals start at 0.
+ locals_base: int
+
+ # Names of attrs known to be stored in `self`. Grows during __init__ and
+ # update, which are compiled before the getter methods.
+ attrs: set[str]
# Bytecode signature of the method being compiled, or None for top-level
# functions.
@@ -923,7 +924,8 @@ class Compiler(ast.NodeVisitor):
def __init__(self) -> None:
self.locals = []
- self.attrs = []
+ self.locals_base = 0
+ self.attrs = set()
self.current_sig = None
self.buffer = io.StringIO()
@@ -943,11 +945,16 @@ def visit_ClassDef(self, node: ast.ClassDef) -> None:
raise CompilerError(f"unsupported method: {item.name}", item)
methods[item.name] = item
- self.attrs = []
+ self.attrs = set()
+
if method := methods.get("__init__"):
self._compile_method(method)
- # self.attrs now holds init's attrs. update's attrs are appended above
- # them, so after update self.attrs is the combined init+update list.
+ else:
+ # Without an @init, LLDB stores the value in self["valobj"].
+ self.attrs.add("valobj")
+
+ # update is compiled next, so that self.attrs holds all assigned attrs
+ # before the getter methods are compiled.
if method := methods.get("update"):
self._compile_method(method)
@@ -973,6 +980,7 @@ def _compile_method(self, node: ast.FunctionDef) -> None:
args.pop() # drop trailing 'internal_dict'
self.locals = [arg.arg for arg in args]
+ self.locals_base = 1
# Compile into a temporary buffer so the signature line can be
# emitted first.
@@ -992,8 +1000,9 @@ def _compile_method(self, node: ast.FunctionDef) -> None:
def visit_FunctionDef(self, node: ast.FunctionDef) -> None:
# Top-level function (not inside a class).
self.current_sig = None
- self.attrs = []
+ self.attrs = set()
self.locals = [arg.arg for arg in node.args.args]
+ self.locals_base = 0
self._visit_each(node.body)
self.locals.clear()
@@ -1068,33 +1077,16 @@ def visit_Assign(self, node: ast.Assign) -> None:
node,
)
+ # self[attr] = value
attr = target.attr
- if attr in self.attrs:
- raise CompilerError(f"attribute '{attr}' is already assigned", node)
-
- # If the RHS is an argument (the only kind of local permitted in
- # __init__) - then it is already on the stack in place, and no
- # evaluation is needed.
- is_arg = (
- isinstance(node.value, ast.Name)
- and self._local_index(node.value) is not None
- )
- if not is_arg:
- # Evaluate the RHS, leaving its value on the stack.
- self.visit(node.value)
-
- # Record the attr.
- self.attrs.append(attr)
+ self._output("0 pick")
+ self._output(f'"{attr}"')
+ self.visit(node.value)
+ self._output("dict_set")
+ self.attrs.add(attr)
return
# Handle local variable assignment.
- if self.current_sig in ("@init", "@update"):
- raise CompilerError(
- "local variable assignment is not allowed in __init__ or update; "
- "use attribute assignment (self.attr = ...) instead",
- node,
- )
-
if isinstance(target, ast.Name):
names = [target]
elif isinstance(target, ast.Tuple):
@@ -1120,8 +1112,12 @@ def visit_Attribute(self, node: ast.Attribute) -> None:
raise CompilerError(
"unsupported attribute access (only self.attr is supported)", node
)
- pick_idx = self._attr_index(node.attr, node)
- self._output(f"{pick_idx} pick") # "# self.{node.attr}"
+ if node.attr not in self.attrs:
+ raise CompilerError(f"unknown attribute: {node.attr}", node)
+ # self[attr]
+ self._output("0 pick")
+ self._output(f'"{node.attr}"')
+ self._output("dict_get")
def visit_Name(self, node: ast.Name) -> None:
idx = self._local_index(node)
@@ -1133,19 +1129,9 @@ def _visit_each(self, nodes: Sequence[ast.AST]) -> None:
for child in nodes:
self.visit(child)
- def _attr_index(self, name: str, node: ast.expr) -> int:
- # self.attrs is always the full visible attr frame, so the index is
- # the direct pick offset with no further adjustment.
- try:
- return self.attrs.index(name)
- except ValueError:
- raise CompilerError(f"unknown attribute: {name}", node)
-
def _local_index(self, name: ast.Name) -> Optional[int]:
try:
- idx = self.locals.index(name.id)
- # Offset past all attrs.
- return len(self.attrs) + idx
+ return self.locals_base + self.locals.index(name.id)
except ValueError:
return None
@@ -1299,6 +1285,7 @@ def _main():
############################################################################
# Tests.
############################################################################
+ import tempfile
import unittest
class TestAssembler(unittest.TestCase):
@@ -1382,7 +1369,7 @@ def test_write_source(self):
self.assertIn("__attribute__((used, section(FORMATTER_SECTION)))", src)
self.assertIn("unsigned char _Account_formatter[] =", src)
- self.assertIn('"\\x01"', src) # version
+ self.assertIn('// version\n "\\x02"', src) # version
self.assertIn('"\\x15"', src) # record size (21)
self.assertIn('"\\x07"', src) # type name size (7)
self.assertIn('"Account"', src) # type name
@@ -1417,4 +1404,121 @@ def test_write_source(self):
disassemble_file(binary, dis)
self.assertEqual(dis.getvalue(), "@summary: return\n")
+ class TestCompiler(unittest.TestCase):
+
+ class FakeValue:
+ """A minimal stand-in for SBValue."""
+
+ def __init__(self, value=0, children=None):
+ self.value = value
+ self.children = children or {}
+
+ def GetChildMemberWithName(self, name):
+ return self.children[name]
+
+ def GetChildAtIndex(self, idx):
+ return list(self.children.values())[idx]
+
+ def GetSyntheticValue(self):
+ return self
+
+ def GetValueAsUnsigned(self):
+ return self.value
+
+ def compile_methods(self, source):
+ with tempfile.NamedTemporaryFile("w", suffix=".py") as f:
+ f.write(textwrap.dedent(source))
+ f.flush()
+ assembly = Compiler().compile(f.name)
+ section = assemble_file("T", io.StringIO(assembly))
+ return dict(section.signatures)
+
+ def test_synthetic(self):
+ methods = self.compile_methods("""
+ import lldb
+
+ class Synthetic:
+ def __init__(self, valobj, _):
+ self.valobj = valobj
+
+ def update(self) -> bool:
+ self.storage = self.valobj.GetChildMemberWithName("_storage")
+ self.count = self.valobj.GetChildMemberWithName(
+ "_count"
+ ).GetValueAsUnsigned()
+ return True
+
+ def num_children(self):
+ return self.count
+
+ def get_child_at_index(self, idx):
+ if idx < self.count:
+ return self.storage.GetChildAtIndex(idx)
+ return None
+ """)
+
+ FakeValue = self.FakeValue
+ a, b = FakeValue(10), FakeValue(20)
+ valobj = FakeValue(
+ children={
+ "_storage": FakeValue(children={"a": a, "b": b}),
+ "_count": FakeValue(2),
+ }
+ )
+
+ # Without @init, LLDB stores the value in self["valobj"].
+ self_dict = {"valobj": valobj}
+ self.assertEqual(interpret(methods["update"], [], [self_dict]), 1)
+ self.assertEqual(self_dict["count"], 2)
+ self.assertEqual(interpret(methods["get_num_children"], [], [self_dict]), 2)
+ self.assertIs(
+ interpret(methods["get_child_at_index"], [], [self_dict, 1]), b
+ )
+ self.assertIsNone(
+ interpret(methods["get_child_at_index"], [], [self_dict, 2])
+ )
+
+ def test_init(self):
+ methods = self.compile_methods(
+ """
+ class Synthetic:
+ def __init__(self, valobj, _):
+ self.storage = valobj.GetChildMemberWithName("_storage")
+
+ def update(self) -> bool:
+ size = self.storage.GetValueAsUnsigned()
+ self.size = size
+ return False
+
+ def num_children(self):
+ return self.size
+ """
+ )
+ storage = self.FakeValue(3)
+ valobj = self.FakeValue(children={"_storage": storage})
+ self_dict = {}
+ interpret(methods["init"], [], [self_dict, valobj])
+ self.assertIs(self_dict["storage"], storage)
+ self.assertEqual(interpret(methods["update"], [], [self_dict]), 0)
+ self.assertEqual(interpret(methods["get_num_children"], [], [self_dict]), 3)
+
+ def test_errors(self):
+ with self.assertRaisesRegex(CompilerError, "unknown attribute: missing"):
+ self.compile_methods(
+ """
+ class Synthetic:
+ def num_children(self):
+ return self.missing
+ """
+ )
+ with self.assertRaisesRegex(CompilerError, "only allowed in __init__"):
+ self.compile_methods(
+ """
+ class Synthetic:
+ def num_children(self):
+ self.count = 1
+ return 1
+ """
+ )
+
unittest.main(argv=[__file__])
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
index ea6f7c924bd445..09e60e2f1d05ad 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
@@ -8,9 +8,9 @@
__attribute__((used, section(FORMATTER_SECTION)))
unsigned char _RigidArray_formatter[] =
// version
- "\x01"
+ "\x02"
// remaining record size
- "\x4a"
+ "\x86\x01"
// type name size
"\x0a"
// type name
@@ -20,19 +20,19 @@ unsigned char _RigidArray_formatter[] =
// sig_update
"\x06"
// program size
- "\x2a"
+ "\x54"
// program
- "\x24\x00\x03\x22\x08\x5f\x73\x74\x6f\x72\x61\x67\x65\x23\x12\x60\x23\x18\x60\x24\x00\x03\x22\x06\x5f\x63\x6f\x75\x6e\x74\x23\x12\x60\x23\x18\x60\x23\x21\x60\x24\x01\x13"
+ "\x24\x00\x03\x22\x07\x73\x74\x6f\x72\x61\x67\x65\x24\x00\x03\x22\x06\x76\x61\x6c\x6f\x62\x6a\x72\x22\x08\x5f\x73\x74\x6f\x72\x61\x67\x65\x23\x12\x60\x23\x18\x60\x71\x24\x00\x03\x22\x05\x63\x6f\x75\x6e\x74\x24\x00\x03\x22\x06\x76\x61\x6c\x6f\x62\x6a\x72\x22\x06\x5f\x63\x6f\x75\x6e\x74\x23\x12\x60\x23\x18\x60\x23\x21\x60\x71\x24\x01\x13"
// sig_get_num_children
"\x02"
// program size
- "\x04"
+ "\x0c"
// program
- "\x24\x02\x03\x13"
+ "\x24\x00\x03\x22\x05\x63\x6f\x75\x6e\x74\x72\x13"
// sig_get_child_at_index
"\x04"
// program size
- "\x0a"
+ "\x14"
// program
- "\x24\x01\x03\x24\x03\x03\x23\x11\x60\x13"
+ "\x24\x00\x03\x22\x07\x73\x74\x6f\x72\x61\x67\x65\x72\x24\x01\x03\x23\x11\x60\x13"
;
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
index e13aaa75aee0b6..646ac1518c1354 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
@@ -5,11 +5,11 @@
@section(".lldbformatters")
#endif
@used
-let `RigidArray formatter`: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
+let `RigidArray formatter`: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
// version
- 0x01,
+ 0x02,
// remaining record size
- 0x4a,
+ 0x86, 0x01,
// type name size
0x0a,
// type name
@@ -19,20 +19,20 @@ let `RigidArray formatter`: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UI
// sig_update
0x06,
// program size
- 0x2a,
+ 0x54,
// program
- 0x24, 0x00, 0x03, 0x22, 0x08, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x23, 0x12, 0x60, 0x23, 0x18, 0x60, 0x24, 0x00, 0x03, 0x22, 0x06, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x23, 0x12, 0x60, 0x23, 0x18, 0x60, 0x23, 0x21, 0x60, 0x24, 0x01, 0x13,
+ 0x24, 0x00, 0x03, 0x22, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x24, 0x00, 0x03, 0x22, 0x06, 0x76, 0x61, 0x6c, 0x6f, 0x62, 0x6a, 0x72, 0x22, 0x08, 0x5f, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x23, 0x12, 0x60, 0x23, 0x18, 0x60, 0x71, 0x24, 0x00, 0x03, 0x22, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x24, 0x00, 0x03, 0x22, 0x06, 0x76, 0x61, 0x6c, 0x6f, 0x62, 0x6a, 0x72, 0x22, 0x06, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x23, 0x12, 0x60, 0x23, 0x18, 0x60, 0x23, 0x21, 0x60, 0x71, 0x24, 0x01, 0x13,
// sig_get_num_children
0x02,
// program size
- 0x04,
+ 0x0c,
// program
- 0x24, 0x02, 0x03, 0x13,
+ 0x24, 0x00, 0x03, 0x22, 0x05, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, 0x13,
// sig_get_child_at_index
0x04,
// program size
- 0x0a,
+ 0x14,
// program
- 0x24, 0x01, 0x03, 0x24, 0x03, 0x03, 0x23, 0x11, 0x60, 0x13,
+ 0x24, 0x00, 0x03, 0x22, 0x07, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x72, 0x24, 0x01, 0x03, 0x23, 0x11, 0x60, 0x13,
)
#endif
>From 26e03eda356edafd39091fcb2978d70b1ffca9a8 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 7 Oct 2026 16:13:52 -0700
Subject: [PATCH 2/4] formatting
---
lldb/examples/python/formatter_bytecode.py | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index 7b1cae4d5f411c..a0e4b62d95a270 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -1479,8 +1479,7 @@ def get_child_at_index(self, idx):
)
def test_init(self):
- methods = self.compile_methods(
- """
+ methods = self.compile_methods("""
class Synthetic:
def __init__(self, valobj, _):
self.storage = valobj.GetChildMemberWithName("_storage")
@@ -1492,8 +1491,7 @@ def update(self) -> bool:
def num_children(self):
return self.size
- """
- )
+ """)
storage = self.FakeValue(3)
valobj = self.FakeValue(children={"_storage": storage})
self_dict = {}
@@ -1504,21 +1502,17 @@ def num_children(self):
def test_errors(self):
with self.assertRaisesRegex(CompilerError, "unknown attribute: missing"):
- self.compile_methods(
- """
+ self.compile_methods("""
class Synthetic:
def num_children(self):
return self.missing
- """
- )
+ """)
with self.assertRaisesRegex(CompilerError, "only allowed in __init__"):
- self.compile_methods(
- """
+ self.compile_methods("""
class Synthetic:
def num_children(self):
self.count = 1
return 1
- """
- )
+ """)
unittest.main(argv=[__file__])
>From 1a774ef02c658211dec18e5edb59e1dd78fbbbb9 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 7 Oct 2026 16:22:03 -0700
Subject: [PATCH 3/4] formatting
---
lldb/examples/python/formatter_bytecode.py | 25 ++++++++++++++--------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/lldb/examples/python/formatter_bytecode.py b/lldb/examples/python/formatter_bytecode.py
index a0e4b62d95a270..5fca4c7cdee3fc 100644
--- a/lldb/examples/python/formatter_bytecode.py
+++ b/lldb/examples/python/formatter_bytecode.py
@@ -1405,7 +1405,6 @@ def test_write_source(self):
self.assertEqual(dis.getvalue(), "@summary: return\n")
class TestCompiler(unittest.TestCase):
-
class FakeValue:
"""A minimal stand-in for SBValue."""
@@ -1434,7 +1433,8 @@ def compile_methods(self, source):
return dict(section.signatures)
def test_synthetic(self):
- methods = self.compile_methods("""
+ methods = self.compile_methods(
+ """
import lldb
class Synthetic:
@@ -1455,7 +1455,8 @@ def get_child_at_index(self, idx):
if idx < self.count:
return self.storage.GetChildAtIndex(idx)
return None
- """)
+ """
+ )
FakeValue = self.FakeValue
a, b = FakeValue(10), FakeValue(20)
@@ -1479,7 +1480,8 @@ def get_child_at_index(self, idx):
)
def test_init(self):
- methods = self.compile_methods("""
+ methods = self.compile_methods(
+ """
class Synthetic:
def __init__(self, valobj, _):
self.storage = valobj.GetChildMemberWithName("_storage")
@@ -1491,7 +1493,8 @@ def update(self) -> bool:
def num_children(self):
return self.size
- """)
+ """
+ )
storage = self.FakeValue(3)
valobj = self.FakeValue(children={"_storage": storage})
self_dict = {}
@@ -1502,17 +1505,21 @@ def num_children(self):
def test_errors(self):
with self.assertRaisesRegex(CompilerError, "unknown attribute: missing"):
- self.compile_methods("""
+ self.compile_methods(
+ """
class Synthetic:
def num_children(self):
return self.missing
- """)
+ """
+ )
with self.assertRaisesRegex(CompilerError, "only allowed in __init__"):
- self.compile_methods("""
+ self.compile_methods(
+ """
class Synthetic:
def num_children(self):
self.count = 1
return 1
- """)
+ """
+ )
unittest.main(argv=[__file__])
>From 37a9eb12d5751856c4812957bee9b0a28d386737 Mon Sep 17 00:00:00 2001
From: Dave Lee <davelee.com at gmail.com>
Date: Wed, 7 Oct 2026 18:48:04 -0700
Subject: [PATCH 4/4] update tests
---
.../FormatterBytecode/RigidArrayLLDBFormatterC.txt | 8 +++++++-
.../FormatterBytecode/RigidArrayLLDBFormatterSwift.txt | 10 ++++++++--
2 files changed, 15 insertions(+), 3 deletions(-)
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
index 09e60e2f1d05ad..d04785c7791873 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterC.txt
@@ -10,13 +10,19 @@ unsigned char _RigidArray_formatter[] =
// version
"\x02"
// remaining record size
- "\x86\x01"
+ "\x97\x01"
// type name size
"\x0a"
// type name
"RigidArray"
// flags
"\x00"
+ // sig_init
+ "\x01"
+ // program size
+ "\x0f"
+ // program
+ "\x24\x00\x03\x22\x06\x76\x61\x6c\x6f\x62\x6a\x24\x01\x03\x71"
// sig_update
"\x06"
// program size
diff --git a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
index 646ac1518c1354..dff897a965ee3e 100644
--- a/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
+++ b/lldb/test/Shell/ScriptInterpreter/Python/Inputs/FormatterBytecode/RigidArrayLLDBFormatterSwift.txt
@@ -5,17 +5,23 @@
@section(".lldbformatters")
#endif
@used
-let `RigidArray formatter`: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
+let `RigidArray formatter`: (UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8) = (
// version
0x02,
// remaining record size
- 0x86, 0x01,
+ 0x97, 0x01,
// type name size
0x0a,
// type name
0x52, 0x69, 0x67, 0x69, 0x64, 0x41, 0x72, 0x72, 0x61, 0x79,
// flags
0x00,
+ // sig_init
+ 0x01,
+ // program size
+ 0x0f,
+ // program
+ 0x24, 0x00, 0x03, 0x22, 0x06, 0x76, 0x61, 0x6c, 0x6f, 0x62, 0x6a, 0x24, 0x01, 0x03, 0x71,
// sig_update
0x06,
// program size
More information about the lldb-commits
mailing list