mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2025-03-07 13:39:43 +08:00
gdb.interrupt was introduced to implement DAP request cancellation. However, because it can be run from another thread, and because I didn't look deeply enough at the implementation, it turns out to be racy. The fix here is to lock accesses to certain globals in extension.c. Note that this won't work in the case where configure detects that the C++ compiler doesn't provide thread support. This version of the patch disables DAP entirely in this situation. Regression tested on x86-64 Fedora 38. I also ran gdb.dap/pause.exp in a thread-sanitizer build tree to make sure the reported race is gone. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=31263
123 lines
2.6 KiB
C
123 lines
2.6 KiB
C
/* Python DAP interpreter
|
|
|
|
Copyright (C) 2022-2024 Free Software Foundation, Inc.
|
|
|
|
This file is part of GDB.
|
|
|
|
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/>. */
|
|
|
|
#include "defs.h"
|
|
#include "python-internal.h"
|
|
#include "interps.h"
|
|
#include "cli-out.h"
|
|
#include "ui.h"
|
|
|
|
class dap_interp final : public interp
|
|
{
|
|
public:
|
|
|
|
explicit dap_interp (const char *name)
|
|
: interp (name),
|
|
m_ui_out (new cli_ui_out (gdb_stdout))
|
|
{
|
|
}
|
|
|
|
~dap_interp () override = default;
|
|
|
|
void init (bool top_level) override;
|
|
|
|
void suspend () override
|
|
{
|
|
}
|
|
|
|
void resume () override
|
|
{
|
|
}
|
|
|
|
void exec (const char *command) override
|
|
{
|
|
/* Just ignore it. */
|
|
}
|
|
|
|
void set_logging (ui_file_up logfile, bool logging_redirect,
|
|
bool debug_redirect) override
|
|
{
|
|
/* Just ignore it. */
|
|
}
|
|
|
|
ui_out *interp_ui_out () override
|
|
{
|
|
return m_ui_out.get ();
|
|
}
|
|
|
|
void pre_command_loop () override;
|
|
|
|
private:
|
|
|
|
std::unique_ptr<ui_out> m_ui_out;
|
|
};
|
|
|
|
|
|
/* Call function FN_NAME from module gdb.dap. */
|
|
|
|
static void
|
|
call_dap_fn (const char *fn_name)
|
|
{
|
|
gdbpy_enter enter_py;
|
|
|
|
gdbpy_ref<> dap_module (PyImport_ImportModule ("gdb.dap"));
|
|
if (dap_module == nullptr)
|
|
gdbpy_handle_exception ();
|
|
|
|
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)
|
|
{
|
|
#if CXX_STD_THREAD
|
|
call_dap_fn ("run");
|
|
|
|
current_ui->input_fd = -1;
|
|
current_ui->m_input_interactive_p = false;
|
|
#else
|
|
error (_("GDB was compiled without threading, which DAP requires"));
|
|
#endif
|
|
}
|
|
|
|
void
|
|
dap_interp::pre_command_loop ()
|
|
{
|
|
call_dap_fn ("pre_command_loop");
|
|
}
|
|
|
|
void _initialize_py_interp ();
|
|
void
|
|
_initialize_py_interp ()
|
|
{
|
|
/* The dap code uses module typing, available starting python 3.5. */
|
|
#if PY_VERSION_HEX >= 0x03050000
|
|
interp_factory_register ("dap", [] (const char *name) -> interp *
|
|
{
|
|
return new dap_interp (name);
|
|
});
|
|
#endif
|
|
}
|