2017-03-21 02:57:51 +08:00
|
|
|
/* MI Interpreter Definitions and Commands for GDB, the GNU debugger.
|
|
|
|
|
2024-01-12 23:30:44 +08:00
|
|
|
Copyright (C) 2017-2024 Free Software Foundation, Inc.
|
2017-03-21 02:57:51 +08:00
|
|
|
|
|
|
|
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/>. */
|
|
|
|
|
2019-01-28 03:51:36 +08:00
|
|
|
#ifndef MI_MI_INTERP_H
|
|
|
|
#define MI_MI_INTERP_H
|
2017-03-21 02:57:51 +08:00
|
|
|
|
2022-06-17 23:38:20 +08:00
|
|
|
#include "interps.h"
|
|
|
|
|
|
|
|
struct mi_console_file;
|
|
|
|
|
|
|
|
/* An MI interpreter. */
|
|
|
|
|
|
|
|
class mi_interp final : public interp
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
mi_interp (const char *name)
|
|
|
|
: interp (name)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void init (bool top_level) override;
|
|
|
|
void resume () override;
|
|
|
|
void suspend () override;
|
Simplify interp::exec / interp_exec - let exceptions propagate
This patch implements a simplication that I suggested here:
https://sourceware.org/pipermail/gdb-patches/2022-March/186320.html
Currently, the interp::exec virtual method interface is such that
subclass implementations must catch exceptions and then return them
via normal function return.
However, higher up the in chain, for the CLI we get to
interpreter_exec_cmd, which does:
for (i = 1; i < nrules; i++)
{
struct gdb_exception e = interp_exec (interp_to_use, prules[i]);
if (e.reason < 0)
{
interp_set (old_interp, 0);
error (_("error in command: \"%s\"."), prules[i]);
}
}
and for MI we get to mi_cmd_interpreter_exec, which has:
void
mi_cmd_interpreter_exec (const char *command, char **argv, int argc)
{
...
for (i = 1; i < argc; i++)
{
struct gdb_exception e = interp_exec (interp_to_use, argv[i]);
if (e.reason < 0)
error ("%s", e.what ());
}
}
Note that if those errors are reached, we lose the original
exception's error code. I can't see why we'd want that.
And, I can't see why we need to have interp_exec catch the exception
and return it via the normal return path. That's normally needed when
we need to handle propagating exceptions across C code, like across
readline or ncurses, but that's not the case here.
It seems to me that we can simplify things by removing some
try/catch-ing and just letting exceptions propagate normally.
Note, the "error in command" error shown above, which only exists in
the CLI interpreter-exec command, is only ever printed AFAICS if you
run "interpreter-exec console" when the top level interpreter is
already the console/tui. Like:
(gdb) interpreter-exec console "foobar"
Undefined command: "foobar". Try "help".
error in command: "foobar".
You won't see it with MI's "-interpreter-exec console" from a top
level MI interpreter:
(gdb)
-interpreter-exec console "foobar"
&"Undefined command: \"foobar\". Try \"help\".\n"
^error,msg="Undefined command: \"foobar\". Try \"help\"."
(gdb)
nor with MI's "-interpreter-exec mi" from a top level MI interpreter:
(gdb)
-interpreter-exec mi "-foobar"
^error,msg="Undefined MI command: foobar",code="undefined-command"
^done
(gdb)
in both these cases because MI's -interpreter-exec just does:
error ("%s", e.what ());
You won't see it either when running an MI command with the CLI's
"interpreter-exec mi":
(gdb) interpreter-exec mi "-foobar"
^error,msg="Undefined MI command: foobar",code="undefined-command"
(gdb)
This last case is because MI's interp::exec implementation never
returns an error:
gdb_exception
mi_interp::exec (const char *command)
{
mi_execute_command_wrapper (command);
return gdb_exception ();
}
Thus I think that "error in command" error is pretty pointless, and
since it simplifies things to not have it, the patch just removes it.
The patch also ends up addressing an old FIXME.
Change-Id: I5a6432a80496934ac7127594c53bf5221622e393
Approved-By: Tom Tromey <tromey@adacore.com>
Approved-By: Kevin Buettner <kevinb@redhat.com>
2023-01-28 02:07:56 +08:00
|
|
|
void exec (const char *command_str) override;
|
2022-06-17 23:38:20 +08:00
|
|
|
ui_out *interp_ui_out () override;
|
|
|
|
void set_logging (ui_file_up logfile, bool logging_redirect,
|
|
|
|
bool debug_redirect) override;
|
|
|
|
void pre_command_loop () override;
|
|
|
|
|
gdb: add interp::on_signal_received method
Instead of having the interpreter code registering observers for the
signal_received observable, add a "signal_received" virtual method to
struct interp. Add a interps_notify_signal_received function that loops
over all UIs and calls the signal_received method on the interpreter.
Finally, add a notify_signal_received function that calls
interps_notify_signal_received and then notifies the observers. Replace
all existing notifications to the signal_received observers with calls
to notify_signal_received.
Before this patch, the CLI and MI code both register a signal_received
observer. These observer go over all UIs, and, for those that have a
interpreter of the right kind, print the stop notifiation.
After this patch, we have just one "loop over all UIs", inside
interps_notify_signal_received. Since the interp::on_signal_received
method gets called once for each interpreter, the implementations only
need to deal with the current interpreter (the "this" pointer).
The motivation for this patch comes from a future patch, that makes the
amdgpu code register an observer to print a warning after the CLI's
signal stop message. Since the amdgpu and the CLI code both use
observers, the order of the two messages is not stable, unless we define
the priority using the observer dependency system. However, the
approach of using virtual methods on the interpreters seems like a good
change anyway, I think it's more straightforward and simple to
understand than the current solution that uses observers. We are sure
that the amdgpu message gets printed after the CLI message, since
observers are notified after interpreters.
Keep the signal_received, even if nothing uses if, because we will be
using it in the upcoming amdgpu patch implementing the warning described
above.
Change-Id: I4d8614bb8f6e0717f4bfc2a59abded3702f23ac4
2023-03-02 05:48:36 +08:00
|
|
|
void on_signal_received (gdb_signal sig) override;
|
2023-04-21 02:02:28 +08:00
|
|
|
void on_signal_exited (gdb_signal sig) override;
|
2023-03-02 09:38:35 +08:00
|
|
|
void on_normal_stop (struct bpstat *bs, int print_frame) override;
|
2023-04-21 02:46:58 +08:00
|
|
|
void on_exited (int status) override;
|
2023-04-21 03:35:18 +08:00
|
|
|
void on_no_history () override;
|
2023-04-21 03:47:59 +08:00
|
|
|
void on_sync_execution_done () override;
|
2023-04-29 02:55:18 +08:00
|
|
|
void on_command_error () override;
|
2023-04-21 04:07:12 +08:00
|
|
|
void on_user_selected_context_changed (user_selected_what selection) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_new_thread (thread_info *t) override;
|
2023-10-13 17:27:48 +08:00
|
|
|
void on_thread_exited (thread_info *t, std::optional<ULONGEST> exit_code,
|
gdb: centralize "[Thread ...exited]" notifications
Currently, each target backend is responsible for printing "[Thread
...exited]" before deleting a thread. This leads to unnecessary
differences between targets, like e.g. with the remote target, we
never print such messages, even though we do print "[New Thread ...]".
E.g., debugging the gdb.threads/attach-many-short-lived-threads.exp
with gdbserver, letting it run for a bit, and then pressing Ctrl-C, we
currently see:
(gdb) c
Continuing.
^C[New Thread 3850398.3887449]
[New Thread 3850398.3887500]
[New Thread 3850398.3887551]
[New Thread 3850398.3887602]
[New Thread 3850398.3887653]
...
Thread 1 "attach-many-sho" received signal SIGINT, Interrupt.
0x00007ffff7e6a23f in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffda80, rem=rem@entry=0x7fffffffda80)
at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
78 in ../sysdeps/unix/sysv/linux/clock_nanosleep.c
(gdb)
Above, we only see "New Thread" notifications, even though threads
were deleted.
After this patch, we'll see:
(gdb) c
Continuing.
^C[Thread 3558643.3577053 exited]
[Thread 3558643.3577104 exited]
[Thread 3558643.3577155 exited]
[Thread 3558643.3579603 exited]
...
[New Thread 3558643.3597415]
[New Thread 3558643.3600015]
[New Thread 3558643.3599965]
...
Thread 1 "attach-many-sho" received signal SIGINT, Interrupt.
0x00007ffff7e6a23f in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7fffffffda80, rem=rem@entry=0x7fffffffda80)
at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:78
78 in ../sysdeps/unix/sysv/linux/clock_nanosleep.c
(gdb) q
This commit fixes this by moving the thread exit printing to common
code instead, triggered from within delete_thread (or rather,
set_thread_exited).
There's one wrinkle, though. While most targest want to print:
[Thread ... exited]
the Windows target wants to print:
[Thread ... exited with code <exit_code>]
... and sometimes wants to suppress the notification for the main
thread. To address that, this commits adds a delete_thread_with_code
function, only used by that target (so far).
This fix was originally posted as part of a larger series:
https://inbox.sourceware.org/gdb-patches/20221212203101.1034916-1-pedro@palves.net/
But didn't really need to be part of that series. In order to get
this fix merged sooner, I (Andrew Burgess) have rebased this commit
outside of the original series. Any bugs introduced while splitting
this patch out and rebasing, are entirely my own.
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=30129
Co-Authored-By: Andrew Burgess <aburgess@redhat.com>
2022-12-13 04:31:00 +08:00
|
|
|
int silent) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_inferior_added (inferior *inf) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_inferior_appeared (inferior *inf) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_inferior_disappeared (inferior *inf) override;
|
2023-05-02 23:35:36 +08:00
|
|
|
void on_inferior_removed (inferior *inf) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_record_changed (inferior *inf, int started, const char *method,
|
|
|
|
const char *format) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_target_resumed (ptid_t ptid) override;
|
2024-02-06 04:18:33 +08:00
|
|
|
void on_solib_loaded (const solib &so) override;
|
|
|
|
void on_solib_unloaded (const solib &so) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_about_to_proceed () override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_traceframe_changed (int tfnum, int tpnum) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_tsv_created (const trace_state_variable *tsv) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_tsv_deleted (const trace_state_variable *tsv) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_tsv_modified (const trace_state_variable *tsv) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_breakpoint_created (breakpoint *b) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_breakpoint_deleted (breakpoint *b) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_breakpoint_modified (breakpoint *b) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_param_changed (const char *param, const char *value) override;
|
2023-04-21 21:45:30 +08:00
|
|
|
void on_memory_changed (inferior *inf, CORE_ADDR addr, ssize_t len,
|
|
|
|
const bfd_byte *data) override;
|
gdb: add interp::on_signal_received method
Instead of having the interpreter code registering observers for the
signal_received observable, add a "signal_received" virtual method to
struct interp. Add a interps_notify_signal_received function that loops
over all UIs and calls the signal_received method on the interpreter.
Finally, add a notify_signal_received function that calls
interps_notify_signal_received and then notifies the observers. Replace
all existing notifications to the signal_received observers with calls
to notify_signal_received.
Before this patch, the CLI and MI code both register a signal_received
observer. These observer go over all UIs, and, for those that have a
interpreter of the right kind, print the stop notifiation.
After this patch, we have just one "loop over all UIs", inside
interps_notify_signal_received. Since the interp::on_signal_received
method gets called once for each interpreter, the implementations only
need to deal with the current interpreter (the "this" pointer).
The motivation for this patch comes from a future patch, that makes the
amdgpu code register an observer to print a warning after the CLI's
signal stop message. Since the amdgpu and the CLI code both use
observers, the order of the two messages is not stable, unless we define
the priority using the observer dependency system. However, the
approach of using virtual methods on the interpreters seems like a good
change anyway, I think it's more straightforward and simple to
understand than the current solution that uses observers. We are sure
that the amdgpu message gets printed after the CLI message, since
observers are notified after interpreters.
Keep the signal_received, even if nothing uses if, because we will be
using it in the upcoming amdgpu patch implementing the warning described
above.
Change-Id: I4d8614bb8f6e0717f4bfc2a59abded3702f23ac4
2023-03-02 05:48:36 +08:00
|
|
|
|
2022-06-17 23:38:20 +08:00
|
|
|
/* MI's output channels */
|
|
|
|
mi_console_file *out;
|
|
|
|
mi_console_file *err;
|
|
|
|
mi_console_file *log;
|
|
|
|
mi_console_file *targ;
|
|
|
|
mi_console_file *event_channel;
|
|
|
|
|
|
|
|
/* Raw console output. */
|
|
|
|
struct ui_file *raw_stdout;
|
|
|
|
|
2022-08-12 00:24:48 +08:00
|
|
|
/* Save the original value of raw_stdout here when logging, and the
|
|
|
|
file which we need to delete, so we can restore correctly when
|
2022-06-17 23:38:20 +08:00
|
|
|
done. */
|
|
|
|
struct ui_file *saved_raw_stdout;
|
2022-11-29 05:05:05 +08:00
|
|
|
ui_file_up logfile_holder;
|
|
|
|
ui_file_up stdout_holder;
|
2022-06-17 23:38:20 +08:00
|
|
|
|
|
|
|
/* MI's builder. */
|
|
|
|
struct ui_out *mi_uiout;
|
|
|
|
|
|
|
|
/* MI's CLI builder (wraps OUT). */
|
|
|
|
struct ui_out *cli_uiout;
|
gdb/mi: fix ^running record with multiple MI interpreters
I stumbled on the mi_proceeded and running_result_record_printed
globals, which are shared by all MI interpreter instances (it's unlikely
that people use multiple MI interpreter instances, but it's possible).
After poking at it, I found this bug:
1. Start GDB in MI mode
2. Add a second MI interpreter with the new-ui command
3. Use -exec-run on the second interpreter
This is the output I get on the first interpreter:
=thread-group-added,id="i1"
~"Reading symbols from a.out...\n"
~"New UI allocated\n"
(gdb)
=thread-group-started,id="i1",pid="94718"
=thread-created,id="1",group-id="i1"
^running
*running,thread-id="all"
And this is the output I get on the second intepreter:
=thread-group-added,id="i1"
(gdb)
-exec-run
=thread-group-started,id="i1",pid="94718"
=thread-created,id="1",group-id="i1"
*running,thread-id="all"
The problem here is that the `^running` reply to the -exec-run command
is printed on the wrong UI. It is printed on the first one, it should
be printed on the second (the one on which we sent the -exec-run).
What happens under the hood is that captured_mi_execute_command, while
executing a command for the second intepreter, clears the
running_result_record_printed and mi_proceeded globals.
mi_about_to_proceed then sets mi_proceeded. Then, mi_on_resume_1 gets
called for the first intepreter first. Since the
!running_result_record_printed && mi_proceeded
condition is true, it prints a ^running, and sets
running_result_record_printed. When mi_on_resume_1 gets called for the
second interpreter, running_result_record_printed is already set, so
^running is not printed there.
It took me a while to understand the relationship between these two
variables. I think that in the end, this is what we want to track:
1. When executing an MI command, take note if that command causes a
"proceed". This is done in mi_about_to_proceed.
2. In mi_on_resume_1, if the command indeed caused a "proceed", we want
to output a ^running record. And we want to remember that we did,
because...
3. Back in captured_mi_execute_command, if we did not output a
^running, we want to output a ^done.
Moving those two variables to the mi_interp struture appears to fix it.
Only for the interpreter doing the -exec-run command does the
running_result_record_printed flag get cleared, and therefore only or
that one does the ^running record get printed.
Add a new test for this, that does pretty much what the reproducer above
shows. Without the fix, the test fails because
mi_send_resuming_command_raw never sees the ^running record.
Change-Id: I63ea30e6cb61a8e1dd5ef03377e6003381a9209b
Tested-By: Alexandra Petlanova Hajkova <ahajkova@redhat.com>
2023-04-22 00:08:42 +08:00
|
|
|
|
|
|
|
int running_result_record_printed = 1;
|
|
|
|
|
|
|
|
/* Flag indicating that the target has proceeded since the last
|
|
|
|
command was issued. */
|
|
|
|
int mi_proceeded;
|
2023-09-06 23:02:00 +08:00
|
|
|
|
|
|
|
const char *current_token;
|
2022-06-17 23:38:20 +08:00
|
|
|
};
|
|
|
|
|
2017-03-21 02:57:51 +08:00
|
|
|
/* Output the shared object attributes to UIOUT. */
|
|
|
|
|
2024-02-06 04:18:33 +08:00
|
|
|
void mi_output_solib_attribs (ui_out *uiout, const solib &solib);
|
2017-03-21 02:57:51 +08:00
|
|
|
|
2023-06-09 04:06:45 +08:00
|
|
|
/* Returns the INTERP's data cast as mi_interp if INTERP is an MI, and
|
|
|
|
returns NULL otherwise. */
|
|
|
|
|
|
|
|
static inline struct mi_interp *
|
|
|
|
as_mi_interp (struct interp *interp)
|
|
|
|
{
|
|
|
|
return dynamic_cast<mi_interp *> (interp);
|
|
|
|
}
|
|
|
|
|
2019-01-28 03:51:36 +08:00
|
|
|
#endif /* MI_MI_INTERP_H */
|