1 /* TUI status line.
2
3 Copyright (C) 1998-2024 Free Software Foundation, Inc.
4
5 Contributed by Hewlett-Packard Company.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
21
22 #include "symtab.h"
23 #include "breakpoint.h"
24 #include "frame.h"
25 #include "command.h"
26 #include "inferior.h"
27 #include "target.h"
28 #include "top.h"
29 #include "gdb-demangle.h"
30 #include "source.h"
31 #include "tui/tui.h"
32 #include "tui/tui-data.h"
33 #include "tui/tui-status.h"
34 #include "tui/tui-wingeneral.h"
35 #include "tui/tui-source.h"
36 #include "tui/tui-winsource.h"
37 #include "tui/tui-file.h"
38 #include "tui/tui-location.h"
39
40 #include "gdb_curses.h"
41
42 static const std::string PROC_PREFIX = "In: ";
43 static const std::string LINE_PREFIX = "L";
44 static const std::string PC_PREFIX = "PC: ";
45
46 /* Strings to display in the TUI status line. */
47 static const std::string SINGLE_KEY = "(SingleKey)";
48
49 /* Minimum/Maximum length of some fields displayed in the TUI status
50 line. */
51 #define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line
52 numbers. */
53 #define MIN_PROC_WIDTH 12
54 #define MAX_TARGET_WIDTH 10
55 #define MAX_PID_WIDTH 19
56
57
58
59 std::string
make_status_line()60 tui_status_window::make_status_line () const
61 {
62 char line_buf[50];
63 int status_size;
64 int proc_width;
65 const char *pid_name;
66 int target_width;
67 int pid_width;
68 int line_width;
69
70 std::string pid_name_holder;
71 if (inferior_ptid == null_ptid)
72 pid_name = "No process";
73 else
74 {
75 pid_name_holder = target_pid_to_str (inferior_ptid);
76 pid_name = pid_name_holder.c_str ();
77 }
78
79 target_width = strlen (target_shortname ());
80 if (target_width > MAX_TARGET_WIDTH)
81 target_width = MAX_TARGET_WIDTH;
82
83 pid_width = strlen (pid_name);
84 if (pid_width > MAX_PID_WIDTH)
85 pid_width = MAX_PID_WIDTH;
86
87 status_size = width;
88
89 /* Translate line number and obtain its size. */
90 int line_no = tui_location.line_no ();
91 if (line_no > 0)
92 xsnprintf (line_buf, sizeof (line_buf), "%d", line_no);
93 else
94 strcpy (line_buf, "??");
95 line_width = strlen (line_buf);
96 if (line_width < MIN_LINE_WIDTH)
97 line_width = MIN_LINE_WIDTH;
98
99 /* Translate PC address. */
100 struct gdbarch *gdbarch = tui_location.gdbarch ();
101 CORE_ADDR addr = tui_location.addr ();
102 std::string pc_out (gdbarch
103 ? paddress (gdbarch, addr)
104 : "??");
105 const char *pc_buf = pc_out.c_str ();
106 int pc_width = pc_out.size ();
107
108 /* Width of the field showing the window with current focus. For a window
109 named "src" we show "(src)". */
110 int focus_width = (tui_win_with_focus () != nullptr
111 ? 1 + strlen (tui_win_with_focus ()->name ()) + 1
112 : 0);
113
114 /* First determine the amount of proc name width we have available.
115 The +1 are for a space separator between fields. */
116 proc_width = (status_size
117 - (target_width + 1)
118 - (pid_width + 1)
119 - (PROC_PREFIX.size () + 1)
120 - (LINE_PREFIX.size () + line_width + 1)
121 - (PC_PREFIX.size () + pc_width + 1)
122 - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
123 ? (SINGLE_KEY.size () + 1)
124 : 0)
125 - (focus_width > 0
126 ? focus_width + 1
127 : 0));
128
129 /* If there is no room to print the function name, try by removing
130 some fields. */
131 if (proc_width < MIN_PROC_WIDTH)
132 {
133 proc_width += target_width + 1;
134 target_width = 0;
135 if (proc_width < MIN_PROC_WIDTH)
136 {
137 proc_width += pid_width + 1;
138 pid_width = 0;
139 if (proc_width <= MIN_PROC_WIDTH)
140 {
141 proc_width += pc_width + PC_PREFIX.size () + 1;
142 pc_width = 0;
143 if (proc_width < 0)
144 {
145 proc_width += line_width + LINE_PREFIX.size () + 1;
146 line_width = 0;
147 if (proc_width < 0)
148 proc_width = 0;
149 }
150 }
151 }
152 }
153
154 /* Now create the status line from the string version of the
155 elements. */
156 string_file string;
157
158 if (target_width > 0)
159 string.printf ("%*.*s ", -target_width, target_width, target_shortname ());
160 if (pid_width > 0)
161 string.printf ("%*.*s ", -pid_width, pid_width, pid_name);
162
163 /* Show whether we are in SingleKey mode. */
164 if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
165 {
166 string.puts (SINGLE_KEY.c_str ());
167 string.puts (" ");
168 }
169
170 if (tui_win_with_focus () != nullptr)
171 {
172 string.puts ("(");
173 string.puts (tui_win_with_focus ()->name ());
174 string.puts (") ");
175 }
176
177 /* Procedure/class name. */
178 if (proc_width > 0)
179 {
180 const std::string &proc_name = tui_location.proc_name ();
181 if (proc_name.size () > proc_width)
182 string.printf ("%s%*.*s* ", PROC_PREFIX.c_str (),
183 1 - proc_width, proc_width - 1, proc_name.c_str ());
184 else
185 string.printf ("%s%*.*s ", PROC_PREFIX.c_str (),
186 -proc_width, proc_width, proc_name.c_str ());
187 }
188
189 if (line_width > 0)
190 string.printf ("%s%*.*s ", LINE_PREFIX.c_str (),
191 -line_width, line_width, line_buf);
192 if (pc_width > 0)
193 {
194 string.puts (PC_PREFIX.c_str ());
195 string.puts (pc_buf);
196 }
197
198 std::string string_val = string.release ();
199
200 size_t len = string_val.size ();
201 if (len < status_size)
202 string_val.append (status_size - len, ' ');
203 else if (len > status_size)
204 string_val.erase (status_size, len);
205
206 gdb_assert (string_val.size () == status_size);
207
208 return string_val;
209 }
210
211 /* Get a printable name for the function at the address. The symbol
212 name is demangled if demangling is turned on. Returns a pointer to
213 a static area holding the result. */
214 static char*
tui_get_function_from_frame(const frame_info_ptr & fi)215 tui_get_function_from_frame (const frame_info_ptr &fi)
216 {
217 static char name[256];
218 string_file stream;
219
220 print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi),
221 &stream, demangle, "");
222
223 /* Use simple heuristics to isolate the function name. The symbol
224 can be demangled and we can have function parameters. Remove
225 them because the status line is too short to display them. */
226 const char *d = stream.c_str ();
227 if (*d == '<')
228 d++;
229 strncpy (name, d, sizeof (name) - 1);
230 name[sizeof (name) - 1] = 0;
231
232 char *p = strchr (name, '(');
233 if (!p)
234 p = strchr (name, '>');
235 if (p)
236 *p = 0;
237 p = strchr (name, '+');
238 if (p)
239 *p = 0;
240 return name;
241 }
242
243 void
rerender()244 tui_status_window::rerender ()
245 {
246 gdb_assert (handle != NULL);
247
248 std::string string = make_status_line ();
249 scrollok (handle.get (), FALSE);
250 wmove (handle.get (), 0, 0);
251 /* We ignore the return value from wstandout and wstandend, casting them
252 to void in order to avoid a compiler warning. The warning itself was
253 introduced by a patch to ncurses 5.7 dated 2009-08-29, changing these
254 macro to expand to code that causes the compiler to generate an
255 unused-value warning. */
256 (void) wstandout (handle.get ());
257 waddstr (handle.get (), string.c_str ());
258 wclrtoeol (handle.get ());
259 (void) wstandend (handle.get ());
260 refresh_window ();
261 wmove (handle.get (), 0, 0);
262 }
263
264 /* Function to print the frame information for the TUI. The windows
265 are refreshed only if frame information has changed since the last
266 refresh. */
267
268 void
tui_show_frame_info(const frame_info_ptr & fi)269 tui_show_frame_info (const frame_info_ptr &fi)
270 {
271 bool status_changed_p;
272
273 if (fi != nullptr)
274 {
275 symtab_and_line sal = find_frame_sal (fi);
276
277 const char *func_name;
278 /* find_frame_sal does not always set PC, but we want to ensure
279 that it is available in the SAL. */
280 if (get_frame_pc_if_available (fi, &sal.pc))
281 func_name = tui_get_function_from_frame (fi);
282 else
283 func_name = _("<unavailable>");
284
285 status_changed_p
286 = tui_location.set_location (get_frame_arch (fi), sal, func_name);
287
288 /* If the status information has not changed, then frame information has
289 not changed. If frame information has not changed, then the windows'
290 contents will not change. So don't bother refreshing the windows. */
291 if (!status_changed_p)
292 return;
293
294 for (struct tui_source_window_base *win_info : tui_source_windows ())
295 {
296 win_info->maybe_update (fi, sal);
297 win_info->update_exec_info ();
298 }
299 }
300 else
301 {
302 symtab_and_line sal {};
303
304 status_changed_p = tui_location.set_location (NULL, sal, "");
305
306 if (!status_changed_p)
307 return;
308
309 for (struct tui_source_window_base *win_info : tui_source_windows ())
310 win_info->erase_source_content ();
311 }
312 }
313
314 void
tui_show_status_content()315 tui_show_status_content ()
316 {
317 if (tui_is_window_visible (STATUS_WIN))
318 TUI_STATUS_WIN->rerender ();
319 }
320
321 /* Command to update the display with the current execution point. */
322 static void
tui_update_command(const char * arg,int from_tty)323 tui_update_command (const char *arg, int from_tty)
324 {
325 execute_command ("frame 0", from_tty);
326 }
327
328 /* Function to initialize gdb commands, for tui window stack
329 manipulation. */
330
331 void _initialize_tui_stack ();
332 void
_initialize_tui_stack()333 _initialize_tui_stack ()
334 {
335 add_com ("update", class_tui, tui_update_command,
336 _("\
337 Update the source window to display the current execution point.\n\
338 Usage: update"));
339 }
340