]>
Commit | Line | Data |
---|---|---|
4a8f6654 AC |
1 | /* CLI Definitions for GDB, the GNU debugger. |
2 | ||
1d506c26 | 3 | Copyright (C) 2002-2024 Free Software Foundation, Inc. |
4a8f6654 AC |
4 | |
5 | This file is part of GDB. | |
6 | ||
7 | This program is free software; you can redistribute it and/or modify | |
8 | it under the terms of the GNU General Public License as published by | |
a9762ec7 | 9 | the Free Software Foundation; either version 3 of the License, or |
4a8f6654 AC |
10 | (at your option) any later version. |
11 | ||
12 | This program is distributed in the hope that it will be useful, | |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
a9762ec7 | 18 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ |
4a8f6654 AC |
19 | |
20 | #include "defs.h" | |
3c216924 | 21 | #include "cli-interp.h" |
4a8f6654 | 22 | #include "interps.h" |
4a8f6654 AC |
23 | #include "event-top.h" |
24 | #include "ui-out.h" | |
25 | #include "cli-out.h" | |
ef0f16cc | 26 | #include "top.h" |
13d03262 | 27 | #include "ui.h" |
fd664c91 | 28 | #include "infrun.h" |
76727919 | 29 | #include "observable.h" |
26cde2cc PA |
30 | #include "gdbthread.h" |
31 | #include "thread-fsm.h" | |
00431a78 | 32 | #include "inferior.h" |
4a8f6654 | 33 | |
d6f9b0fb PA |
34 | cli_interp_base::cli_interp_base (const char *name) |
35 | : interp (name) | |
36 | {} | |
37 | ||
38 | cli_interp_base::~cli_interp_base () | |
39 | {} | |
40 | ||
8322445e | 41 | /* The console interpreter. */ |
d6f9b0fb PA |
42 | |
43 | class cli_interp final : public cli_interp_base | |
8322445e | 44 | { |
d6f9b0fb PA |
45 | public: |
46 | explicit cli_interp (const char *name); | |
083aca0c | 47 | ~cli_interp () = default; |
d6f9b0fb PA |
48 | |
49 | void init (bool top_level) override; | |
50 | void resume () override; | |
51 | void suspend () override; | |
b885aea1 | 52 | void exec (const char *command_str) override; |
d6f9b0fb PA |
53 | ui_out *interp_ui_out () override; |
54 | ||
083aca0c TT |
55 | private: |
56 | ||
8322445e | 57 | /* The ui_out for the console interpreter. */ |
083aca0c | 58 | std::unique_ptr<cli_ui_out> m_cli_uiout; |
8322445e PA |
59 | }; |
60 | ||
d6f9b0fb | 61 | cli_interp::cli_interp (const char *name) |
083aca0c TT |
62 | : cli_interp_base (name), |
63 | m_cli_uiout (new cli_ui_out (gdb_stdout)) | |
d6f9b0fb | 64 | { |
ba543ca5 GB |
65 | } |
66 | ||
4034d0ff | 67 | /* Suppress notification struct. */ |
f36c8918 | 68 | struct cli_suppress_notification cli_suppress_notification; |
4034d0ff | 69 | |
26cde2cc PA |
70 | /* See cli-interp.h. |
71 | ||
72 | Breakpoint hits should always be mirrored to a console. Deciding | |
73 | what to mirror to a console wrt to breakpoints and random stops | |
74 | gets messy real fast. E.g., say "s" trips on a breakpoint. We'd | |
75 | clearly want to mirror the event to the console in this case. But | |
76 | what about more complicated cases like "s&; thread n; s&", and one | |
77 | of those steps spawning a new thread, and that thread hitting a | |
78 | breakpoint? It's impossible in general to track whether the thread | |
79 | had any relation to the commands that had been executed. So we | |
80 | just simplify and always mirror breakpoints and random events to | |
81 | all consoles. | |
82 | ||
83 | OTOH, we should print the source line to the console when stepping | |
84 | or other similar commands, iff the step was started by that console | |
85 | (or in MI's case, by a console command), but not if it was started | |
86 | with MI's -exec-step or similar. */ | |
87 | ||
88 | int | |
89 | should_print_stop_to_console (struct interp *console_interp, | |
90 | struct thread_info *tp) | |
91 | { | |
92 | if ((bpstat_what (tp->control.stop_bpstat).main_action | |
93 | == BPSTAT_WHAT_STOP_NOISY) | |
573269a8 LS |
94 | || tp->thread_fsm () == nullptr |
95 | || tp->thread_fsm ()->command_interp == console_interp | |
96 | || !tp->thread_fsm ()->finished_p ()) | |
26cde2cc PA |
97 | return 1; |
98 | return 0; | |
99 | } | |
100 | ||
fd664c91 PA |
101 | /* Observers for several run control events. If the interpreter is |
102 | quiet (i.e., another interpreter is being run with | |
5227abd2 PA |
103 | interpreter-exec), print nothing. These are named "cli_base" as |
104 | they print to both CLI interpreters and TUI interpreters. */ | |
fd664c91 | 105 | |
87829267 SM |
106 | void |
107 | cli_interp_base::on_normal_stop (struct bpstat *bs, int print_frame) | |
243a9253 | 108 | { |
eaae60fd PA |
109 | if (!print_frame) |
110 | return; | |
111 | ||
2b826f75 TBA |
112 | /* This event is suppressed. */ |
113 | if (cli_suppress_notification.normal_stop) | |
114 | return; | |
115 | ||
87829267 SM |
116 | thread_info *thread = inferior_thread (); |
117 | if (should_print_stop_to_console (this, thread)) | |
118 | print_stop_event (this->interp_ui_out ()); | |
73ab01a0 | 119 | |
243a9253 PA |
120 | } |
121 | ||
3f75a984 SM |
122 | void |
123 | cli_interp_base::on_signal_received (enum gdb_signal siggnal) | |
fd664c91 | 124 | { |
3f75a984 | 125 | print_signal_received_reason (this->interp_ui_out (), siggnal); |
fd664c91 PA |
126 | } |
127 | ||
d6bd2ef5 SM |
128 | void |
129 | cli_interp_base::on_signal_exited (gdb_signal sig) | |
fd664c91 | 130 | { |
d6bd2ef5 | 131 | print_signal_exited_reason (this->interp_ui_out (), sig); |
fd664c91 PA |
132 | } |
133 | ||
bf64d1d5 SM |
134 | void |
135 | cli_interp_base::on_exited (int status) | |
fd664c91 | 136 | { |
bf64d1d5 | 137 | print_exited_reason (this->interp_ui_out (), status); |
fd664c91 PA |
138 | } |
139 | ||
2e5dbfab SM |
140 | void |
141 | cli_interp_base::on_no_history () | |
fd664c91 | 142 | { |
2e5dbfab | 143 | print_no_history_reason (this->interp_ui_out ()); |
fd664c91 PA |
144 | } |
145 | ||
c3d321de SM |
146 | void |
147 | cli_interp_base::on_sync_execution_done () | |
92bcb5f9 | 148 | { |
73ab01a0 | 149 | display_gdb_prompt (NULL); |
92bcb5f9 PA |
150 | } |
151 | ||
2736b771 SM |
152 | void |
153 | cli_interp_base::on_command_error () | |
92bcb5f9 | 154 | { |
73ab01a0 | 155 | display_gdb_prompt (NULL); |
92bcb5f9 PA |
156 | } |
157 | ||
77cd03e2 SM |
158 | void |
159 | cli_interp_base::on_user_selected_context_changed (user_selected_what selection) | |
4034d0ff | 160 | { |
4034d0ff AT |
161 | /* This event is suppressed. */ |
162 | if (cli_suppress_notification.user_selected_context) | |
163 | return; | |
164 | ||
5227abd2 | 165 | thread_info *tp = inferior_ptid != null_ptid ? inferior_thread () : nullptr; |
4034d0ff | 166 | |
77cd03e2 SM |
167 | if (selection & USER_SELECTED_INFERIOR) |
168 | print_selected_inferior (this->interp_ui_out ()); | |
4034d0ff | 169 | |
77cd03e2 SM |
170 | if (tp != nullptr |
171 | && ((selection & (USER_SELECTED_THREAD | USER_SELECTED_FRAME)))) | |
172 | print_selected_thread_frame (this->interp_ui_out (), selection); | |
4034d0ff AT |
173 | } |
174 | ||
b2d86570 PA |
175 | /* pre_command_loop implementation. */ |
176 | ||
177 | void | |
d6f9b0fb | 178 | cli_interp_base::pre_command_loop () |
b2d86570 PA |
179 | { |
180 | display_gdb_prompt (0); | |
181 | } | |
182 | ||
4a8f6654 AC |
183 | /* These implement the cli out interpreter: */ |
184 | ||
d6f9b0fb PA |
185 | void |
186 | cli_interp::init (bool top_level) | |
4a8f6654 | 187 | { |
4a8f6654 AC |
188 | } |
189 | ||
d6f9b0fb PA |
190 | void |
191 | cli_interp::resume () | |
4a8f6654 | 192 | { |
3c216924 | 193 | struct ui *ui = current_ui; |
38caaeec DJ |
194 | struct ui_file *stream; |
195 | ||
4a8f6654 | 196 | /*sync_execution = 1; */ |
38caaeec | 197 | |
ebcd3b23 MS |
198 | /* gdb_setup_readline will change gdb_stdout. If the CLI was |
199 | previously writing to gdb_stdout, then set it to the new | |
200 | gdb_stdout afterwards. */ | |
38caaeec | 201 | |
083aca0c | 202 | stream = m_cli_uiout->set_stream (gdb_stdout); |
38caaeec DJ |
203 | if (stream != gdb_stdout) |
204 | { | |
083aca0c | 205 | m_cli_uiout->set_stream (stream); |
38caaeec DJ |
206 | stream = NULL; |
207 | } | |
208 | ||
3c216924 PA |
209 | gdb_setup_readline (1); |
210 | ||
211 | ui->input_handler = command_line_handler; | |
38caaeec DJ |
212 | |
213 | if (stream != NULL) | |
083aca0c | 214 | m_cli_uiout->set_stream (gdb_stdout); |
4a8f6654 AC |
215 | } |
216 | ||
d6f9b0fb PA |
217 | void |
218 | cli_interp::suspend () | |
4a8f6654 AC |
219 | { |
220 | gdb_disable_readline (); | |
4a8f6654 AC |
221 | } |
222 | ||
b885aea1 | 223 | void |
d6f9b0fb | 224 | cli_interp::exec (const char *command_str) |
4a8f6654 | 225 | { |
083aca0c | 226 | /* gdb_stdout could change between the time m_cli_uiout was |
ebcd3b23 MS |
227 | initialized and now. Since we're probably using a different |
228 | interpreter which has a new ui_file for gdb_stdout, use that one | |
229 | instead of the default. | |
4a8f6654 | 230 | |
ebcd3b23 MS |
231 | It is important that it gets reset everytime, since the user |
232 | could set gdb to use a different interpreter. */ | |
b885aea1 PA |
233 | ui_file *old_stream = m_cli_uiout->set_stream (gdb_stdout); |
234 | SCOPE_EXIT { m_cli_uiout->set_stream (old_stream); }; | |
f9679975 PA |
235 | |
236 | /* Save and override the global ``struct ui_out'' builder. */ | |
753ff9bd | 237 | scoped_restore saved_uiout = make_scoped_restore (¤t_uiout, |
b885aea1 | 238 | m_cli_uiout.get ()); |
cdb27c12 | 239 | |
a70b8144 | 240 | try |
04bd08de | 241 | { |
b885aea1 | 242 | execute_command (command_str, 1); |
04bd08de | 243 | } |
b885aea1 | 244 | catch (const gdb_exception_error &ex) |
7556d4a4 | 245 | { |
b885aea1 PA |
246 | exception_print (gdb_stderr, ex); |
247 | throw; | |
7556d4a4 | 248 | } |
b885aea1 | 249 | } |
f9679975 | 250 | |
b885aea1 PA |
251 | bool |
252 | cli_interp_base::supports_command_editing () | |
253 | { | |
254 | return true; | |
4a8f6654 AC |
255 | } |
256 | ||
d6f9b0fb PA |
257 | ui_out * |
258 | cli_interp::interp_ui_out () | |
4801a9a3 | 259 | { |
083aca0c | 260 | return m_cli_uiout.get (); |
8322445e PA |
261 | } |
262 | ||
616268b6 PA |
263 | /* See cli-interp.h. */ |
264 | ||
265 | void | |
ca1285d1 AH |
266 | cli_interp_base::set_logging (ui_file_up logfile, bool logging_redirect, |
267 | bool debug_redirect) | |
616268b6 | 268 | { |
f3a09c80 | 269 | if (logfile != nullptr) |
616268b6 | 270 | { |
19622df1 TT |
271 | gdb_assert (m_saved_output == nullptr); |
272 | m_saved_output.reset (new saved_output_files); | |
273 | m_saved_output->out = gdb_stdout; | |
274 | m_saved_output->err = gdb_stderr; | |
275 | m_saved_output->log = gdb_stdlog; | |
276 | m_saved_output->targ = gdb_stdtarg; | |
277 | m_saved_output->targerr = gdb_stdtargerr; | |
f3a09c80 | 278 | |
2b141965 | 279 | ui_file *logfile_p = logfile.get (); |
35254615 | 280 | m_saved_output->logfile_holder = std::move (logfile); |
2b141965 | 281 | |
1dd88936 TT |
282 | /* The new stdout and stderr only depend on whether logging |
283 | redirection is being done. */ | |
284 | ui_file *new_stdout = logfile_p; | |
285 | ui_file *new_stderr = logfile_p; | |
286 | if (!logging_redirect) | |
ca1285d1 | 287 | { |
35254615 | 288 | m_saved_output->stdout_holder.reset |
2b141965 | 289 | (new tee_file (gdb_stdout, logfile_p)); |
35254615 TT |
290 | new_stdout = m_saved_output->stdout_holder.get (); |
291 | m_saved_output->stderr_holder.reset | |
1dd88936 | 292 | (new tee_file (gdb_stderr, logfile_p)); |
35254615 | 293 | new_stderr = m_saved_output->stderr_holder.get (); |
ca1285d1 | 294 | } |
59b59f08 | 295 | |
35254615 | 296 | m_saved_output->stdlog_holder.reset |
1dd88936 | 297 | (new timestamped_file (debug_redirect ? logfile_p : new_stderr)); |
52a4a588 | 298 | |
1dd88936 | 299 | gdb_stdout = new_stdout; |
35254615 | 300 | gdb_stdlog = m_saved_output->stdlog_holder.get (); |
1dd88936 TT |
301 | gdb_stderr = new_stderr; |
302 | gdb_stdtarg = new_stderr; | |
303 | gdb_stdtargerr = new_stderr; | |
616268b6 PA |
304 | } |
305 | else | |
306 | { | |
19622df1 TT |
307 | gdb_stdout = m_saved_output->out; |
308 | gdb_stderr = m_saved_output->err; | |
309 | gdb_stdlog = m_saved_output->log; | |
310 | gdb_stdtarg = m_saved_output->targ; | |
311 | gdb_stdtargerr = m_saved_output->targerr; | |
8b1931b3 | 312 | |
19622df1 | 313 | m_saved_output.reset (nullptr); |
616268b6 PA |
314 | } |
315 | } | |
316 | ||
8322445e PA |
317 | /* Factory for CLI interpreters. */ |
318 | ||
319 | static struct interp * | |
320 | cli_interp_factory (const char *name) | |
321 | { | |
d6f9b0fb | 322 | return new cli_interp (name); |
4801a9a3 | 323 | } |
4a8f6654 | 324 | |
4791eb66 | 325 | /* Standard gdb initialization hook. */ |
b9362cc7 | 326 | |
6c265988 | 327 | void _initialize_cli_interp (); |
4a8f6654 | 328 | void |
6c265988 | 329 | _initialize_cli_interp () |
4a8f6654 | 330 | { |
8322445e | 331 | interp_factory_register (INTERP_CONSOLE, cli_interp_factory); |
4a8f6654 | 332 | } |