[gdb/dap] Fix race between dap startup and dap log file

In dap_gdb_start we do:
...
        append GDBFLAGS " -iex \"set debug dap-log-file $logfile\" -q -i=dap"
...

While the dap log file setting comes before the dap interpreter setting,
the order is the other way around:
- first, the dap interpreter is started
- second, the -iex commands are executed and the log file is initialized.

Consequently, there's a race between dap interpreter startup and dap log file
initialization.

This cannot be fixed by using -eiex instead.  Before the interpreter is
started, the "set debug dap-log-file" command is not yet registered.

Fix this by postponing the start of the DAP server until GDB has processed all
command files.

Tested on aarch64-linux.

Approved-By: Tom Tromey <tom@tromey.com>

PR dap/31386
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31386
This commit is contained in:
Tom de Vries
2024-02-22 11:35:26 +01:00
parent 67cf0bd885
commit 05bf17f03b
4 changed files with 52 additions and 4 deletions

View File

@@ -69,5 +69,23 @@ def run():
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"))
startup.start_dap(server.main_loop)
# 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)

View File

@@ -61,13 +61,18 @@ public:
return m_ui_out.get ();
}
void pre_command_loop () override;
private:
std::unique_ptr<ui_out> m_ui_out;
};
void
dap_interp::init (bool top_level)
/* Call function FN_NAME from module gdb.dap. */
static void
call_dap_fn (const char *fn_name)
{
gdbpy_enter enter_py;
@@ -75,18 +80,30 @@ dap_interp::init (bool top_level)
if (dap_module == nullptr)
gdbpy_handle_exception ();
gdbpy_ref<> func (PyObject_GetAttrString (dap_module.get (), "run"));
gdbpy_ref<> func (PyObject_GetAttrString (dap_module.get (), fn_name));
if (func == nullptr)
gdbpy_handle_exception ();
gdbpy_ref<> result_obj (PyObject_CallObject (func.get (), nullptr));
if (result_obj == nullptr)
gdbpy_handle_exception ();
}
void
dap_interp::init (bool top_level)
{
call_dap_fn ("run");
current_ui->input_fd = -1;
current_ui->m_input_interactive_p = false;
}
void
dap_interp::pre_command_loop ()
{
call_dap_fn ("pre_command_loop");
}
void _initialize_py_interp ();
void
_initialize_py_interp ()