Skip to content

[gdb] Complete stubs for gdb.dap #14269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions stubs/gdb/@tests/stubtest_allowlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,3 @@ gdb.Progspace.xmethods

# stubtest thinks this can't be sub-classed at runtime, but it is
gdb.disassembler.DisassemblerPart

# incomplete modules
gdb\.dap\.[a-z_]+\.[A-Za-z_]+
10 changes: 8 additions & 2 deletions stubs/gdb/gdb/__init__.pyi
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import threading
from _typeshed import Incomplete
from collections.abc import Callable, Iterator, Mapping, Sequence
from contextlib import AbstractContextManager
from typing import Any, Final, Generic, Literal, Protocol, TypeVar, final, overload, type_check_only
from typing import Any, Final, Generic, Literal, Protocol, TypedDict, TypeVar, final, overload, type_check_only
from typing_extensions import TypeAlias, deprecated

import gdb.FrameDecorator
Expand Down Expand Up @@ -860,10 +860,16 @@ class LazyString:

# Architectures

@type_check_only
class _Instruction(TypedDict):
addr: int
asm: str
length: int

@final
class Architecture:
def name(self) -> str: ...
def disassemble(self, start_pc: int, end_pc: int = ..., count: int = ...) -> list[dict[str, object]]: ...
def disassemble(self, start_pc: int, end_pc: int = ..., count: int = ...) -> list[_Instruction]: ...
def integer_type(self, size: int, signed: bool = ...) -> Type: ...
def registers(self, reggroup: str = ...) -> RegisterDescriptorIterator: ...
def register_groups(self) -> RegisterGroupsIterator: ...
Expand Down
24 changes: 16 additions & 8 deletions stubs/gdb/gdb/dap/__init__.pyi
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
from typing import Any

class Server:
def __init__(self, in_stream, out_stream, child_stream) -> None: ...
def main_loop(self) -> None: ...
def send_event(self, event: str, body: Any | None = None) -> None: ... # body is an arbitrary object
def send_event_later(self, event: str, body: Any | None = None) -> None: ... # body is an arbitrary object
def shutdown(self) -> None: ...
from . import (
breakpoint as breakpoint,
bt as bt,
evaluate as evaluate,
launch as launch,
locations as locations,
memory as memory,
modules as modules,
next as next,
pause as pause,
scopes as scopes,
sources as sources,
startup as startup,
threads as threads,
)
from .server import Server as Server

def pre_command_loop() -> None: ...
def run() -> None: ...
Expand Down
50 changes: 49 additions & 1 deletion stubs/gdb/gdb/dap/breakpoint.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,49 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Incomplete, Unused
from collections.abc import Sequence
from contextlib import AbstractContextManager
from typing import TypedDict, type_check_only
from typing_extensions import NotRequired

import gdb

from .sources import Source

@type_check_only
class _SourceBreakpoint(TypedDict):
source: str
line: int
condition: NotRequired[str | None]
hitCondition: NotRequired[str | None]
logMessage: NotRequired[str | None]

@type_check_only
class _ExceptionFilterOptions(TypedDict):
filderId: str
condition: NotRequired[str | None]

@type_check_only
class _BreakpointDescriptor(TypedDict):
id: int
verified: bool
reason: NotRequired[str] # only present when verified is False. Possibly only literal "pending" or "failed"
message: NotRequired[str] # only present when reason == "failed"
source: NotRequired[Source]
line: NotRequired[int]
instructionReference: NotRequired[str]

@type_check_only
class _SetBreakpointResult(TypedDict):
breakpoints: list[_BreakpointDescriptor]

# frozenset entries are tuples from _SourceBreakpoint.items() or _ExceptionFilterOptions.items()
breakpoint_map: dict[str, dict[frozenset[Incomplete], gdb.Breakpoint]]

def suppress_new_breakpoint_event() -> AbstractContextManager[None]: ...
def set_breakpoint(*, source: Source, breakpoints: Sequence[_SourceBreakpoint] = (), **args: Unused) -> _SetBreakpointResult: ...
def set_fn_breakpoint(*, breakpoints: Sequence[_SourceBreakpoint], **args: Unused) -> _SetBreakpointResult: ...
def set_insn_breakpoints(
*, breakpoints: Sequence[_SourceBreakpoint], offset: int | None = None, **args: Unused
) -> _SetBreakpointResult: ...
def set_exception_breakpoints(
*, filters: Sequence[str], filterOptions: Sequence[_ExceptionFilterOptions] = (), **args: Unused
) -> _SetBreakpointResult: ...
49 changes: 48 additions & 1 deletion stubs/gdb/gdb/dap/bt.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,48 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import TypedDict, type_check_only
from typing_extensions import NotRequired

from .sources import Source
from .varref import ValueFormat

