mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-12-19 01:19:41 +08:00
This updates the copyright headers to include 2025. I did this by running gdb/copyright.py and then manually modifying a few files as noted by the script. Approved-By: Eli Zaretskii <eliz@gnu.org>
205 lines
6.5 KiB
Python
205 lines
6.5 KiB
Python
# Copyright (C) 2023-2025 Free Software Foundation, Inc.
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
"""
|
|
MissingFileHandler base class, and support functions used by the
|
|
missing_debug.py and missing_objfile.py modules.
|
|
"""
|
|
|
|
import sys
|
|
|
|
import gdb
|
|
|
|
if sys.version_info >= (3, 7):
|
|
# Functions str.isascii() and str.isalnum are available starting Python
|
|
# 3.7.
|
|
def isascii(ch):
|
|
return ch.isascii()
|
|
|
|
def isalnum(ch):
|
|
return ch.isalnum()
|
|
|
|
else:
|
|
# Older version of Python doesn't have str.isascii() and
|
|
# str.isalnum() so provide our own.
|
|
#
|
|
# We could import isalnum() and isascii() from the curses library,
|
|
# but that adds an extra dependency. Given these functions are
|
|
# both small and trivial lets implement them here.
|
|
#
|
|
# These definitions are based on those in the curses library, but
|
|
# simplified as we know C will always be a single character 'str'.
|
|
|
|
def isdigit(c):
|
|
return 48 <= ord(c) <= 57
|
|
|
|
def islower(c):
|
|
return 97 <= ord(c) <= 122
|
|
|
|
def isupper(c):
|
|
return 65 <= ord(c) <= 90
|
|
|
|
def isalpha(c):
|
|
return isupper(c) or islower(c)
|
|
|
|
def isalnum(c):
|
|
return isalpha(c) or isdigit(c)
|
|
|
|
def isascii(c):
|
|
return 0 <= ord(c) <= 127
|
|
|
|
|
|
def _validate_name(name):
|
|
"""Validate a missing file handler name string.
|
|
|
|
If name is valid as a missing file handler name, then this
|
|
function does nothing. If name is not valid then an exception is
|
|
raised.
|
|
|
|
Arguments:
|
|
name: A string, the name of a missing file handler.
|
|
|
|
Returns:
|
|
Nothing.
|
|
|
|
Raises:
|
|
ValueError: If name is invalid as a missing file handler
|
|
name.
|
|
"""
|
|
|
|
for ch in name:
|
|
if not isascii(ch) or not (isalnum(ch) or ch in "_-"):
|
|
raise ValueError("invalid character '%s' in handler name: %s" % (ch, name))
|
|
|
|
|
|
class MissingFileHandler(object):
|
|
"""Base class for missing file handlers written in Python.
|
|
|
|
A missing file handler has a single method __call__ along with the
|
|
read/write attribute enabled, and a read-only attribute name. The
|
|
attributes are provided by this class while the __call__ method is
|
|
provided by a sub-class. Each sub-classes __call__ method will
|
|
have a different signature.
|
|
|
|
Attributes:
|
|
name: Read-only attribute, the name of this handler.
|
|
enabled: When true this handler is enabled.
|
|
"""
|
|
|
|
def __init__(self, name):
|
|
"""Constructor.
|
|
|
|
Args:
|
|
name: An identifying name for this handler.
|
|
|
|
Raises:
|
|
TypeError: name is not a string.
|
|
ValueError: name contains invalid characters.
|
|
"""
|
|
|
|
if not isinstance(name, str):
|
|
raise TypeError("incorrect type for name: %s" % type(name))
|
|
|
|
_validate_name(name)
|
|
|
|
self._name = name
|
|
self._enabled = True
|
|
|
|
@property
|
|
def name(self):
|
|
return self._name
|
|
|
|
@property
|
|
def enabled(self):
|
|
return self._enabled
|
|
|
|
@enabled.setter
|
|
def enabled(self, value):
|
|
if not isinstance(value, bool):
|
|
raise TypeError("incorrect type for enabled attribute: %s" % type(value))
|
|
self._enabled = value
|
|
|
|
|
|
def register_handler(handler_type, locus, handler, replace=False):
|
|
"""Register handler in given locus.
|
|
|
|
The handler is prepended to the locus's missing file handlers
|
|
list. The name of handler should be unique (or replace must be
|
|
True), and the name must pass the _validate_name check.
|
|
|
|
Arguments:
|
|
handler_type: A string, either 'debug' or 'objfile' indicating the
|
|
type of handler to be registered.
|
|
locus: Either a progspace, or None (in which case the unwinder
|
|
is registered globally).
|
|
handler: An object used as a missing file handler. Usually a
|
|
sub-class of MissingFileHandler.
|
|
replace: If True, replaces existing handler with the same name
|
|
within locus. Otherwise, raises RuntimeException if
|
|
unwinder with the same name already exists.
|
|
|
|
Returns:
|
|
Nothing.
|
|
|
|
Raises:
|
|
RuntimeError: The name of handler is not unique.
|
|
TypeError: Bad locus type.
|
|
AttributeError: Required attributes of handler are missing.
|
|
ValueError: If the name of the handler is invalid, or if
|
|
handler_type is neither 'debug' or 'objfile'.
|
|
"""
|
|
|
|
if handler_type != "debug" and handler_type != "objfile":
|
|
raise ValueError("handler_type must be 'debug' or 'objfile'")
|
|
|
|
if locus is None:
|
|
if gdb.parameter("verbose"):
|
|
gdb.write("Registering global %s handler ...\n" % handler.name)
|
|
locus = gdb
|
|
elif isinstance(locus, gdb.Progspace):
|
|
if gdb.parameter("verbose"):
|
|
gdb.write(
|
|
"Registering %s handler for %s ...\n" % (handler.name, locus.filename)
|
|
)
|
|
else:
|
|
raise TypeError("locus should be gdb.Progspace or None")
|
|
|
|
# Some sanity checks on HANDLER. Calling getattr will raise an
|
|
# exception if the attribute doesn't exist, which is what we want.
|
|
# These checks are not exhaustive; we don't check the attributes
|
|
# have the correct types, or the method has the correct signature,
|
|
# but this should catch some basic mistakes.
|
|
name = getattr(handler, "name")
|
|
_validate_name(name)
|
|
|
|
getattr(handler, "enabled")
|
|
|
|
call_method = getattr(handler, "__call__")
|
|
if not callable(call_method):
|
|
raise AttributeError(
|
|
"'%s' object's '__call__' attribute is not callable"
|
|
% type(handler).__name__
|
|
)
|
|
|
|
i = 0
|
|
for needle in locus.missing_file_handlers:
|
|
if needle[0] == handler_type and needle[1].name == handler.name:
|
|
if replace:
|
|
del locus.missing_file_handlers[i]
|
|
else:
|
|
raise RuntimeError("Handler %s already exists." % handler.name)
|
|
i += 1
|
|
locus.missing_file_handlers.insert(0, (handler_type, handler))
|