Skip to content

Commit 18d27d7

Browse files
authored
Fixes for gdb stubs (#13169)
* gdb: Clarify a comment * gdb: Fix gdb.unwinder.Unwinder.__call__ argument. It takes a gdb.PendingFrame, not a gdb.Frame. * gdb: Unwinders may implement a proto without subclassing gdb.unwinder.Unwinder * gdb: Fix Breakpoint.__init__ 1. `line` should be `int|str`, not just `int` (IDK what a string means, but that it can be a string is clear if you read py-breakpoint.c:bppy_init(). 2. `type` argument should be able to be passed to the "location" form, not just the "spec" form, even if https://sourceware.org/gdb/current/onlinedocs/gdb.html/Breakpoints-In-Python.html neglects to mention it (don't worry, I'll be submitting a patch to fix the doc soon). 3. Fix the positional argument order (based on GDB's sources, it isn't really documented) 4. Use more `@overloads` to enforce that at least 1 of `function`, `label`, or `line` are given in the location form.
1 parent fcf30cf commit 18d27d7

File tree

3 files changed

+129
-13
lines changed

3 files changed

+129
-13
lines changed

stubs/gdb/METADATA.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
version = "15.0.*"
2-
# This is the official web portal for GDB,
2+
# This is the official web portal for the GDB Git repo,
33
# see https://sourceware.org/gdb/current/ for other ways of obtaining the source code.
44
upstream_repository = "https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;a=tree"
55
extra_description = """\

stubs/gdb/gdb/__init__.pyi

Lines changed: 126 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@ import threading
77
from _typeshed import Incomplete
88
from collections.abc import Callable, Iterator, Mapping, Sequence
99
from contextlib import AbstractContextManager
10-
from typing import Any, Final, Generic, Literal, Protocol, TypeVar, final, overload
10+
from typing import Any, Final, Generic, Literal, Protocol, TypeVar, final, overload, type_check_only
1111
from typing_extensions import TypeAlias, deprecated
1212

1313
import gdb.FrameDecorator
1414
import gdb.types
15-
import gdb.unwinder
1615
import gdb.xmethod
1716

1817
# The following submodules are automatically imported
@@ -289,7 +288,15 @@ class PendingFrame:
289288
class UnwindInfo:
290289
def add_saved_register(self, reg: str | RegisterDescriptor | int, value: Value, /) -> None: ...
291290

292-
frame_unwinders: list[gdb.unwinder.Unwinder]
291+
@type_check_only
292+
class _Unwinder(Protocol):
293+
@property
294+
def name(self) -> str: ...
295+
enabled: bool
296+
297+
def __call__(self, pending_frame: PendingFrame) -> UnwindInfo | None: ...
298+
299+
frame_unwinders: list[_Unwinder]
293300

294301
# Inferiors
295302

@@ -468,7 +475,7 @@ class Progspace:
468475
pretty_printers: list[_PrettyPrinterLookupFunction]
469476
type_printers: list[gdb.types._TypePrinter]
470477
frame_filters: dict[str, _FrameFilter]
471-
frame_unwinders: list[gdb.unwinder.Unwinder]
478+
frame_unwinders: list[_Unwinder]
472479
missing_debug_handlers: Incomplete
473480

474481
def block_for_pc(self, pc: int, /) -> Block | None: ...
@@ -493,7 +500,7 @@ class Objfile:
493500
pretty_printers: list[_PrettyPrinterLookupFunction]
494501
type_printers: list[gdb.types._TypePrinter]
495502
frame_filters: dict[str, _FrameFilter]
496-
frame_unwinders: list[gdb.unwinder.Unwinder]
503+
frame_unwinders: list[_Unwinder]
497504
is_file: bool
498505

499506
def is_valid(self) -> bool: ...
@@ -664,21 +671,131 @@ class LineTable:
664671
# Breakpoints
665672

666673
class Breakpoint:
674+
675+
# The where="spec" form of __init__(). See py-breakpoints.c:bppy_init():keywords for the positional order.
676+
@overload
677+
def __init__(
678+
self,
679+
# where
680+
spec: str,
681+
# options
682+
type: int = ...,
683+
wp_class: int = ...,
684+
internal: bool = ...,
685+
temporary: bool = ...,
686+
qualified: bool = ...,
687+
) -> None: ...
688+
689+
# The where="location" form of __init__(). A watchpoint (`type=BP_WATCHPOINT`) cannot be created with this form.
690+
#
691+
# We exclude the `wp_class` (watchpoint class) option here, even though py-breakpoints.c accepts it. It doesn't make sense
692+
# unless type==BP_WATCHPOINT, and is silently ignored in those cases; allowing it in those cases is likely an oversight, not
693+
# an intentional allowance.
694+
#
695+
# We repeat this 7 times because the type system doesn't have simple a way for us to say "at least one of `function`, `label`,
696+
# or `line`", so we must repeat it for each combination of the 3.
697+
#
698+
# The len=3 combination.
699+
@overload
700+
def __init__(
701+
self,
702+
*,
703+
# where
704+
source: str = ...,
705+
function: str,
706+
label: str,
707+
line: int | str,
708+
# options
709+
type: int = ...,
710+
internal: bool = ...,
711+
temporary: bool = ...,
712+
qualified: bool = ...,
713+
) -> None: ...
714+
# The 3 len=2 combinations.
715+
@overload
716+
def __init__(
717+
self,
718+
*,
719+
source: str = ...,
720+
# where
721+
label: str,
722+
line: int | str,
723+
# options
724+
type: int = ...,
725+
internal: bool = ...,
726+
temporary: bool = ...,
727+
qualified: bool = ...,
728+
) -> None: ...
729+
@overload
730+
def __init__(
731+
self,
732+
*,
733+
source: str = ...,
734+
# where
735+
function: str,
736+
line: int | str,
737+
# options
738+
type: int = ...,
739+
internal: bool = ...,
740+
temporary: bool = ...,
741+
qualified: bool = ...,
742+
) -> None: ...
667743
@overload
668744
def __init__(
669-
self, spec: str, type: int = ..., wp_class: int = ..., internal: bool = ..., temporary: bool = ..., qualified: bool = ...
745+
self,
746+
*,
747+
source: str = ...,
748+
# where
749+
function: str,
750+
label: str,
751+
# options
752+
type: int = ...,
753+
internal: bool = ...,
754+
temporary: bool = ...,
755+
qualified: bool = ...,
670756
) -> None: ...
757+
# The 3 len=1 combinations.
671758
@overload
672759
def __init__(
673760
self,
761+
*,
674762
source: str = ...,
675-
function: str = ...,
676-
label: str = ...,
677-
line: int = ...,
763+
# where
764+
function: str,
765+
# options
766+
type: int = ...,
678767
internal: bool = ...,
679768
temporary: bool = ...,
680769
qualified: bool = ...,
681770
) -> None: ...
771+
@overload
772+
def __init__(
773+
self,
774+
*,
775+
source: str = ...,
776+
# where
777+
label: str,
778+
# options
779+
type: int = ...,
780+
internal: bool = ...,
781+
temporary: bool = ...,
782+
qualified: bool = ...,
783+
) -> None: ...
784+
@overload
785+
def __init__(
786+
self,
787+
*,
788+
source: str = ...,
789+
# where
790+
line: int | str,
791+
# options
792+
type: int = ...,
793+
internal: bool = ...,
794+
temporary: bool = ...,
795+
qualified: bool = ...,
796+
) -> None: ...
797+
798+
# Methods.
682799
def stop(self) -> bool: ...
683800
def is_valid(self) -> bool: ...
684801
def delete(self) -> None: ...

stubs/gdb/gdb/unwinder.pyi

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import gdb
2-
from gdb import Frame, UnwindInfo
32

43
class FrameId:
54
def __init__(self, sp: gdb.Value | int, pc: gdb.Value | int, special: gdb.Value | int | None = None) -> None: ...
@@ -16,6 +15,6 @@ class Unwinder:
1615
enabled: bool
1716

1817
def __init__(self, name: str) -> None: ...
19-
def __call__(self, pending_frame: Frame) -> UnwindInfo | None: ...
18+
def __call__(self, pending_frame: gdb.PendingFrame) -> gdb.UnwindInfo | None: ...
2019

21-
def register_unwinder(locus: gdb.Objfile | gdb.Progspace | None, unwinder: Unwinder, replace: bool = ...) -> None: ...
20+
def register_unwinder(locus: gdb.Objfile | gdb.Progspace | None, unwinder: gdb._Unwinder, replace: bool = ...) -> None: ...

0 commit comments

Comments
 (0)