@type_check_only
class _StackFrameFormat(ValueFormat, total=False):
parameters: bool
parameterTypes: bool
parameterNames: bool
parameterValues: bool
line: bool
module: bool
includeAll: bool

@type_check_only
class _StackFrame(TypedDict):
id: int
name: str
line: int
column: int
instructionPointerReference: str
moduleId: NotRequired[str | None]
source: NotRequired[Source]

class _StaceTraceResult(TypedDict):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to verify: Should this be annotated with @type_check_only as well?

stackFrames: list[_StackFrame]

def check_stack_frame(
*,
# From source:
# Note that StackFrameFormat extends ValueFormat, which is why
# "hex" appears here.
hex: bool = False,
parameters: bool = False,
parameterTypes: bool = False,
parameterNames: bool = False,
parameterValues: bool = False,
line: bool = False,
module: bool = False,
includeAll: bool = False,
**rest: Unused,
) -> _StackFrameFormat: ...
def stacktrace(
*, levels: int = 0, startFrame: int = 0, threadId: int, format: _StackFrameFormat | None = None, **extra: Unused
) -> _StaceTraceResult: ...
23 changes: 22 additions & 1 deletion stubs/gdb/gdb/dap/disassemble.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,22 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import TypedDict, type_check_only
from typing_extensions import NotRequired

from .sources import Source

@type_check_only
class _Instruction(TypedDict):
address: str
instruction: str
instructionBytes: str
symbol: NotRequired[str] # only set if there's a corresponding label
line: NotRequired[int] # only set if source is available
location: NotRequired[Source] # only set if source is available

@type_check_only
class _DisassembleResult(TypedDict):
instructions: list[_Instruction]

def disassemble(
*, memoryReference: str, offset: int = 0, instructionOffset: int = 0, instructionCount: int, **extra: Unused
) -> _DisassembleResult: ...
32 changes: 31 additions & 1 deletion stubs/gdb/gdb/dap/evaluate.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,31 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import Literal, TypedDict, type_check_only

import gdb

from .varref import ValueFormat, VariableReference, VariableReferenceDescriptor

class EvaluateResult(VariableReference):
def __init__(self, value: gdb.Value) -> None: ...

@type_check_only
class _VariablesResult(TypedDict):
variables: list[VariableReferenceDescriptor]

def eval_request(
*,
expression: str,
frameId: int | None = None,
context: Literal["watch", "variables", "hover", "repl"] = "variables",
format: ValueFormat | None = None,
**args: Unused,
) -> VariableReferenceDescriptor: ...
def variables(
*, variablesReference: int, start: int = 0, count: int = 0, format: ValueFormat | None = None, **args: Unused
) -> _VariablesResult: ...
def set_expression(
*, expression: str, value: str, frameId: int | None = None, format: ValueFormat | None = None, **args: Unused
) -> VariableReferenceDescriptor: ...
def set_variable(
*, variablesReference: int, name: str, value: str, format: ValueFormat | None = None, **args: Unused
) -> VariableReferenceDescriptor: ...
13 changes: 12 additions & 1 deletion stubs/gdb/gdb/dap/events.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,12 @@
def __getattr__(name: str): ... # incomplete module
import gdb

inferior_running: bool

def send_process_event_once() -> None: ...
def expect_process(reason: str) -> None: ...
def thread_event(event: gdb.ThreadEvent, reason: str) -> None: ...
def expect_stop(reason: str) -> None: ...
def exec_and_expect_stop(cmd: str, expected_pause: bool = False) -> None: ...

# Map from gdb stop reasons to DAP stop reasons.
stop_reason_map: dict[str, str]
8 changes: 7 additions & 1 deletion stubs/gdb/gdb/dap/frames.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
def __getattr__(name: str): ... # incomplete module
from collections.abc import Generator

import gdb

def frame_for_id(id: int) -> gdb.Frame: ...
def select_frame(id: int) -> None: ...
def dap_frame_generator(frame_low: int, levels: int, include_all: bool) -> Generator[tuple[int, gdb.Frame]]: ...
10 changes: 9 additions & 1 deletion stubs/gdb/gdb/dap/io.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
def __getattr__(name: str): ... # incomplete module
from typing import Any, BinaryIO

import gdb

from .server import _JSONValue
from .startup import DAPQueue

def read_json(stream: BinaryIO) -> Any: ... # returns result of json.loads
def start_json_writer(stream: BinaryIO, queue: DAPQueue[_JSONValue]) -> gdb.Thread: ...
Comment on lines +8 to +9
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use a protocol (potentially an already existing one from _typeshed) instead of the semi-deprecated BinaryIO here?

15 changes: 14 additions & 1 deletion stubs/gdb/gdb/dap/launch.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from collections.abc import Mapping, Sequence

