|
1 | | -# Copyright (C) 2010-2024 Free Software Foundation, Inc. |
| 1 | +# Copyright (C) 2010-2025 Free Software Foundation, Inc. |
2 | 2 |
|
3 | 3 | # This program is free software; you can redistribute it and/or modify |
4 | 4 | # it under the terms of the GNU General Public License as published by |
|
19 | 19 | import threading |
20 | 20 | import traceback |
21 | 21 | from contextlib import contextmanager |
| 22 | +from importlib import reload |
22 | 23 |
|
23 | | -# Python 3 moved "reload" |
24 | | -if sys.version_info >= (3, 4): |
25 | | - from importlib import reload |
26 | | -else: |
27 | | - from imp import reload |
28 | | - |
29 | | -import _gdb |
30 | | - |
| 24 | +# The star import imports _gdb names. When the names are used locally, they |
| 25 | +# trigger F405 warnings unless added to the explicit import list. |
31 | 26 | # Note that two indicators are needed here to silence flake8. |
32 | 27 | from _gdb import * # noqa: F401,F403 |
| 28 | +from _gdb import ( |
| 29 | + STDERR, |
| 30 | + STDOUT, |
| 31 | + Command, |
| 32 | + execute, |
| 33 | + flush, |
| 34 | + parameter, |
| 35 | + selected_inferior, |
| 36 | + write, |
| 37 | +) |
33 | 38 |
|
34 | 39 | # isort: split |
35 | 40 |
|
@@ -60,14 +65,14 @@ def writelines(self, iterable): |
60 | 65 | self.write(line) |
61 | 66 |
|
62 | 67 | def flush(self): |
63 | | - _gdb.flush(stream=self.stream) |
| 68 | + flush(stream=self.stream) |
64 | 69 |
|
65 | 70 | def write(self, s): |
66 | | - _gdb.write(s, stream=self.stream) |
| 71 | + write(s, stream=self.stream) |
67 | 72 |
|
68 | 73 |
|
69 | | -sys.stdout = _GdbFile(_gdb.STDOUT) |
70 | | -sys.stderr = _GdbFile(_gdb.STDERR) |
| 74 | +sys.stdout = _GdbFile(STDOUT) |
| 75 | +sys.stderr = _GdbFile(STDERR) |
71 | 76 |
|
72 | 77 | # Default prompt hook does nothing. |
73 | 78 | prompt_hook = None |
@@ -189,7 +194,7 @@ def GdbSetPythonDirectory(dir): |
189 | 194 |
|
190 | 195 | def current_progspace(): |
191 | 196 | "Return the current Progspace." |
192 | | - return _gdb.selected_inferior().progspace |
| 197 | + return selected_inferior().progspace |
193 | 198 |
|
194 | 199 |
|
195 | 200 | def objfiles(): |
@@ -226,14 +231,14 @@ def set_parameter(name, value): |
226 | 231 | value = "on" |
227 | 232 | else: |
228 | 233 | value = "off" |
229 | | - _gdb.execute("set " + name + " " + str(value), to_string=True) |
| 234 | + execute("set " + name + " " + str(value), to_string=True) |
230 | 235 |
|
231 | 236 |
|
232 | 237 | @contextmanager |
233 | 238 | def with_parameter(name, value): |
234 | 239 | """Temporarily set the GDB parameter NAME to VALUE. |
235 | 240 | Note that this is a context manager.""" |
236 | | - old_value = _gdb.parameter(name) |
| 241 | + old_value = parameter(name) |
237 | 242 | set_parameter(name, value) |
238 | 243 | try: |
239 | 244 | # Nothing that useful to return. |
@@ -392,3 +397,121 @@ def _handle_missing_objfile(pspace, buildid, filename): |
392 | 397 | return _handle_missing_files( |
393 | 398 | pspace, "objfile", lambda h: h(pspace, buildid, filename) |
394 | 399 | ) |
| 400 | + |
| 401 | + |
| 402 | +class ParameterPrefix: |
| 403 | + # A wrapper around gdb.Command for creating set/show prefixes. |
| 404 | + # |
| 405 | + # When creating a gdb.Parameter sub-classes, it is sometimes necessary |
| 406 | + # to first create a gdb.Command object in order to create the needed |
| 407 | + # command prefix. However, for parameters, we actually need two |
| 408 | + # prefixes, a 'set' prefix, and a 'show' prefix. With this helper |
| 409 | + # class, a single instance of this class will create both prefixes at |
| 410 | + # once. |
| 411 | + # |
| 412 | + # It is important that this class-level documentation not be a __doc__ |
| 413 | + # string. Users are expected to sub-class this ParameterPrefix class |
| 414 | + # and add their own documentation. If they don't, then GDB will |
| 415 | + # generate a suitable doc string. But, if this (parent) class has a |
| 416 | + # __doc__ string of its own, then sub-classes will inherit that __doc__ |
| 417 | + # string, and GDB will not understand that it needs to generate one. |
| 418 | + |
| 419 | + class _PrefixCommand(Command): |
| 420 | + """A gdb.Command used to implement both the set and show prefixes. |
| 421 | +
|
| 422 | + This documentation string is not used as the prefix command |
| 423 | + documentation as it is overridden in the __init__ method below.""" |
| 424 | + |
| 425 | + # This private method is connected to the 'invoke' attribute within |
| 426 | + # this _PrefixCommand object if the containing ParameterPrefix |
| 427 | + # object has an invoke_set or invoke_show method. |
| 428 | + # |
| 429 | + # This method records within self.__delegate which _PrefixCommand |
| 430 | + # object is currently active, and then calls the correct invoke |
| 431 | + # method on the delegat object (the ParameterPrefix sub-class |
| 432 | + # object). |
| 433 | + # |
| 434 | + # Recording the currently active _PrefixCommand object is important; |
| 435 | + # if from the invoke method the user calls dont_repeat, then this is |
| 436 | + # forwarded to the currently active _PrefixCommand object. |
| 437 | + def __invoke(self, args, from_tty): |
| 438 | + |
| 439 | + # A helper class for use as part of a Python 'with' block. |
| 440 | + # Records which gdb.Command object is currently running its |
| 441 | + # invoke method. |
| 442 | + class MarkActiveCallback: |
| 443 | + # The CMD is a _PrefixCommand object, and the DELEGATE is |
| 444 | + # the ParameterPrefix class, or sub-class object. At this |
| 445 | + # point we simple record both of these within the |
| 446 | + # MarkActiveCallback object. |
| 447 | + def __init__(self, cmd, delegate): |
| 448 | + self.__cmd = cmd |
| 449 | + self.__delegate = delegate |
| 450 | + |
| 451 | + # Record the currently active _PrefixCommand object within |
| 452 | + # the outer ParameterPrefix sub-class object. |
| 453 | + def __enter__(self): |
| 454 | + self.__delegate.active_prefix = self.__cmd |
| 455 | + |
| 456 | + # Once the invoke method has completed, then clear the |
| 457 | + # _PrefixCommand object that was stored into the outer |
| 458 | + # ParameterPrefix sub-class object. |
| 459 | + def __exit__(self, exception_type, exception_value, traceback): |
| 460 | + self.__delegate.active_prefix = None |
| 461 | + |
| 462 | + # The self.__cb attribute is set when the _PrefixCommand object |
| 463 | + # is created, and is either invoke_set or invoke_show within the |
| 464 | + # ParameterPrefix sub-class object. |
| 465 | + assert callable(self.__cb) |
| 466 | + |
| 467 | + # Record the currently active _PrefixCommand object within the |
| 468 | + # ParameterPrefix sub-class object, then call the relevant |
| 469 | + # invoke method within the ParameterPrefix sub-class object. |
| 470 | + with MarkActiveCallback(self, self.__delegate): |
| 471 | + self.__cb(args, from_tty) |
| 472 | + |
| 473 | + @staticmethod |
| 474 | + def __find_callback(delegate, mode): |
| 475 | + """The MODE is either 'set' or 'show'. Look for an invoke_MODE method |
| 476 | + on DELEGATE, if a suitable method is found, then return it, otherwise, |
| 477 | + return None. |
| 478 | + """ |
| 479 | + cb = getattr(delegate, "invoke_" + mode, None) |
| 480 | + if callable(cb): |
| 481 | + return cb |
| 482 | + return None |
| 483 | + |
| 484 | + def __init__(self, mode, name, cmd_class, delegate, doc=None): |
| 485 | + """Setup this gdb.Command. Mode is a string, either 'set' or 'show'. |
| 486 | + NAME is the name for this prefix command, that is, the |
| 487 | + words that appear after both 'set' and 'show' in the |
| 488 | + command name. CMD_CLASS is the usual enum. And DELEGATE |
| 489 | + is the gdb.ParameterPrefix object this prefix is part of. |
| 490 | + """ |
| 491 | + assert mode == "set" or mode == "show" |
| 492 | + if doc is None: |
| 493 | + self.__doc__ = delegate.__doc__ |
| 494 | + else: |
| 495 | + self.__doc__ = doc |
| 496 | + self.__cb = self.__find_callback(delegate, mode) |
| 497 | + self.__delegate = delegate |
| 498 | + if self.__cb is not None: |
| 499 | + self.invoke = self.__invoke |
| 500 | + super().__init__(mode + " " + name, cmd_class, prefix=True) |
| 501 | + |
| 502 | + def __init__(self, name, cmd_class, doc=None): |
| 503 | + """Create a _PrefixCommand for both the set and show prefix commands. |
| 504 | + NAME is the command name without either the leading 'set ' or |
| 505 | + 'show ' strings, and CMD_CLASS is the usual enum value. |
| 506 | + """ |
| 507 | + self.active_prefix = None |
| 508 | + self._set_prefix_cmd = self._PrefixCommand("set", name, cmd_class, self, doc) |
| 509 | + self._show_prefix_cmd = self._PrefixCommand("show", name, cmd_class, self, doc) |
| 510 | + |
| 511 | + # When called from within an invoke method the self.active_prefix |
| 512 | + # attribute should be set to a gdb.Command sub-class (a _PrefixCommand |
| 513 | + # object, see above). Forward the dont_repeat call to this object to |
| 514 | + # register the actual command as none repeating. |
| 515 | + def dont_repeat(self): |
| 516 | + if self.active_prefix is not None: |
| 517 | + self.active_prefix.dont_repeat() |
0 commit comments