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