summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Estep <sam@samestep.com>2025-07-22 04:31:09 -0400
committerGitHub <noreply@github.com>2025-07-22 08:31:09 +0000
commite6906d65ed5367b46675f97b2a272a52c74b6806 (patch)
tree2897f48a10e7215c92f8ed3eeb16177b7078639e
parent9d47a352960efd71494c7dfa0918debd5b405077 (diff)
Add Python type stubs for LLDB (#7826)
-rw-r--r--source/core/core_lldb.py92
-rw-r--r--typings/README.md5
-rw-r--r--typings/lldb.pyi408
3 files changed, 459 insertions, 46 deletions
diff --git a/source/core/core_lldb.py b/source/core/core_lldb.py
index 25a829675..05ba0a4db 100644
--- a/source/core/core_lldb.py
+++ b/source/core/core_lldb.py
@@ -4,7 +4,7 @@ To use it, add the following line to your ~/.lldbinit file:
command script import /path/to/source/core/core_lldb.py
"""
-import lldb # type: ignore[import]
+import lldb
# Set to True to enable the logger
ENABLE_LOGGING = True
@@ -16,7 +16,7 @@ def log(msg):
lldb.formatters.Logger.Logger() >> msg
-def make_string(F, L):
+def make_string(F: lldb.SBData, L: int) -> str:
strval = ""
G = F.uint8
for X in range(L):
@@ -28,17 +28,17 @@ def make_string(F, L):
# Return the pointer to the data in a Slang::RefPtr
-def get_ref_pointer(valobj):
+def get_ref_pointer(valobj: lldb.SBValue) -> lldb.SBValue:
return valobj.GetNonSyntheticValue().GetChildMemberWithName("pointer")
# Check if a pointer is nullptr
-def is_nullptr(valobj):
+def is_nullptr(valobj: lldb.SBValue) -> bool:
return valobj.GetValueAsUnsigned(0) == 0
# Slang::String summary
-def String_summary(valobj, dict):
+def String_summary(valobj: lldb.SBValue, dict) -> str:
buffer_ptr = get_ref_pointer(valobj.GetChildMemberWithName("m_buffer"))
if is_nullptr(buffer_ptr):
return '""'
@@ -49,7 +49,7 @@ def String_summary(valobj, dict):
# Slang::UnownedStringSlice summary
-def UnownedStringSlice_summary(valobj, dict):
+def UnownedStringSlice_summary(valobj: lldb.SBValue, dict) -> str:
begin = valobj.GetChildMemberWithName("m_begin")
end = valobj.GetChildMemberWithName("m_end")
length = end.GetValueAsUnsigned(0) - begin.GetValueAsUnsigned(0)
@@ -60,8 +60,8 @@ def UnownedStringSlice_summary(valobj, dict):
# Slang::RefPtr synthetic provider
-class RefPtr_synthetic:
- def __init__(self, valobj, dict):
+class RefPtr_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
self.valobj = valobj
def has_children(self):
@@ -71,14 +71,14 @@ class RefPtr_synthetic:
return len(self.children)
def get_child_index(self, name):
- for index in range(self.num_children()):
- if self.children[index].GetName() == name:
- return index
+ for idx in range(self.num_children()):
+ if self.children[idx].GetName() == name:
+ return idx
return -1
- def get_child_at_index(self, index):
- if index >= 0 and index < self.num_children():
- return self.children[index]
+ def get_child_at_index(self, idx):
+ if idx >= 0 and idx < self.num_children():
+ return self.children[idx]
else:
return None
@@ -92,7 +92,7 @@ class RefPtr_synthetic:
# Slang::RefPtr summary
-def RefPtr_summary(valobj, dict):
+def RefPtr_summary(valobj: lldb.SBValue, dict) -> str:
pointer = valobj.GetNonSyntheticValue().GetChildMemberWithName("pointer")
if is_nullptr(pointer):
return "nullptr"
@@ -102,8 +102,8 @@ def RefPtr_summary(valobj, dict):
# Slang::ComPtr synthetic provider
-class ComPtr_synthetic:
- def __init__(self, valobj, dict):
+class ComPtr_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
self.valobj = valobj
def has_children(self):
@@ -113,14 +113,14 @@ class ComPtr_synthetic:
return len(self.children)
def get_child_index(self, name):
- for index in range(self.num_children()):
- if self.children[index].GetName() == name:
- return index
+ for idx in range(self.num_children()):
+ if self.children[idx].GetName() == name:
+ return idx
return -1
- def get_child_at_index(self, index):
- if index >= 0 and index < self.num_children():
- return self.children[index]
+ def get_child_at_index(self, idx):
+ if idx >= 0 and idx < self.num_children():
+ return self.children[idx]
else:
return None
@@ -132,7 +132,7 @@ class ComPtr_synthetic:
# Slang::ComPtr summary
-def ComPtr_summary(valobj, dict):
+def ComPtr_summary(valobj: lldb.SBValue, dict) -> str:
pointer = valobj.GetNonSyntheticValue().GetChildMemberWithName("m_ptr")
if is_nullptr(pointer):
return "nullptr"
@@ -140,8 +140,8 @@ def ComPtr_summary(valobj, dict):
# Slang::Array synthetic provider
-class Array_synthetic:
- def __init__(self, valobj, dict):
+class Array_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
self.valobj = valobj
def has_children(self):
@@ -153,11 +153,11 @@ class Array_synthetic:
def get_child_index(self, name):
return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- if index >= 0 and index < self.num_children():
- offset = index * self.data_size
+ def get_child_at_index(self, idx):
+ if idx >= 0 and idx < self.num_children():
+ offset = idx * self.data_size
return self.buffer.CreateChildAtOffset(
- "[" + str(index) + "]", offset, self.data_type
+ "[" + str(idx) + "]", offset, self.data_type
)
else:
return None
@@ -170,8 +170,8 @@ class Array_synthetic:
# Slang::List synthetic provider
-class List_synthetic:
- def __init__(self, valobj, dict):
+class List_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
self.valobj = valobj
def has_children(self):
@@ -183,11 +183,11 @@ class List_synthetic:
def get_child_index(self, name):
return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- if index >= 0 and index < self.num_children():
- offset = index * self.data_size
+ def get_child_at_index(self, idx):
+ if idx >= 0 and idx < self.num_children():
+ offset = idx * self.data_size
return self.buffer.CreateChildAtOffset(
- "[" + str(index) + "]", offset, self.data_type
+ "[" + str(idx) + "]", offset, self.data_type
)
else:
return None
@@ -200,8 +200,8 @@ class List_synthetic:
# Slang::ShortList synthetic provider
-class ShortList_synthetic:
- def __init__(self, valobj, dict):
+class ShortList_synthetic(lldb.SBSyntheticValueProvider):
+ def __init__(self, valobj: lldb.SBValue, dict):
self.valobj = valobj
def has_children(self):
@@ -213,16 +213,16 @@ class ShortList_synthetic:
def get_child_index(self, name):
return int(name.lstrip("[").rstrip("]"))
- def get_child_at_index(self, index):
- if index >= 0 and index < self.short_count:
- offset = index * self.data_size
+ def get_child_at_index(self, idx):
+ if idx >= 0 and idx < self.short_count:
+ offset = idx * self.data_size
return self.short_buffer.CreateChildAtOffset(
- "[" + str(index) + "]", offset, self.data_type
+ "[" + str(idx) + "]", offset, self.data_type
)
- elif index >= self.short_count and index < self.num_children():
- offset = (index - self.short_count) * self.data_size
+ elif idx >= self.short_count and idx < self.num_children():
+ offset = (idx - self.short_count) * self.data_size
return self.buffer.CreateChildAtOffset(
- "[" + str(index) + "]", offset, self.data_type
+ "[" + str(idx) + "]", offset, self.data_type
)
else:
return None
@@ -236,7 +236,7 @@ class ShortList_synthetic:
self.data_size = self.data_type.GetByteSize()
-def __lldb_init_module(debugger, internal_dict):
+def __lldb_init_module(debugger: lldb.SBDebugger, internal_dict):
if ENABLE_LOGGING:
lldb.formatters.Logger._lldb_formatters_debug_level = 2
diff --git a/typings/README.md b/typings/README.md
new file mode 100644
index 000000000..e7c84043c
--- /dev/null
+++ b/typings/README.md
@@ -0,0 +1,5 @@
+# Python type stubs
+
+This directory holds [Python stub files](https://peps.python.org/pep-0484/#stub-files) to improve the editing experience for Python code in this repo, such as [LLDB data formatters](https://lldb.llvm.org/use/variable.html).
+
+If you use Pyright (e.g. via [Pylance](https://marketplace.visualstudio.com/items?itemName=ms-python.vscode-pylance) in VS Code) then these will be picked up automatically; other tools may require additional configuration to see them.
diff --git a/typings/lldb.pyi b/typings/lldb.pyi
new file mode 100644
index 000000000..5a4eb1522
--- /dev/null
+++ b/typings/lldb.pyi
@@ -0,0 +1,408 @@
+# This file holds (incomplete) Python type stubs for LLDB v19.1.7:
+# https://lldb.llvm.org/python_api.html
+
+# The API includes many docstrings which describe the type signatures of
+# functions, but these are not in a format that can be read by Python
+# type checking tools. This has been requested upstream, but seems to be
+# blocked because SWIG (the tool used to generate the LLDB Python
+# bindings) doees not support generating Python type hints:
+# https://github.com/llvm/llvm-project/issues/79043
+
+# For another example of a project that takes the same approach for LLDB
+# Python types, see the mongo-c-driver repo:
+# https://github.com/mongodb/mongo-c-driver/blob/2.0.2/lldb.pyi
+
+# The classes in this file, along with the members in each class, are
+# listed in the same order as the autogenerated `lldb/__init__.py` file
+# distributed with LLVM:
+# https://packages.debian.org/sid/amd64/python3-lldb-19/filelist
+
+# This file should not impose a maintenance burden, because although not
+# all classes are present and not all methods are fully typed, each
+# present class has all its members listed. As a result, language
+# servers like Pylance don't give spurious errors about missing members,
+# and can simply report types as "unknown" for methods that have not
+# been annotated yet. Thus, when adding a new class to this file, be
+# sure to include all its members, but don't feel required to include
+# types for everything unless you want to.
+
+from typing import Sequence
+
+class SBData:
+ @property
+ def thisown(self): ...
+ def __init__(self, *args): ...
+ def GetAddressByteSize(self): ...
+ def SetAddressByteSize(self, addr_byte_size): ...
+ def Clear(self): ...
+ def __nonzero__(self): ...
+ def __bool__(self): ...
+ def IsValid(self): ...
+ def GetByteSize(self): ...
+ def GetByteOrder(self): ...
+ def SetByteOrder(self, endian): ...
+ def GetFloat(self, error, offset): ...
+ def GetDouble(self, error, offset): ...
+ def GetLongDouble(self, error, offset): ...
+ def GetAddress(self, error, offset): ...
+ def GetUnsignedInt8(self, error, offset): ...
+ def GetUnsignedInt16(self, error, offset): ...
+ def GetUnsignedInt32(self, error, offset): ...
+ def GetUnsignedInt64(self, error, offset): ...
+ def GetSignedInt8(self, error, offset): ...
+ def GetSignedInt16(self, error, offset): ...
+ def GetSignedInt32(self, error, offset): ...
+ def GetSignedInt64(self, error, offset): ...
+ def GetString(self, error, offset): ...
+ def ReadRawData(self, error, offset, buf): ...
+ def GetDescription(self, *args): ...
+ def SetData(self, error, buf, endian, addr_size): ...
+ def SetDataWithOwnership(self, error, buf, endian, addr_size): ...
+ def Append(self, rhs): ...
+ @staticmethod
+ def CreateDataFromCString(endian, addr_byte_size, data): ...
+ @staticmethod
+ def CreateDataFromUInt64Array(endian, addr_byte_size, array): ...
+ @staticmethod
+ def CreateDataFromUInt32Array(endian, addr_byte_size, array): ...
+ @staticmethod
+ def CreateDataFromSInt64Array(endian, addr_byte_size, array): ...
+ @staticmethod
+ def CreateDataFromSInt32Array(endian, addr_byte_size, array): ...
+ @staticmethod
+ def CreateDataFromDoubleArray(endian, addr_byte_size, array): ...
+ def SetDataFromCString(self, data): ...
+ def SetDataFromUInt64Array(self, array): ...
+ def SetDataFromUInt32Array(self, array): ...
+ def SetDataFromSInt64Array(self, array): ...
+ def SetDataFromSInt32Array(self, array): ...
+ def SetDataFromDoubleArray(self, array): ...
+ def __repr__(self) -> str: ...
+ def __len__(self): ...
+ @classmethod
+ def CreateDataFromInt(
+ cls, value, size=None, target=None, ptr_size=None, endian=None
+ ): ...
+ def _make_helper(self, sbdata, getfunc, itemsize): ...
+ def _make_helper_uint8(self): ...
+ def _make_helper_uint16(self): ...
+ def _make_helper_uint32(self): ...
+ def _make_helper_uint64(self): ...
+ def _make_helper_sint8(self): ...
+ def _make_helper_sint16(self): ...
+ def _make_helper_sint32(self): ...
+ def _make_helper_sint64(self): ...
+ def _make_helper_float(self): ...
+ def _make_helper_double(self): ...
+ def _read_all_uint8(self): ...
+ def _read_all_uint16(self): ...
+ def _read_all_uint32(self): ...
+ def _read_all_uint64(self): ...
+ def _read_all_sint8(self): ...
+ def _read_all_sint16(self): ...
+ def _read_all_sint32(self): ...
+ def _read_all_sint64(self): ...
+ def _read_all_float(self): ...
+ def _read_all_double(self): ...
+ @property
+ def uint8(self) -> Sequence[int]: ...
+ @property
+ def uint16(self): ...
+ @property
+ def uint32(self): ...
+ @property
+ def uint64(self): ...
+ @property
+ def sint8(self): ...
+ @property
+ def sint16(self): ...
+ @property
+ def sint32(self): ...
+ @property
+ def sint64(self): ...
+ @property
+ def float(self): ...
+ @property
+ def double(self): ...
+ @property
+ def uint8s(self): ...
+ @property
+ def uint16s(self): ...
+ @property
+ def uint32s(self): ...
+ @property
+ def uint64s(self): ...
+ @property
+ def sint8s(self): ...
+ @property
+ def sint16s(self): ...
+ @property
+ def sint32s(self): ...
+ @property
+ def sint64s(self): ...
+ @property
+ def floats(self): ...
+ @property
+ def doubles(self): ...
+ @property
+ def byte_order(self): ...
+ @property
+ def size(self): ...
+
+class SBDebugger:
+ def HandleCommand(self, command: str) -> None: ...
+
+class SBType:
+ @property
+ def thisown(self): ...
+ def __init__(self, *args): ...
+ def __nonzero__(self): ...
+ def IsValid(self): ...
+ def GetByteSize(self) -> int: ...
+ def GetByteAlign(self): ...
+ def IsPointerType(self): ...
+ def IsReferenceType(self): ...
+ def IsFunctionType(self): ...
+ def IsPolymorphicClass(self): ...
+ def IsArrayType(self): ...
+ def IsVectorType(self): ...
+ def IsTypedefType(self): ...
+ def IsAnonymousType(self): ...
+ def IsScopedEnumerationType(self): ...
+ def IsAggregateType(self): ...
+ def GetPointerType(self): ...
+ def GetPointeeType(self) -> SBType: ...
+ def GetReferenceType(self): ...
+ def GetTypedefedType(self): ...
+ def GetDereferencedType(self): ...
+ def GetUnqualifiedType(self): ...
+ def GetArrayElementType(self) -> SBType: ...
+ def GetArrayType(self, size): ...
+ def GetVectorElementType(self): ...
+ def GetCanonicalType(self): ...
+ def GetEnumerationIntegerType(self): ...
+ def GetBasicType(self, *args): ...
+ def GetNumberOfFields(self): ...
+ def GetNumberOfDirectBaseClasses(self): ...
+ def GetNumberOfVirtualBaseClasses(self): ...
+ def GetFieldAtIndex(self, idx): ...
+ def GetDirectBaseClassAtIndex(self, idx): ...
+ def GetVirtualBaseClassAtIndex(self, idx): ...
+ def GetStaticFieldWithName(self, name): ...
+ def GetEnumMembers(self): ...
+ def GetNumberOfTemplateArguments(self): ...
+ def GetTemplateArgumentType(self, idx): ...
+ def GetTemplateArgumentKind(self, idx): ...
+ def GetFunctionReturnType(self): ...
+ def GetFunctionArgumentTypes(self): ...
+ def GetNumberOfMemberFunctions(self): ...
+ def GetMemberFunctionAtIndex(self, idx): ...
+ def GetModule(self): ...
+ def GetName(self): ...
+ def GetDisplayTypeName(self): ...
+ def GetTypeClass(self): ...
+ def IsTypeComplete(self): ...
+ def GetTypeFlags(self): ...
+ def GetDescription(self, description, description_level): ...
+ def FindDirectNestedType(self, name): ...
+ def __eq__(self, rhs): ...
+ def __ne__(self, rhs): ...
+ def __repr__(self): ...
+ def template_arg_array(self): ...
+ def __len__(self): ...
+ @property
+ def module(self): ...
+ @property
+ def name(self): ...
+ @property
+ def size(self): ...
+ @property
+ def is_pointer(self): ...
+ @property
+ def is_reference(self): ...
+ @property
+ def num_fields(self): ...
+ @property
+ def num_bases(self): ...
+ @property
+ def num_vbases(self): ...
+ @property
+ def num_template_args(self): ...
+ @property
+ def template_args(self): ...
+ @property
+ def type(self): ...
+ @property
+ def is_complete(self): ...
+ def get_bases_array(self): ...
+ def get_vbases_array(self): ...
+ def get_fields_array(self): ...
+ def get_members_array(self): ...
+ def get_enum_members_array(self): ...
+ @property
+ def bases(self): ...
+ @property
+ def vbases(self): ...
+ @property
+ def fields(self): ...
+ @property
+ def members(self): ...
+ @property
+ def enum_members(self): ...
+
+class SBValue:
+ @property
+ def thisown(self): ...
+ def __init__(self, *args): ...
+ def __nonzero__(self): ...
+ def IsValid(self): ...
+ def Clear(self): ...
+ def GetError(self): ...
+ def GetID(self): ...
+ def GetName(self) -> str: ...
+ def GetTypeName(self): ...
+ def GetDisplayTypeName(self): ...
+ def GetByteSize(self): ...
+ def IsInScope(self): ...
+ def GetFormat(self): ...
+ def SetFormat(self, format): ...
+ def GetValue(self) -> str: ...
+ def GetValueAsSigned(self, *args): ...
+ def GetValueAsUnsigned(self, fail_value: int = 0) -> int: ...
+ def GetValueAsAddress(self): ...
+ def GetValueType(self): ...
+ def GetValueDidChange(self): ...
+ def GetSummary(self, *args): ...
+ def GetObjectDescription(self): ...
+ def GetDynamicValue(self, use_dynamic): ...
+ def GetStaticValue(self): ...
+ def GetNonSyntheticValue(self) -> SBValue: ...
+ def GetSyntheticValue(self): ...
+ def GetPreferDynamicValue(self): ...
+ def SetPreferDynamicValue(self, use_dynamic): ...
+ def GetPreferSyntheticValue(self): ...
+ def SetPreferSyntheticValue(self, use_synthetic): ...
+ def IsDynamic(self): ...
+ def IsSynthetic(self): ...
+ def IsSyntheticChildrenGenerated(self): ...
+ def SetSyntheticChildrenGenerated(self, arg2): ...
+ def GetLocation(self): ...
+ def SetValueFromCString(self, *args): ...
+ def GetTypeFormat(self): ...
+ def GetTypeSummary(self): ...
+ def GetTypeFilter(self): ...
+ def GetTypeSynthetic(self): ...
+ def CreateChildAtOffset(self, name: str, offset: int, type: SBType) -> SBValue: ...
+ def Cast(self, type): ...
+ def CreateValueFromExpression(self, *args): ...
+ def CreateValueFromAddress(self, name, address, type): ...
+ def CreateValueFromData(self, name, data, type): ...
+ def GetChildAtIndex(self, *args): ...
+ def GetIndexOfChildWithName(self, name): ...
+ def GetChildMemberWithName(self, name: str) -> SBValue: ...
+ def GetValueForExpressionPath(self, expr_path): ...
+ def AddressOf(self): ...
+ def GetLoadAddress(self): ...
+ def GetAddress(self): ...
+ def GetPointeeData(self, item_idx: int = 0, item_count: int = 1) -> SBData: ...
+ def GetData(self): ...
+ def SetData(self, data, error): ...
+ def Clone(self, new_name): ...
+ def GetDeclaration(self): ...
+ def MightHaveChildren(self): ...
+ def IsRuntimeSupportValue(self): ...
+ def GetNumChildren(self, max: int | None = None) -> int: ...
+ def GetOpaqueType(self): ...
+ def GetTarget(self): ...
+ def GetProcess(self): ...
+ def GetThread(self): ...
+ def GetFrame(self): ...
+ def Dereference(self) -> SBValue: ...
+ def TypeIsPointerType(self): ...
+ def GetType(self) -> SBType: ...
+ def Persist(self): ...
+ def GetDescription(self, description): ...
+ def GetExpressionPath(self, *args): ...
+ def EvaluateExpression(self, *args): ...
+ def Watch(self, *args): ...
+ def WatchPointee(self, resolve_location, read, write, error): ...
+ def GetVTable(self): ...
+ def __repr__(self): ...
+ def __get_dynamic__(self): ...
+ def get_child_access_object(self): ...
+ def get_value_child_list(self): ...
+ def __hex__(self): ...
+ def __iter__(self): ...
+ def __len__(self): ...
+ @property
+ def children(self) -> list[SBValue]: ...
+ @property
+ def child(self): ...
+ @property
+ def name(self): ...
+ @property
+ def type(self): ...
+ @property
+ def size(self): ...
+ @property
+ def is_in_scope(self): ...
+ @property
+ def format(self): ...
+ @property
+ def value(self): ...
+ @property
+ def value_type(self): ...
+ @property
+ def changed(self): ...
+ @property
+ def data(self): ...
+ @property
+ def load_addr(self): ...
+ @property
+ def addr(self): ...
+ @property
+ def deref(self): ...
+ @property
+ def address_of(self): ...
+ @property
+ def error(self): ...
+ @property
+ def summary(self): ...
+ @property
+ def description(self): ...
+ @property
+ def dynamic(self): ...
+ @property
+ def location(self): ...
+ @property
+ def target(self): ...
+ @property
+ def process(self): ...
+ @property
+ def thread(self): ...
+ @property
+ def frame(self): ...
+ @property
+ def num_children(self): ...
+ @property
+ def unsigned(self): ...
+ @property
+ def signed(self): ...
+ def get_expr_path(self): ...
+ @property
+ def path(self): ...
+ def synthetic_child_from_expression(self, name, expr, options=None): ...
+ def synthetic_child_from_data(self, name, data, type): ...
+ def synthetic_child_from_address(self, name, addr, type): ...
+ def __eol_test(val): ...
+ def linked_list_iter(self, next_item_name, end_of_list_test=__eol_test): ...
+
+class SBSyntheticValueProvider:
+ def __init__(self, valobj: SBValue) -> None: ...
+ def num_children(self) -> int: ...
+ def get_child_index(self, name: str) -> int: ...
+ def get_child_at_index(self, idx: int) -> SBValue | None: ...
+ def update(self) -> bool | None: ...
+ def has_children(self) -> bool: ...
+ def __len__(self) -> int: ...
+ def __iter__(self): ...