mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-01-12 12:16:04 +08:00
8f6c452b5a
This commit builds on the previous commit, and implements the extension_language_ops::handle_missing_debuginfo function for Python. This hook will give user supplied Python code a chance to help find missing debug information. The implementation of the new hook is pretty minimal within GDB's C++ code; most of the work is out-sourced to a Python implementation which is modelled heavily on how GDB's Python frame unwinders are implemented. The following new commands are added as commands implemented in Python, this is similar to how the Python unwinder commands are implemented: info missing-debug-handlers enable missing-debug-handler LOCUS HANDLER disable missing-debug-handler LOCUS HANDLER To make use of this extension hook a user will create missing debug information handler objects, and registers these handlers with GDB. When GDB encounters an objfile that is missing debug information, each handler is called in turn until one is able to help. Here is a minimal handler that does nothing useful: import gdb import gdb.missing_debug class MyFirstHandler(gdb.missing_debug.MissingDebugHandler): def __init__(self): super().__init__("my_first_handler") def __call__(self, objfile): # This handler does nothing useful. return None gdb.missing_debug.register_handler(None, MyFirstHandler()) Returning None from the __call__ method tells GDB that this handler was unable to find the missing debug information, and GDB should ask any other registered handlers. By extending the __call__ method it is possible for the Python extension to locate the debug information for objfile and return a value that tells GDB how to use the information that has been located. Possible return values from a handler: - None: This means the handler couldn't help. GDB will call other registered handlers to see if they can help instead. - False: The handler has done all it can, but the debug information for the objfile still couldn't be found. GDB will not call any other handlers, and will continue without the debug information for objfile. - True: The handler has installed the debug information into a location where GDB would normally expect to find it. GDB should look again for the debug information. - A string: The handler can return a filename, which is the file containing the missing debug information. GDB will load this file. When a handler returns True, GDB will look again for the debug information, but only using the standard built-in build-id and .gnu_debuglink based lookup strategies. It is not possible for an extension to trigger another debuginfod lookup; the assumption is that the debuginfod server is remote, and out of the control of extensions running within GDB. Handlers can be registered globally, or per program space. GDB checks the handlers for the current program space first, and then all of the global handles. The first handler that returns a value that is not None, has "handled" the objfile, at which point GDB continues. Reviewed-By: Eli Zaretskii <eliz@gnu.org> Approved-By: Tom Tromey <tom@tromey.com>
121 lines
3.2 KiB
Python
121 lines
3.2 KiB
Python
# Copyright (C) 2023 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/>.
|
|
|
|
import gdb
|
|
from gdb.missing_debug import MissingDebugHandler
|
|
from enum import Enum
|
|
import os
|
|
|
|
# A global log that is filled in by instances of the LOG_HANDLER class
|
|
# when they are called.
|
|
handler_call_log = []
|
|
|
|
|
|
class Mode(Enum):
|
|
RETURN_NONE = 0
|
|
RETURN_TRUE = 1
|
|
RETURN_FALSE = 2
|
|
RETURN_STRING = 3
|
|
|
|
|
|
class handler(MissingDebugHandler):
|
|
def __init__(self):
|
|
super().__init__("handler")
|
|
self._call_count = 0
|
|
self._mode = Mode.RETURN_NONE
|
|
|
|
def __call__(self, objfile):
|
|
global handler_call_log
|
|
handler_call_log.append(self.name)
|
|
self._call_count += 1
|
|
if self._mode == Mode.RETURN_NONE:
|
|
return None
|
|
|
|
if self._mode == Mode.RETURN_TRUE:
|
|
os.rename(self._src, self._dest)
|
|
return True
|
|
|
|
if self._mode == Mode.RETURN_FALSE:
|
|
return False
|
|
|
|
if self._mode == Mode.RETURN_STRING:
|
|
return self._dest
|
|
|
|
assert False
|
|
|
|
@property
|
|
def call_count(self):
|
|
"""Return a count, the number of calls to __call__ since the last
|
|
call to set_mode.
|
|
"""
|
|
return self._call_count
|
|
|
|
def set_mode(self, mode, *args):
|
|
self._call_count = 0
|
|
self._mode = mode
|
|
|
|
if mode == Mode.RETURN_NONE:
|
|
assert len(args) == 0
|
|
return
|
|
|
|
if mode == Mode.RETURN_TRUE:
|
|
assert len(args) == 2
|
|
self._src = args[0]
|
|
self._dest = args[1]
|
|
return
|
|
|
|
if mode == Mode.RETURN_FALSE:
|
|
assert len(args) == 0
|
|
return
|
|
|
|
if mode == Mode.RETURN_STRING:
|
|
assert len(args) == 1
|
|
self._dest = args[0]
|
|
return
|
|
|
|
assert False
|
|
|
|
|
|
class exception_handler(MissingDebugHandler):
|
|
def __init__(self):
|
|
super().__init__("exception_handler")
|
|
self.exception_type = None
|
|
|
|
def __call__(self, objfile):
|
|
global handler_call_log
|
|
handler_call_log.append(self.name)
|
|
assert self.exception_type is not None
|
|
raise self.exception_type("message")
|
|
|
|
|
|
class log_handler(MissingDebugHandler):
|
|
def __call__(self, objfile):
|
|
global handler_call_log
|
|
handler_call_log.append(self.name)
|
|
return None
|
|
|
|
|
|
# A basic helper function, this keeps lines shorter in the TCL script.
|
|
def register(name, locus=None):
|
|
gdb.missing_debug.register_handler(locus, log_handler(name))
|
|
|
|
|
|
# Create instances of the handlers, but don't install any. We install
|
|
# these as needed from the TCL script.
|
|
rhandler = exception_handler()
|
|
handler_obj = handler()
|
|
|
|
print("Success")
|