blob: 86da9b8ef3c92cd850fbe12fbb453a42d66f3afc [file] [log] [blame]
# Copyright 2022-2024 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 os
import gdb
# This must come before other DAP imports.
from . import startup
# Load modules that define commands.
from . import breakpoint
from . import bt
from . import disassemble
from . import evaluate
from . import launch
from . import locations
from . import memory
from . import modules
from . import next
from . import pause
from . import scopes
from . import sources
from . import threads
from .server import Server
def run():
"""Main entry point for the DAP server.
This is called by the GDB DAP interpreter."""
startup.exec_and_log("set python print-stack full")
startup.exec_and_log("set pagination off")
# We want to control gdb stdin and stdout entirely, so we dup
# them to new file descriptors.
saved_out = os.dup(1)
saved_in = os.dup(0)
# Make sure these are not inheritable. This is already the case
# for Unix, but not for Windows.
os.set_inheritable(saved_out, False)
os.set_inheritable(saved_in, False)
# The new gdb (and inferior) stdin will just be /dev/null. For
# gdb, the "dap" interpreter also rewires the UI so that gdb
# doesn't try to read this (and thus see EOF and exit).
new_in = os.open(os.devnull, os.O_RDONLY)
os.dup2(new_in, 0, True)
os.close(new_in)
# Make the new stdout be a pipe. This way the DAP code can easily
# read from the inferior and send OutputEvent to the client.
(rfd, wfd) = os.pipe()
os.set_inheritable(rfd, False)
os.dup2(wfd, 1, True)
# Also send stderr this way.
os.dup2(wfd, 2, True)
os.close(wfd)
# Note the inferior output is opened in text mode.
global server
server = Server(open(saved_in, "rb"), open(saved_out, "wb"), open(rfd, "r"))
# Whether the interactive session has started.
session_started = False
def pre_command_loop():
"""DAP's pre_command_loop interpreter hook. This is called by the GDB DAP
interpreter."""
global session_started
if not session_started:
# The pre_command_loop interpreter hook can be called several times.
# The first time it's called, it means we're starting an interactive
# session.
session_started = True
startup.thread_log("starting DAP server")
global server
startup.start_dap(server.main_loop)