mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-18 00:32:30 +08:00

The Debugger Adapter Protocol is a JSON-RPC protocol that IDEs can use to communicate with debuggers. You can find more information here: https://microsoft.github.io/debug-adapter-protocol/ Frequently this is implemented as a shim, but it seemed to me that GDB could implement it directly, via the Python API. This patch is the initial implementation. DAP is implemented as a new "interp". This is slightly weird, because it doesn't act like an ordinary interpreter -- for example it doesn't implement a command syntax, and doesn't use GDB's ordinary event loop. However, this seemed like the best approach overall. To run GDB in this mode, use: gdb -i=dap The DAP code will accept JSON-RPC messages on stdin and print responses to stdout. GDB redirects the inferior's stdout to a new pipe so that output can be encapsulated by the protocol. The Python code uses multiple threads to do its work. Separate threads are used for reading JSON from the client and for writing JSON to the client. All GDB work is done in the main thread. (The first implementation used asyncio, but this had some limitations, and so I rewrote it to use threads instead.) This is not a complete implementation of the protocol, but it does implement enough to demonstrate that the overall approach works. There is a rudimentary test suite. It uses a JSON parser written in pure Tcl. This parser is under the same license as Tcl itself, so I felt it was acceptable to simply import it into the tree. There is also a bit of documentation -- just documenting the new interpreter name.
58 lines
1.6 KiB
Python
58 lines
1.6 KiB
Python
# Copyright 2022 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 .startup import in_gdb_thread
|
|
|
|
|
|
# Map from frame (thread,level) pair to frame ID numbers. Note we
|
|
# can't use the frame itself here as it is not hashable.
|
|
_frame_ids = {}
|
|
|
|
# Map from frame ID number back to frames.
|
|
_id_to_frame = {}
|
|
|
|
|
|
# Clear all the frame IDs.
|
|
@in_gdb_thread
|
|
def _clear_frame_ids(evt):
|
|
global _frame_ids, _id_to_frame
|
|
_frame_ids = {}
|
|
_id_to_frame = {}
|
|
|
|
|
|
# Clear the frame ID map whenever the inferior runs.
|
|
gdb.events.cont.connect(_clear_frame_ids)
|
|
|
|
|
|
@in_gdb_thread
|
|
def frame_id(frame):
|
|
"""Return the frame identifier for FRAME."""
|
|
global _frame_ids, _id_to_frame
|
|
pair = (gdb.selected_thread().global_num, frame.level)
|
|
if pair not in _frame_ids:
|
|
id = len(_frame_ids)
|
|
_frame_ids[pair] = id
|
|
_id_to_frame[id] = frame
|
|
return _frame_ids[pair]
|
|
|
|
|
|
@in_gdb_thread
|
|
def frame_for_id(id):
|
|
"""Given a frame identifier ID, return the corresponding frame."""
|
|
global _id_to_frame
|
|
return _id_to_frame[id]
|