Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d78ce59

Browse files
authored
Run gdb stubtests (#11644)
The gdb package is only available inside gdb and cannot be installed externally through e.g. pip. Run the stubtest inside gdb.
1 parent 9965725 commit d78ce59

3 files changed

Lines changed: 213 additions & 3 deletions

File tree

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# TODO: Update types in stub
2+
# This list includes everything to allow initial stubtests to run in gdb's environment
3+
gdb.BP_NONE
4+
gdb.Breakpoint.stop
5+
gdb.BreakpointEvent
6+
gdb.ClearObjFilesEvent
7+
gdb.Command.complete
8+
gdb.Command.invoke
9+
gdb.ConnectionEvent
10+
gdb.ContinueEvent
11+
gdb.DUMMY_FRAME
12+
gdb.Event
13+
gdb.EventRegistry
14+
gdb.ExitedEvent
15+
gdb.FRAME_UNWIND_FIRST_ERROR
16+
gdb.FinishBreakpoint.out_of_scope
17+
gdb.Function.invoke
18+
gdb.GdbExitingEvent
19+
gdb.GdbSetPythonDirectory
20+
gdb.HOST_CONFIG
21+
gdb.Inferior.connection
22+
gdb.Inferior.thread_from_thread_handle
23+
gdb.InferiorCallPostEvent
24+
gdb.InferiorCallPreEvent
25+
gdb.InferiorDeletedEvent
26+
gdb.InferiorThread.details
27+
gdb.Instruction
28+
gdb.LazyString
29+
gdb.LineTable.__next__
30+
gdb.LineTable.is_valid
31+
gdb.LineTable.source_lines
32+
gdb.LineTable.source_lnes
33+
gdb.LineTableIterator
34+
gdb.MICommand.invoke
35+
gdb.Membuf
36+
gdb.MemoryChangedEvent
37+
gdb.NewInferiorEvent
38+
gdb.NewObjFileEvent
39+
gdb.NewThreadEvent
40+
gdb.Objfile.frame_unwinders
41+
gdb.Objfile.lookup_static_method
42+
gdb.Objfile.lookup_static_symbol
43+
gdb.Objfile.xmethods
44+
gdb.Parameter.get_set_string
45+
gdb.Parameter.get_show_string
46+
gdb.Progspace.frame_unwinders
47+
gdb.Progspace.xmethods
48+
gdb.Record
49+
gdb.RecordFunctionSegment
50+
gdb.RecordGap
51+
gdb.RecordInstruction
52+
gdb.RegisterChangedEvent
53+
gdb.RegisterDescriptor
54+
gdb.RegisterDescriptorIterator
55+
gdb.RegisterGroup
56+
gdb.RegisterGroupsIterator
57+
gdb.RemoteTargetConnection
58+
gdb.SYMBOL_FUNCTIONS_DOMAIN
59+
gdb.SYMBOL_TYPES_DOMAIN
60+
gdb.SYMBOL_VARIABLES_DOMAIN
61+
gdb.SignalEvent
62+
gdb.StopEvent
63+
gdb.TARGET_CONFIG
64+
gdb.ThreadEvent
65+
gdb.TuiWindow
66+
gdb.Type.__contains__
67+
gdb.Type.get
68+
gdb.Type.has_key
69+
gdb.Type.is_scalar
70+
gdb.Type.is_signed
71+
gdb.Type.items
72+
gdb.Type.iteritems
73+
gdb.Type.iterkeys
74+
gdb.Type.itervalues
75+
gdb.Type.keys
76+
gdb.Type.values
77+
gdb.TypeIterator
78+
gdb.Unwinder
79+
gdb.Value.rvalue_reference_value
80+
gdb.frame_filters
81+
gdb.frame_unwinders
82+
gdb.packages
83+
gdb.prompt_hook
84+
gdb.type_printers
85+
gdb.xmethods
86+
gdb.events
87+
gdb.printing.RegexpCollectionPrettyPrinter.RegexpSubprinter
88+
gdb.printing.add_builtin_pretty_printer
89+
gdb.prompt.prompt_help
90+
gdb.prompt.prompt_substitutions
91+
gdb.types.TypePrinter.instantiate
92+
gdb.unwinder.Unwinder
93+
gdb.xmethod.SimpleXMethodMatcher
94+
gdb.xmethod.XMethodMatcher.match
95+
gdb.xmethod.XMethodWorker.__call__
96+
gdb.xmethod.XMethodWorker.get_arg_types
97+
gdb.xmethod.XMethodWorker.get_result_type
98+
gdb.FrameDecorator
99+
gdb.FrameIterator
100+
gdb.command
101+
gdb.command.explore
102+
gdb.command.frame_filters
103+
gdb.command.pretty_printers
104+
gdb.command.prompt
105+
gdb.command.type_printers
106+
gdb.command.unwinders
107+
gdb.command.xmethods
108+
gdb.frames
109+
gdb.function
110+
gdb.function.as_string
111+
gdb.function.caller_is
112+
gdb.function.strfns
113+
gdb.printer
114+
gdb.printer.bound_registers
115+
gdb.printing.basestring
116+
gdb.printing.long
117+
gdb.xmethod.basestring
118+
gdb.xmethod.long
119+
gdb.styling

stubs/gdb/METADATA.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@ extra_description = """\
1111
"""
1212

1313
[tool.stubtest]
14-
# Since the "gdb" Python package is available only inside GDB, it is not
15-
# possible to install it through pip, so stub tests cannot install it.
16-
skip = true
14+
platforms = ["linux"]
15+
apt_dependencies = ["gdb"]

tests/stubtest_third_party.py

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@ def run_stubtest(
7373
# TODO: Maybe find a way to cache these in CI
7474
dists_to_install = [dist_req, get_mypy_req()]
7575
dists_to_install.extend(requirements.external_pkgs) # Internal requirements are added to MYPYPATH
76+
77+
# Since the "gdb" Python package is available only inside GDB, it is not
78+
# possible to install it through pip, so stub tests cannot install it.
79+
if dist_name == "gdb":
80+
dists_to_install[:] = dists_to_install[1:]
81+
7682
pip_cmd = [pip_exe, "install", *dists_to_install]
7783
try:
7884
subprocess.run(pip_cmd, check=True, capture_output=True)
@@ -118,6 +124,10 @@ def run_stubtest(
118124
if not setup_uwsgi_stubtest_command(dist, venv_dir, stubtest_cmd):
119125
return False
120126

127+
if dist_name == "gdb":
128+
if not setup_gdb_stubtest_command(venv_dir, stubtest_cmd):
129+
return False
130+
121131
try:
122132
subprocess.run(stubtest_cmd, env=stubtest_env, check=True, capture_output=True)
123133
except subprocess.CalledProcessError as e:
@@ -153,6 +163,88 @@ def run_stubtest(
153163
return True
154164

155165

166+
def setup_gdb_stubtest_command(venv_dir: Path, stubtest_cmd: list[str]) -> bool:
167+
"""
168+
Use wrapper scripts to run stubtest inside gdb.
169+
The wrapper script is used to pass the arguments to the gdb script.
170+
"""
171+
if sys.platform == "win32":
172+
print_error("gdb is not supported on Windows")
173+
return False
174+
175+
try:
176+
gdb_version = subprocess.check_output(["gdb", "--version"], text=True, stderr=subprocess.STDOUT)
177+
except FileNotFoundError:
178+
print_error("gdb is not installed")
179+
return False
180+
if "Python scripting is not supported in this copy of GDB" in gdb_version:
181+
print_error("Python scripting is not supported in this copy of GDB")
182+
return False
183+
184+
gdb_script = venv_dir / "gdb_stubtest.py"
185+
wrapper_script = venv_dir / "gdb_wrapper.py"
186+
gdb_script_contents = dedent(
187+
f"""
188+
import json
189+
import os
190+
import site
191+
import sys
192+
import traceback
193+
194+
from glob import glob
195+
196+
# Add the venv site-packages to sys.path. gdb doesn't use the virtual environment.
197+
# Taken from https://github.com/pwndbg/pwndbg/blob/83d8d95b576b749e888f533ce927ad5a77fb957b/gdbinit.py#L37
198+
site_pkgs_path = glob(os.path.join({str(venv_dir)!r}, "lib/*/site-packages"))[0]
199+
site.addsitedir(site_pkgs_path)
200+
201+
exit_code = 1
202+
try:
203+
# gdb wraps stdout and stderr without a .fileno
204+
# colored output in mypy tries to access .fileno()
205+
sys.stdout.fileno = sys.__stdout__.fileno
206+
sys.stderr.fileno = sys.__stderr__.fileno
207+
208+
from mypy.stubtest import main
209+
210+
sys.argv = json.loads(os.environ.get("STUBTEST_ARGS"))
211+
exit_code = main()
212+
except Exception:
213+
traceback.print_exc()
214+
finally:
215+
gdb.execute(f"quit {{exit_code}}")
216+
"""
217+
)
218+
gdb_script.write_text(gdb_script_contents)
219+
220+
wrapper_script_contents = dedent(
221+
f"""
222+
import json
223+
import os
224+
import subprocess
225+
import sys
226+
227+
stubtest_env = os.environ | {{"STUBTEST_ARGS": json.dumps(sys.argv)}}
228+
gdb_cmd = [
229+
"gdb",
230+
"--quiet",
231+
"--nx",
232+
"--batch",
233+
"--command",
234+
{str(gdb_script)!r},
235+
]
236+
r = subprocess.run(gdb_cmd, env=stubtest_env)
237+
sys.exit(r.returncode)
238+
"""
239+
)
240+
wrapper_script.write_text(wrapper_script_contents)
241+
242+
# replace "-m mypy.stubtest" in stubtest_cmd with the path to our wrapper script
243+
assert stubtest_cmd[1:3] == ["-m", "mypy.stubtest"]
244+
stubtest_cmd[1:3] = [str(wrapper_script)]
245+
return True
246+
247+
156248
def setup_uwsgi_stubtest_command(dist: Path, venv_dir: Path, stubtest_cmd: list[str]) -> bool:
157249
"""Perform some black magic in order to run stubtest inside uWSGI.
158250

0 commit comments

Comments
 (0)