def launch(
*,
program: str | None = None,
cwd: str | None = None,
args: Sequence[str] = (),
env: Mapping[str, str] | None = None,
stopAtBeginningOfMainSubprogram: bool = False,
**extra: Unused,
): ...
def attach(*, program: str | None = None, pid: int | None = None, target: str | None = None, **args: Unused) -> None: ...
def config_done(**args: Unused) -> None: ...
17 changes: 16 additions & 1 deletion stubs/gdb/gdb/dap/locations.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,16 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import TypedDict, type_check_only

from .sources import Source

@type_check_only
class _Line(TypedDict):
line: int

@type_check_only
class _BreakpointLocationsResult(TypedDict):
breakpoints: list[_Line]

def breakpoint_locations(
*, source: Source, line: int, endLine: int | None = None, **extra: Unused
) -> _BreakpointLocationsResult: ...
11 changes: 10 additions & 1 deletion stubs/gdb/gdb/dap/memory.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,10 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import TypedDict, type_check_only

@type_check_only
class _ReadMemoryResult(TypedDict):
address: str
data: str

def read_memory(*, memoryReference: str, offset: int = 0, count: int, **extra: Unused) -> _ReadMemoryResult: ...
def write_memory(*, memoryReference: str, offset: int = 0, data: str, **extra: Unused): ...
22 changes: 21 additions & 1 deletion stubs/gdb/gdb/dap/modules.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,21 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import TypedDict, type_check_only
from typing_extensions import NotRequired

import gdb

@type_check_only
class _Module(TypedDict):
id: str | None
name: str | None
path: NotRequired[str | None]

@type_check_only
class _ModulesResult(TypedDict):
modules: list[_Module]
totalModules: int

def module_id(objfile: gdb.Objfile) -> str | None: ...
def is_module(objfile: gdb.Objfile) -> bool: ...
def make_module(objf: gdb.Objfile) -> _Module: ...
def modules(*, startModule: int = 0, moduleCount: int = 0, **args: Unused) -> _ModulesResult: ...
15 changes: 14 additions & 1 deletion stubs/gdb/gdb/dap/next.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,14 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from typing import Literal, TypedDict, type_check_only
from typing_extensions import TypeAlias

@type_check_only
class _ContinueRequestResult(TypedDict):
allThreadsContinued: bool

_Granularity: TypeAlias = Literal["statement", "instruction"]

def next(*, threadId: int, singleThread: bool = False, granularity: _Granularity = "statement", **args: Unused) -> None: ...
def step_in(*, threadId: int, singleThread: bool = False, granularity: _Granularity = "statement", **args: Unused) -> None: ...
def step_out(*, threadId: int, singleThread: bool = False, **args: Unused): ...
def continue_request(*, threadId: int, singleThread: bool = False, **args: Unused) -> _ContinueRequestResult: ...
4 changes: 3 additions & 1 deletion stubs/gdb/gdb/dap/pause.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused

def pause(**args: Unused) -> None: ...
48 changes: 47 additions & 1 deletion stubs/gdb/gdb/dap/scopes.pyi
Original file line number Diff line number Diff line change
@@ -1 +1,47 @@
def __getattr__(name: str): ... # incomplete module
from _typeshed import Unused
from collections.abc import Iterable
from typing import TypedDict, type_check_only
from typing_extensions import NotRequired

import gdb

from ..FrameDecorator import FrameDecorator, SymValueWrapper
from .varref import BaseReference, ReferenceDescriptor

frame_to_scope: dict[int, _ScopeReference]

@type_check_only
class _ScopeReferenceDescriptor(ReferenceDescriptor):
presentationHint: str
expensive: bool
namedVariables: int
line: NotRequired[int]

@type_check_only
class _ScopesResult(TypedDict):
scopes: list[_ScopeReferenceDescriptor]

def clear_scopes(event: Unused) -> None: ...
def set_finish_value(val: gdb.Value) -> None: ...
def symbol_value(sym: SymValueWrapper, frame: FrameDecorator) -> tuple[str, gdb.Value]: ...

class _ScopeReference(BaseReference):
hint: str
frame: FrameDecorator
inf_frame: gdb.Frame
function: str | None
line: int | None
var_list: tuple[SymValueWrapper, ...]
def __init__(self, name: str, hint: str, frame: FrameDecorator, var_list: Iterable[SymValueWrapper]) -> None: ...
def to_object(self) -> _ScopeReferenceDescriptor: ...
def has_children(self) -> bool: ...
def child_count(self) -> int: ...
# note: parameter named changed from 'index' to 'idx'
def fetch_one_child(self, idx: int) -> tuple[str, gdb.Value]: ...

class _FinishScopeReference(_ScopeReference): ...

class _RegisterReference(_ScopeReference):
def __init__(self, name: str, frame: FrameDecorator) -> None: ...

def scopes(*, frameId: int, **extra: Unused) -> _ScopesResult: ...
Loading