mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2026-08-27 00:26:02 -04:00
This patch changes how gdb output redirection is done. Currently, output is done via the UI. gdb_stdout, for example, is a define the expands to an lvalue referencing a field in the current UI. When redirecting, this field may temporarily be reset; and when logging is enabled or disabled, this is also done. This has lead to bugs where the combination of redirection and logging results in use-after-free. Crashes are readily observable; see the new test cases. This patch upends this. Now, gdb_stdout is simply an rvalue, and refers to the current interpreter. The interpreter provides ui_files that do whatever rewriting is needed (mostly for MI); then output is forward to the current UI via an indirection (see the new ui::passthrough_file). The ui provides paging, logging, timestamps, and the final stream that writes to an actual file descriptor. Redirection is handled at the ui layer. Rather than changing the output pipeline, new ui_files are simply swapped in by rewriting pointers, hopefully with a scoped_restore. Redirecting at the ui layer means that interpreter rewriting is still applied when capturing output. This fixes one of the reported bugs. Not changing the pipeline means that the problems with the combination of redirect and logging simply vanish. Logging just changes a flag and doesn't involve object destruction. Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=17697 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28620 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28798 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=28948 Approved-By: Andrew Burgess <aburgess@redhat.com>
116 lines
2.5 KiB
C
116 lines
2.5 KiB
C
/* Python DAP interpreter
|
|
|
|
Copyright (C) 2022-2026 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 "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 = std::make_unique<cli_ui_out> (m_stdout.get ());
|
|
}
|
|
|
|
~dap_interp () override = default;
|
|
|
|
void do_init (bool top_level) override;
|
|
|
|
void suspend () override
|
|
{
|
|
}
|
|
|
|
void resume () override
|
|
{
|
|
}
|
|
|
|
void exec (const char *command) override
|
|
{
|
|
/* Just ignore it. */
|
|
}
|
|
|
|
ui_out *interp_ui_out () override
|
|
{
|
|
return m_ui_out.get ();
|
|
}
|
|
|
|
void pre_command_loop () override;
|
|
|
|
bool supports_new_ui () const override
|
|
{ return false; }
|
|
|
|
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::do_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");
|
|
}
|
|
|
|
INIT_GDB_FILE (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
|
|
}
|