2024-01-12 23:30:44 +08:00
|
|
|
/* Copyright (C) 2023-2024 Free Software Foundation, Inc.
|
2023-04-29 02:27:11 +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/>. */
|
|
|
|
|
|
|
|
#ifndef UI_H
|
|
|
|
#define UI_H
|
|
|
|
|
|
|
|
#include "gdbsupport/event-loop.h"
|
2023-04-29 02:27:13 +08:00
|
|
|
#include "gdbsupport/intrusive_list.h"
|
2023-04-29 02:27:11 +08:00
|
|
|
#include "gdbsupport/next-iterator.h"
|
2024-04-29 23:07:22 +08:00
|
|
|
#include "gdbsupport/scoped_restore.h"
|
2023-04-29 02:27:11 +08:00
|
|
|
|
2023-04-29 02:27:13 +08:00
|
|
|
struct interp;
|
|
|
|
|
2023-04-29 02:27:11 +08:00
|
|
|
/* Prompt state. */
|
|
|
|
|
|
|
|
enum prompt_state
|
|
|
|
{
|
|
|
|
/* The command line is blocked simulating synchronous execution.
|
|
|
|
This is used to implement the foreground execution commands
|
|
|
|
('run', 'continue', etc.). We won't display the prompt and
|
|
|
|
accept further commands until the execution is actually over. */
|
|
|
|
PROMPT_BLOCKED,
|
|
|
|
|
|
|
|
/* The command finished; display the prompt before returning back to
|
|
|
|
the top level. */
|
|
|
|
PROMPT_NEEDED,
|
|
|
|
|
|
|
|
/* We've displayed the prompt already, ready for input. */
|
|
|
|
PROMPTED,
|
|
|
|
};
|
|
|
|
|
|
|
|
/* All about a user interface instance. Each user interface has its
|
|
|
|
own I/O files/streams, readline state, its own top level
|
|
|
|
interpreter (for the main UI, this is the interpreter specified
|
|
|
|
with -i on the command line) and secondary interpreters (for
|
|
|
|
interpreter-exec ...), etc. There's always one UI associated with
|
|
|
|
stdin/stdout/stderr, but the user can create secondary UIs, for
|
|
|
|
example, to create a separate MI channel on its own stdio
|
|
|
|
streams. */
|
|
|
|
|
|
|
|
struct ui
|
|
|
|
{
|
|
|
|
/* Create a new UI. */
|
|
|
|
ui (FILE *instream, FILE *outstream, FILE *errstream);
|
|
|
|
~ui ();
|
|
|
|
|
|
|
|
DISABLE_COPY_AND_ASSIGN (ui);
|
|
|
|
|
|
|
|
/* Pointer to next in singly-linked list. */
|
|
|
|
struct ui *next = nullptr;
|
|
|
|
|
|
|
|
/* Convenient handle (UI number). Unique across all UIs. */
|
|
|
|
int num;
|
|
|
|
|
|
|
|
/* The UI's command line buffer. This is to used to accumulate
|
|
|
|
input until we have a whole command line. */
|
|
|
|
std::string line_buffer;
|
|
|
|
|
|
|
|
/* The callback used by the event loop whenever an event is detected
|
|
|
|
on the UI's input file descriptor. This function incrementally
|
|
|
|
builds a buffer where it accumulates the line read up to the
|
|
|
|
point of invocation. In the special case in which the character
|
|
|
|
read is newline, the function invokes the INPUT_HANDLER callback
|
|
|
|
(see below). */
|
|
|
|
void (*call_readline) (gdb_client_data) = nullptr;
|
|
|
|
|
|
|
|
/* The function to invoke when a complete line of input is ready for
|
|
|
|
processing. */
|
|
|
|
void (*input_handler) (gdb::unique_xmalloc_ptr<char> &&) = nullptr;
|
|
|
|
|
|
|
|
/* True if this UI is using the readline library for command
|
|
|
|
editing; false if using GDB's own simple readline emulation, with
|
|
|
|
no editing support. */
|
|
|
|
int command_editing = 0;
|
|
|
|
|
|
|
|
/* Each UI has its own independent set of interpreters. */
|
2023-04-29 02:27:13 +08:00
|
|
|
intrusive_list<interp> interp_list;
|
|
|
|
interp *current_interpreter = nullptr;
|
|
|
|
interp *top_level_interpreter = nullptr;
|
|
|
|
|
|
|
|
/* The interpreter that is active while `interp_exec' is active, NULL
|
|
|
|
at all other times. */
|
|
|
|
interp *command_interpreter = nullptr;
|
2023-04-29 02:27:11 +08:00
|
|
|
|
|
|
|
/* True if the UI is in async mode, false if in sync mode. If in
|
|
|
|
sync mode, a synchronous execution command (e.g, "next") does not
|
|
|
|
return until the command is finished. If in async mode, then
|
|
|
|
running a synchronous command returns right after resuming the
|
|
|
|
target. Waiting for the command's completion is later done on
|
|
|
|
the top event loop. For the main UI, this starts out disabled,
|
|
|
|
until all the explicit command line arguments (e.g., `gdb -ex
|
|
|
|
"start" -ex "next"') are processed. */
|
|
|
|
int async = 0;
|
|
|
|
|
|
|
|
/* The number of nested readline secondary prompts that are
|
|
|
|
currently active. */
|
|
|
|
int secondary_prompt_depth = 0;
|
|
|
|
|
|
|
|
/* The UI's stdin. Set to stdin for the main UI. */
|
|
|
|
FILE *stdin_stream;
|
|
|
|
|
|
|
|
/* stdio stream that command input is being read from. Set to stdin
|
|
|
|
normally. Set by source_command to the file we are sourcing.
|
|
|
|
Set to NULL if we are executing a user-defined command or
|
|
|
|
interacting via a GUI. */
|
|
|
|
FILE *instream;
|
|
|
|
/* Standard output stream. */
|
|
|
|
FILE *outstream;
|
|
|
|
/* Standard error stream. */
|
|
|
|
FILE *errstream;
|
|
|
|
|
|
|
|
/* The file descriptor for the input stream, so that we can register
|
|
|
|
it with the event loop. This can be set to -1 to prevent this
|
|
|
|
registration. */
|
|
|
|
int input_fd;
|
|
|
|
|
|
|
|
/* Whether ISATTY returns true on input_fd. Cached here because
|
|
|
|
quit_force needs to know this _after_ input_fd might be
|
|
|
|
closed. */
|
|
|
|
bool m_input_interactive_p;
|
|
|
|
|
|
|
|
/* See enum prompt_state's description. */
|
|
|
|
enum prompt_state prompt_state = PROMPT_NEEDED;
|
|
|
|
|
gdb, python: selectively omit enabling stdin in gdb.execute
From the Python API, we can execute GDB commands via gdb.execute. If
the command gives an exception, however, we need to recover the GDB
prompt and enable stdin, because the exception does not reach
top-level GDB or normal_stop. This was done in commit
commit 1ba1ac88011703abcd0271e4f5d00927dc69a09a
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date: Tue Nov 19 11:17:20 2019 +0000
gdb: Enable stdin on exception in execute_gdb_command
with the following code:
catch (const gdb_exception &except)
{
/* If an exception occurred then we won't hit normal_stop (), or have
an exception reach the top level of the event loop, which are the
two usual places in which stdin would be re-enabled. So, before we
convert the exception and continue back in Python, we should
re-enable stdin here. */
async_enable_stdin ();
GDB_PY_HANDLE_EXCEPTION (except);
}
In this patch, we explain what happens when we run a GDB command in
the context of a synchronous command, e.g. via Python observer
notifications.
As an example, suppose we have the following objfile event listener,
specified in a file named file.py:
~~~
import gdb
class MyListener:
def __init__(self):
gdb.events.new_objfile.connect(self.handle_new_objfile_event)
self.processed_objfile = False
def handle_new_objfile_event(self, event):
if self.processed_objfile:
return
print("loading " + event.new_objfile.filename)
self.processed_objfile = True
gdb.execute('add-inferior -no-connection')
gdb.execute('inferior 2')
gdb.execute('target remote | gdbserver - /tmp/a.out')
gdb.execute('inferior 1')
the_listener = MyListener()
~~~
Using this Python file, we see the behavior below:
$ gdb -q -ex "source file.py" -ex "run" --args a.out
Reading symbols from a.out...
Starting program: /tmp/a.out
loading /lib64/ld-linux-x86-64.so.2
[New inferior 2]
Added inferior 2
[Switching to inferior 2 [<null>] (<noexec>)]
stdin/stdout redirected
Process /tmp/a.out created; pid = 3075406
Remote debugging using stdio
Reading /tmp/a.out from remote target...
...
[Switching to inferior 1 [process 3075400] (/tmp/a.out)]
[Switching to thread 1.1 (process 3075400)]
#0 0x00007ffff7fe3290 in ?? () from /lib64/ld-linux-x86-64.so.2
(gdb) [Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Inferior 1 (process 3075400) exited normally]
Note how the GDB prompt comes in-between the debugger output. We have this
obscure behavior, because the executed command, "target remote", triggers
an invocation of `normal_stop` that enables stdin. After that, however,
the Python notification context completes and GDB continues with its normal
flow of executing the 'run' command. This can be seen in the call stack
below:
(top-gdb) bt
#0 async_enable_stdin () at src/gdb/event-top.c:523
#1 0x00005555561c3acd in normal_stop () at src/gdb/infrun.c:9432
#2 0x00005555561b328e in start_remote (from_tty=0) at src/gdb/infrun.c:3801
#3 0x0000555556441224 in remote_target::start_remote_1 (this=0x5555587882e0, from_tty=0, extended_p=0) at src/gdb/remote.c:5225
#4 0x000055555644166c in remote_target::start_remote (this=0x5555587882e0, from_tty=0, extended_p=0) at src/gdb/remote.c:5316
#5 0x00005555564430cf in remote_target::open_1 (name=0x55555878525e "| gdbserver - /tmp/a.out", from_tty=0, extended_p=0) at src/gdb/remote.c:6175
#6 0x0000555556441707 in remote_target::open (name=0x55555878525e "| gdbserver - /tmp/a.out", from_tty=0) at src/gdb/remote.c:5338
#7 0x00005555565ea63f in open_target (args=0x55555878525e "| gdbserver - /tmp/a.out", from_tty=0, command=0x555558589280) at src/gdb/target.c:824
#8 0x0000555555f0d89a in cmd_func (cmd=0x555558589280, args=0x55555878525e "| gdbserver - /tmp/a.out", from_tty=0) at src/gdb/cli/cli-decode.c:2735
#9 0x000055555661fb42 in execute_command (p=0x55555878529e "t", from_tty=0) at src/gdb/top.c:575
#10 0x0000555555f1a506 in execute_control_command_1 (cmd=0x555558756f00, from_tty=0) at src/gdb/cli/cli-script.c:529
#11 0x0000555555f1abea in execute_control_command (cmd=0x555558756f00, from_tty=0) at src/gdb/cli/cli-script.c:701
#12 0x0000555555f19fc7 in execute_control_commands (cmdlines=0x555558756f00, from_tty=0) at src/gdb/cli/cli-script.c:411
#13 0x0000555556400d91 in execute_gdb_command (self=0x7ffff43b5d00, args=0x7ffff440ab60, kw=0x0) at src/gdb/python/python.c:700
#14 0x00007ffff7a96023 in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#15 0x00007ffff7a4dadc in _PyObject_MakeTpCall () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#16 0x00007ffff79e9a1c in _PyEval_EvalFrameDefault () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#17 0x00007ffff7b303af in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#18 0x00007ffff7a50358 in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#19 0x00007ffff7a4f3f4 in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#20 0x00007ffff7a4f883 in PyObject_CallFunctionObjArgs () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#21 0x00005555563a9758 in evpy_emit_event (event=0x7ffff42b5430, registry=0x7ffff42b4690) at src/gdb/python/py-event.c:104
#22 0x00005555563cb874 in emit_new_objfile_event (objfile=0x555558761700) at src/gdb/python/py-newobjfileevent.c:52
#23 0x00005555563b53bc in python_new_objfile (objfile=0x555558761700) at src/gdb/python/py-inferior.c:195
#24 0x0000555555d6dff0 in std::__invoke_impl<void, void (*&)(objfile*), objfile*> (__f=@0x5555585b5860: 0x5555563b5360 <python_new_objfile(objfile*)>) at /usr/include/c++/11/bits/invoke.h:61
#25 0x0000555555d6be18 in std::__invoke_r<void, void (*&)(objfile*), objfile*> (__fn=@0x5555585b5860: 0x5555563b5360 <python_new_objfile(objfile*)>) at /usr/include/c++/11/bits/invoke.h:111
#26 0x0000555555d69661 in std::_Function_handler<void (objfile*), void (*)(objfile*)>::_M_invoke(std::_Any_data const&, objfile*&&) (__functor=..., __args#0=@0x7fffffffd080: 0x555558761700) at /usr/include/c++/11/bits/std_function.h:290
#27 0x0000555556314caf in std::function<void (objfile*)>::operator()(objfile*) const (this=0x5555585b5860, __args#0=0x555558761700) at /usr/include/c++/11/bits/std_function.h:590
#28 0x000055555631444e in gdb::observers::observable<objfile*>::notify (this=0x55555836eea0 <gdb::observers::new_objfile>, args#0=0x555558761700) at src/gdb/../gdbsupport/observable.h:166
#29 0x0000555556599b3f in symbol_file_add_with_addrs (abfd=..., name=0x55555875d310 "/lib64/ld-linux-x86-64.so.2", add_flags=..., addrs=0x7fffffffd2f0, flags=..., parent=0x0) at src/gdb/symfile.c:1125
#30 0x0000555556599ca4 in symbol_file_add_from_bfd (abfd=..., name=0x55555875d310 "/lib64/ld-linux-x86-64.so.2", add_flags=..., addrs=0x7fffffffd2f0, flags=..., parent=0x0) at src/gdb/symfile.c:1160
#31 0x0000555556546371 in solib_read_symbols (so=..., flags=...) at src/gdb/solib.c:692
#32 0x0000555556546f0f in solib_add (pattern=0x0, from_tty=0, readsyms=1) at src/gdb/solib.c:1015
#33 0x0000555556539891 in enable_break (info=0x55555874e180, from_tty=0) at src/gdb/solib-svr4.c:2416
#34 0x000055555653b305 in svr4_solib_create_inferior_hook (from_tty=0) at src/gdb/solib-svr4.c:3058
#35 0x0000555556547cee in solib_create_inferior_hook (from_tty=0) at src/gdb/solib.c:1217
#36 0x0000555556196f6a in post_create_inferior (from_tty=0) at src/gdb/infcmd.c:275
#37 0x0000555556197670 in run_command_1 (args=0x0, from_tty=1, run_how=RUN_NORMAL) at src/gdb/infcmd.c:486
#38 0x000055555619783f in run_command (args=0x0, from_tty=1) at src/gdb/infcmd.c:512
#39 0x0000555555f0798d in do_simple_func (args=0x0, from_tty=1, c=0x555558567510) at src/gdb/cli/cli-decode.c:95
#40 0x0000555555f0d89a in cmd_func (cmd=0x555558567510, args=0x0, from_tty=1) at src/gdb/cli/cli-decode.c:2735
#41 0x000055555661fb42 in execute_command (p=0x7fffffffe2c4 "", from_tty=1) at src/gdb/top.c:575
#42 0x000055555626303b in catch_command_errors (command=0x55555661f4ab <execute_command(char const*, int)>, arg=0x7fffffffe2c1 "run", from_tty=1, do_bp_actions=true) at src/gdb/main.c:513
#43 0x000055555626328a in execute_cmdargs (cmdarg_vec=0x7fffffffdaf0, file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x7fffffffda3c) at src/gdb/main.c:612
#44 0x0000555556264849 in captured_main_1 (context=0x7fffffffdd40) at src/gdb/main.c:1293
#45 0x0000555556264a7f in captured_main (data=0x7fffffffdd40) at src/gdb/main.c:1314
#46 0x0000555556264b2e in gdb_main (args=0x7fffffffdd40) at src/gdb/main.c:1343
#47 0x0000555555ceccab in main (argc=9, argv=0x7fffffffde78) at src/gdb/gdb.c:39
(top-gdb)
The use of the "target remote" command here is just an example. In
principle, we would reproduce the problem with any command that
triggers an invocation of `normal_stop`.
To omit enabling the stdin in `normal_stop`, we would have to check the
context we are in. Since we cannot do that, we add a new field to
`struct ui` to track whether the prompt was already blocked, and set
the tracker flag in the Python context before executing a GDB command.
After applying this patch, the output becomes
...
Reading symbols from a.out...
Starting program: /tmp/a.out
loading /lib64/ld-linux-x86-64.so.2
[New inferior 2]
Added inferior 2
[Switching to inferior 2 [<null>] (<noexec>)]
stdin/stdout redirected
Process /tmp/a.out created; pid = 3032261
Remote debugging using stdio
Reading /tmp/a.out from remote target...
...
[Switching to inferior 1 [process 3032255] (/tmp/a.out)]
[Switching to thread 1.1 (process 3032255)]
#0 0x00007ffff7fe3290 in ?? () from /lib64/ld-linux-x86-64.so.2
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[Inferior 1 (process 3032255) exited normally]
(gdb)
Let's now consider a secondary scenario, where the command executed from
the Python raises an error. As an example, suppose we have the Python
file below:
def handle_new_objfile_event(self, event):
...
print("loading " + event.new_objfile.filename)
self.processed_objfile = True
gdb.execute('print a')
The executed command, "print a", gives an error because "a" is not
defined. Without this patch, we see the behavior below, where the
prompt is again placed incorrectly:
...
Reading symbols from /tmp/a.out...
Starting program: /tmp/a.out
loading /lib64/ld-linux-x86-64.so.2
Python Exception <class 'gdb.error'>: No symbol "a" in current context.
(gdb) [Inferior 1 (process 3980401) exited normally]
This time, `async_enable_stdin` is called from the 'catch' block in
`execute_gdb_command`:
(top-gdb) bt
#0 async_enable_stdin () at src/gdb/event-top.c:523
#1 0x0000555556400f0a in execute_gdb_command (self=0x7ffff43b5d00, args=0x7ffff440ab60, kw=0x0) at src/gdb/python/python.c:713
#2 0x00007ffff7a96023 in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#3 0x00007ffff7a4dadc in _PyObject_MakeTpCall () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#4 0x00007ffff79e9a1c in _PyEval_EvalFrameDefault () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#5 0x00007ffff7b303af in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#6 0x00007ffff7a50358 in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#7 0x00007ffff7a4f3f4 in ?? () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#8 0x00007ffff7a4f883 in PyObject_CallFunctionObjArgs () from /lib/x86_64-linux-gnu/libpython3.10.so.1.0
#9 0x00005555563a9758 in evpy_emit_event (event=0x7ffff42b5430, registry=0x7ffff42b4690) at src/gdb/python/py-event.c:104
#10 0x00005555563cb874 in emit_new_objfile_event (objfile=0x555558761410) at src/gdb/python/py-newobjfileevent.c:52
#11 0x00005555563b53bc in python_new_objfile (objfile=0x555558761410) at src/gdb/python/py-inferior.c:195
#12 0x0000555555d6dff0 in std::__invoke_impl<void, void (*&)(objfile*), objfile*> (__f=@0x5555585b5860: 0x5555563b5360 <python_new_objfile(objfile*)>) at /usr/include/c++/11/bits/invoke.h:61
#13 0x0000555555d6be18 in std::__invoke_r<void, void (*&)(objfile*), objfile*> (__fn=@0x5555585b5860: 0x5555563b5360 <python_new_objfile(objfile*)>) at /usr/include/c++/11/bits/invoke.h:111
#14 0x0000555555d69661 in std::_Function_handler<void (objfile*), void (*)(objfile*)>::_M_invoke(std::_Any_data const&, objfile*&&) (__functor=..., __args#0=@0x7fffffffd080: 0x555558761410) at /usr/include/c++/11/bits/std_function.h:290
#15 0x0000555556314caf in std::function<void (objfile*)>::operator()(objfile*) const (this=0x5555585b5860, __args#0=0x555558761410) at /usr/include/c++/11/bits/std_function.h:590
#16 0x000055555631444e in gdb::observers::observable<objfile*>::notify (this=0x55555836eea0 <gdb::observers::new_objfile>, args#0=0x555558761410) at src/gdb/../gdbsupport/observable.h:166
#17 0x0000555556599b3f in symbol_file_add_with_addrs (abfd=..., name=0x55555875d020 "/lib64/ld-linux-x86-64.so.2", add_flags=..., addrs=0x7fffffffd2f0, flags=..., parent=0x0) at src/gdb/symfile.c:1125
#18 0x0000555556599ca4 in symbol_file_add_from_bfd (abfd=..., name=0x55555875d020 "/lib64/ld-linux-x86-64.so.2", add_flags=..., addrs=0x7fffffffd2f0, flags=..., parent=0x0) at src/gdb/symfile.c:1160
#19 0x0000555556546371 in solib_read_symbols (so=..., flags=...) at src/gdb/solib.c:692
#20 0x0000555556546f0f in solib_add (pattern=0x0, from_tty=0, readsyms=1) at src/gdb/solib.c:1015
#21 0x0000555556539891 in enable_break (info=0x55555874a670, from_tty=0) at src/gdb/solib-svr4.c:2416
#22 0x000055555653b305 in svr4_solib_create_inferior_hook (from_tty=0) at src/gdb/solib-svr4.c:3058
#23 0x0000555556547cee in solib_create_inferior_hook (from_tty=0) at src/gdb/solib.c:1217
#24 0x0000555556196f6a in post_create_inferior (from_tty=0) at src/gdb/infcmd.c:275
#25 0x0000555556197670 in run_command_1 (args=0x0, from_tty=1, run_how=RUN_NORMAL) at src/gdb/infcmd.c:486
#26 0x000055555619783f in run_command (args=0x0, from_tty=1) at src/gdb/infcmd.c:512
#27 0x0000555555f0798d in do_simple_func (args=0x0, from_tty=1, c=0x555558567510) at src/gdb/cli/cli-decode.c:95
#28 0x0000555555f0d89a in cmd_func (cmd=0x555558567510, args=0x0, from_tty=1) at src/gdb/cli/cli-decode.c:2735
#29 0x000055555661fb42 in execute_command (p=0x7fffffffe2c4 "", from_tty=1) at src/gdb/top.c:575
#30 0x000055555626303b in catch_command_errors (command=0x55555661f4ab <execute_command(char const*, int)>, arg=0x7fffffffe2c1 "run", from_tty=1, do_bp_actions=true) at src/gdb/main.c:513
#31 0x000055555626328a in execute_cmdargs (cmdarg_vec=0x7fffffffdaf0, file_type=CMDARG_FILE, cmd_type=CMDARG_COMMAND, ret=0x7fffffffda3c) at src/gdb/main.c:612
#32 0x0000555556264849 in captured_main_1 (context=0x7fffffffdd40) at src/gdb/main.c:1293
#33 0x0000555556264a7f in captured_main (data=0x7fffffffdd40) at src/gdb/main.c:1314
#34 0x0000555556264b2e in gdb_main (args=0x7fffffffdd40) at src/gdb/main.c:1343
#35 0x0000555555ceccab in main (argc=9, argv=0x7fffffffde78) at src/gdb/gdb.c:39
(top-gdb)
Again, after we enable stdin, GDB continues with its normal flow
of the 'run' command and receives the inferior's exit event, where
it would have enabled stdin, if we had not done it prematurely.
(top-gdb) bt
#0 async_enable_stdin () at src/gdb/event-top.c:523
#1 0x00005555561c3acd in normal_stop () at src/gdb/infrun.c:9432
#2 0x00005555561b5bf1 in fetch_inferior_event () at src/gdb/infrun.c:4700
#3 0x000055555618d6a7 in inferior_event_handler (event_type=INF_REG_EVENT) at src/gdb/inf-loop.c:42
#4 0x000055555620ecdb in handle_target_event (error=0, client_data=0x0) at src/gdb/linux-nat.c:4316
#5 0x0000555556f33035 in handle_file_event (file_ptr=0x5555587024e0, ready_mask=1) at src/gdbsupport/event-loop.cc:573
#6 0x0000555556f3362f in gdb_wait_for_event (block=0) at src/gdbsupport/event-loop.cc:694
#7 0x0000555556f322cd in gdb_do_one_event (mstimeout=-1) at src/gdbsupport/event-loop.cc:217
#8 0x0000555556262df8 in start_event_loop () at src/gdb/main.c:407
#9 0x0000555556262f85 in captured_command_loop () at src/gdb/main.c:471
#10 0x0000555556264a84 in captured_main (data=0x7fffffffdd40) at src/gdb/main.c:1324
#11 0x0000555556264b2e in gdb_main (args=0x7fffffffdd40) at src/gdb/main.c:1343
#12 0x0000555555ceccab in main (argc=9, argv=0x7fffffffde78) at src/gdb/gdb.c:39
(top-gdb)
The solution implemented by this patch addresses the problem. After
applying the patch, the output becomes
$ gdb -q -ex "source file.py" -ex "run" --args a.out
Reading symbols from /tmp/a.out...
Starting program: /tmp/a.out
loading /lib64/ld-linux-x86-64.so.2
Python Exception <class 'gdb.error'>: No symbol "a" in current context.
[Inferior 1 (process 3984511) exited normally]
(gdb)
Regression-tested on X86_64 Linux using the default board file (i.e. unix).
Co-Authored-By: Oguzhan Karakaya <oguzhan.karakaya@intel.com>
Reviewed-By: Guinevere Larsen <blarsen@redhat.com>
Approved-By: Tom Tromey <tom@tromey.com>
2024-02-19 17:55:01 +08:00
|
|
|
/* Whether the prompt should be kept blocked. This is useful to not
|
|
|
|
unblock the prompt too early in the context of nested command
|
|
|
|
execution. */
|
|
|
|
bool keep_prompt_blocked = false;
|
|
|
|
|
2023-04-29 02:27:11 +08:00
|
|
|
/* The fields below that start with "m_" are "private". They're
|
|
|
|
meant to be accessed through wrapper macros that make them look
|
|
|
|
like globals. */
|
|
|
|
|
|
|
|
/* The ui_file streams. */
|
|
|
|
/* Normal results */
|
|
|
|
struct ui_file *m_gdb_stdout;
|
|
|
|
/* Input stream */
|
|
|
|
struct ui_file *m_gdb_stdin;
|
|
|
|
/* Serious error notifications */
|
|
|
|
struct ui_file *m_gdb_stderr;
|
|
|
|
/* Log/debug/trace messages that should bypass normal stdout/stderr
|
|
|
|
filtering. */
|
|
|
|
struct ui_file *m_gdb_stdlog;
|
|
|
|
|
|
|
|
/* The current ui_out. */
|
|
|
|
struct ui_out *m_current_uiout = nullptr;
|
|
|
|
|
|
|
|
/* Register the UI's input file descriptor in the event loop. */
|
|
|
|
void register_file_handler ();
|
|
|
|
|
|
|
|
/* Unregister the UI's input file descriptor from the event loop. */
|
|
|
|
void unregister_file_handler ();
|
|
|
|
|
|
|
|
/* Return true if this UI's input fd is a tty. */
|
|
|
|
bool input_interactive_p () const;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* The main UI. This is the UI that is bound to stdin/stdout/stderr.
|
|
|
|
It always exists and is created automatically when GDB starts
|
|
|
|
up. */
|
|
|
|
extern struct ui *main_ui;
|
|
|
|
|
|
|
|
/* The current UI. */
|
|
|
|
extern struct ui *current_ui;
|
|
|
|
|
|
|
|
/* The list of all UIs. */
|
|
|
|
extern struct ui *ui_list;
|
|
|
|
|
|
|
|
/* State for SWITCH_THRU_ALL_UIS. */
|
|
|
|
class switch_thru_all_uis
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
|
|
|
|
switch_thru_all_uis () : m_iter (ui_list), m_save_ui (¤t_ui)
|
|
|
|
{
|
|
|
|
current_ui = ui_list;
|
|
|
|
}
|
|
|
|
|
|
|
|
DISABLE_COPY_AND_ASSIGN (switch_thru_all_uis);
|
|
|
|
|
|
|
|
/* If done iterating, return true; otherwise return false. */
|
|
|
|
bool done () const
|
|
|
|
{
|
|
|
|
return m_iter == NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move to the next UI, setting current_ui if iteration is not yet
|
|
|
|
complete. */
|
|
|
|
void next ()
|
|
|
|
{
|
|
|
|
m_iter = m_iter->next;
|
|
|
|
if (m_iter != NULL)
|
|
|
|
current_ui = m_iter;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
/* Used to iterate through the UIs. */
|
|
|
|
struct ui *m_iter;
|
|
|
|
|
|
|
|
/* Save and restore current_ui. */
|
|
|
|
scoped_restore_tmpl<struct ui *> m_save_ui;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Traverse through all UI, and switch the current UI to the one
|
|
|
|
being iterated. */
|
|
|
|
#define SWITCH_THRU_ALL_UIS() \
|
|
|
|
for (switch_thru_all_uis stau_state; !stau_state.done (); stau_state.next ())
|
|
|
|
|
|
|
|
using ui_range = next_range<ui>;
|
|
|
|
|
|
|
|
/* An adapter that can be used to traverse over all UIs. */
|
|
|
|
static inline
|
|
|
|
ui_range all_uis ()
|
|
|
|
{
|
|
|
|
return ui_range (ui_list);
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* UI_H */
|