Move some defines to tui-stack.c
[binutils-gdb.git] / gdb / tui / tui-stack.c
1 /* TUI display locator.
2
3 Copyright (C) 1998-2019 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-stack.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
40 #include "gdb_curses.h"
41
42 #define PROC_PREFIX "In: "
43 #define LINE_PREFIX "L"
44 #define PC_PREFIX "PC: "
45
46 /* Minimum/Maximum length of some fields displayed in the TUI status
47 line. */
48 #define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line
49 numbers. */
50 #define MIN_PROC_WIDTH 12
51 #define MAX_TARGET_WIDTH 10
52 #define MAX_PID_WIDTH 19
53
54 static struct tui_locator_window _locator;
55
56 /* Get a printable name for the function at the address.
57 The symbol name is demangled if demangling is turned on.
58 Returns a pointer to a static area holding the result. */
59 static char *tui_get_function_from_frame (struct frame_info *fi);
60
61 /* Set the full_name portion of the locator. */
62 static void tui_set_locator_fullname (const char *fullname);
63
64 /* Update the locator, with the provided arguments. */
65 static int tui_set_locator_info (struct gdbarch *gdbarch,
66 const char *fullname,
67 const char *procname,
68 int lineno, CORE_ADDR addr);
69
70 static void tui_update_command (const char *, int);
71 \f
72
73 /* Accessor for the locator win info. Answers a pointer to the static
74 locator win info struct. */
75 struct tui_locator_window *
76 tui_locator_win_info_ptr (void)
77 {
78 return &_locator;
79 }
80
81 /* Create the status line to display as much information as we can on
82 this single line: target name, process number, current function,
83 current line, current PC, SingleKey mode. */
84 static char *
85 tui_make_status_line (struct tui_locator_window *loc)
86 {
87 char *string;
88 char line_buf[50], *pname;
89 char *buf;
90 int status_size;
91 int i, proc_width;
92 const char *pid_name;
93 int target_width;
94 int pid_width;
95 int line_width;
96
97 std::string pid_name_holder;
98 if (inferior_ptid == null_ptid)
99 pid_name = "No process";
100 else
101 {
102 pid_name_holder = target_pid_to_str (inferior_ptid);
103 pid_name = pid_name_holder.c_str ();
104 }
105
106 target_width = strlen (target_shortname);
107 if (target_width > MAX_TARGET_WIDTH)
108 target_width = MAX_TARGET_WIDTH;
109
110 pid_width = strlen (pid_name);
111 if (pid_width > MAX_PID_WIDTH)
112 pid_width = MAX_PID_WIDTH;
113
114 status_size = tui_term_width ();
115 string = (char *) xmalloc (status_size + 1);
116 buf = (char*) alloca (status_size + 1);
117
118 /* Translate line number and obtain its size. */
119 if (loc->line_no > 0)
120 xsnprintf (line_buf, sizeof (line_buf), "%d", loc->line_no);
121 else
122 strcpy (line_buf, "??");
123 line_width = strlen (line_buf);
124 if (line_width < MIN_LINE_WIDTH)
125 line_width = MIN_LINE_WIDTH;
126
127 /* Translate PC address. */
128 std::string pc_out (loc->gdbarch
129 ? paddress (loc->gdbarch, loc->addr)
130 : "??");
131 const char *pc_buf = pc_out.c_str ();
132 int pc_width = pc_out.size ();
133
134 /* First determine the amount of proc name width we have available.
135 The +1 are for a space separator between fields.
136 The -1 are to take into account the \0 counted by sizeof. */
137 proc_width = (status_size
138 - (target_width + 1)
139 - (pid_width + 1)
140 - (sizeof (PROC_PREFIX) - 1 + 1)
141 - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
142 - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
143 - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
144 ? (sizeof (SINGLE_KEY) - 1 + 1)
145 : 0));
146
147 /* If there is no room to print the function name, try by removing
148 some fields. */
149 if (proc_width < MIN_PROC_WIDTH)
150 {
151 proc_width += target_width + 1;
152 target_width = 0;
153 if (proc_width < MIN_PROC_WIDTH)
154 {
155 proc_width += pid_width + 1;
156 pid_width = 0;
157 if (proc_width <= MIN_PROC_WIDTH)
158 {
159 proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
160 pc_width = 0;
161 if (proc_width < 0)
162 {
163 proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
164 line_width = 0;
165 if (proc_width < 0)
166 proc_width = 0;
167 }
168 }
169 }
170 }
171
172 /* Now convert elements to string form. */
173 pname = loc->proc_name;
174
175 /* Now create the locator line from the string version of the
176 elements. We could use sprintf() here but that wouldn't ensure
177 that we don't overrun the size of the allocated buffer.
178 strcat_to_buf() will. */
179 *string = (char) 0;
180
181 if (target_width > 0)
182 {
183 sprintf (buf, "%*.*s ",
184 -target_width, target_width, target_shortname);
185 strcat_to_buf (string, status_size, buf);
186 }
187 if (pid_width > 0)
188 {
189 sprintf (buf, "%*.*s ",
190 -pid_width, pid_width, pid_name);
191 strcat_to_buf (string, status_size, buf);
192 }
193
194 /* Show whether we are in SingleKey mode. */
195 if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
196 {
197 strcat_to_buf (string, status_size, SINGLE_KEY);
198 strcat_to_buf (string, status_size, " ");
199 }
200
201 /* Procedure/class name. */
202 if (proc_width > 0)
203 {
204 if (strlen (pname) > proc_width)
205 sprintf (buf, "%s%*.*s* ", PROC_PREFIX,
206 1 - proc_width, proc_width - 1, pname);
207 else
208 sprintf (buf, "%s%*.*s ", PROC_PREFIX,
209 -proc_width, proc_width, pname);
210 strcat_to_buf (string, status_size, buf);
211 }
212
213 if (line_width > 0)
214 {
215 sprintf (buf, "%s%*.*s ", LINE_PREFIX,
216 -line_width, line_width, line_buf);
217 strcat_to_buf (string, status_size, buf);
218 }
219 if (pc_width > 0)
220 {
221 strcat_to_buf (string, status_size, PC_PREFIX);
222 strcat_to_buf (string, status_size, pc_buf);
223 }
224
225
226 for (i = strlen (string); i < status_size; i++)
227 string[i] = ' ';
228 string[status_size] = (char) 0;
229
230 return string;
231 }
232
233 /* Get a printable name for the function at the address. The symbol
234 name is demangled if demangling is turned on. Returns a pointer to
235 a static area holding the result. */
236 static char*
237 tui_get_function_from_frame (struct frame_info *fi)
238 {
239 static char name[256];
240 string_file stream;
241
242 print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi),
243 &stream, demangle, "");
244
245 /* Use simple heuristics to isolate the function name. The symbol
246 can be demangled and we can have function parameters. Remove
247 them because the status line is too short to display them. */
248 const char *d = stream.c_str ();
249 if (*d == '<')
250 d++;
251 strncpy (name, d, sizeof (name) - 1);
252 name[sizeof (name) - 1] = 0;
253
254 char *p = strchr (name, '(');
255 if (!p)
256 p = strchr (name, '>');
257 if (p)
258 *p = 0;
259 p = strchr (name, '+');
260 if (p)
261 *p = 0;
262 return name;
263 }
264
265 void
266 tui_show_locator_content (void)
267 {
268 char *string;
269 struct tui_locator_window *locator;
270
271 locator = tui_locator_win_info_ptr ();
272
273 if (locator != NULL && locator->handle != NULL)
274 {
275 string = tui_make_status_line (locator);
276 wmove (locator->handle, 0, 0);
277 /* We ignore the return value from wstandout and wstandend, casting
278 them to void in order to avoid a compiler warning. The warning
279 itself was introduced by a patch to ncurses 5.7 dated 2009-08-29,
280 changing these macro to expand to code that causes the compiler
281 to generate an unused-value warning. */
282 (void) wstandout (locator->handle);
283 waddstr (locator->handle, string);
284 wclrtoeol (locator->handle);
285 (void) wstandend (locator->handle);
286 locator->refresh_window ();
287 wmove (locator->handle, 0, 0);
288 xfree (string);
289 }
290 }
291
292 void
293 tui_locator_window::rerender ()
294 {
295 tui_show_locator_content ();
296 }
297
298 /* Set the filename portion of the locator. */
299 static void
300 tui_set_locator_fullname (const char *fullname)
301 {
302 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
303
304 locator->full_name[0] = 0;
305 strcat_to_buf (locator->full_name, MAX_LOCATOR_ELEMENT_LEN, fullname);
306 }
307
308 /* Update the locator, with the provided arguments.
309
310 Returns 1 if any of the locator's fields were actually changed,
311 and 0 otherwise. */
312
313 static int
314 tui_set_locator_info (struct gdbarch *gdbarch,
315 const char *fullname,
316 const char *procname,
317 int lineno,
318 CORE_ADDR addr)
319 {
320 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
321 int locator_changed_p = 0;
322
323 if (procname == NULL)
324 procname = "";
325
326 if (fullname == NULL)
327 fullname = "";
328
329 locator_changed_p |= strncmp (locator->proc_name, procname,
330 MAX_LOCATOR_ELEMENT_LEN) != 0;
331 locator_changed_p |= lineno != locator->line_no;
332 locator_changed_p |= addr != locator->addr;
333 locator_changed_p |= gdbarch != locator->gdbarch;
334 locator_changed_p |= strncmp (locator->full_name, fullname,
335 MAX_LOCATOR_ELEMENT_LEN) != 0;
336
337 locator->proc_name[0] = (char) 0;
338 strcat_to_buf (locator->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
339 locator->line_no = lineno;
340 locator->addr = addr;
341 locator->gdbarch = gdbarch;
342 tui_set_locator_fullname (fullname);
343
344 return locator_changed_p;
345 }
346
347 /* Update only the full_name portion of the locator. */
348 void
349 tui_update_locator_fullname (const char *fullname)
350 {
351 tui_set_locator_fullname (fullname);
352 tui_show_locator_content ();
353 }
354
355 /* Function to print the frame information for the TUI. The windows are
356 refreshed only if frame information has changed since the last refresh.
357
358 Return 1 if frame information has changed (and windows subsequently
359 refreshed), 0 otherwise. */
360
361 int
362 tui_show_frame_info (struct frame_info *fi)
363 {
364 int locator_changed_p;
365
366 if (fi)
367 {
368 struct tui_locator_window *locator = tui_locator_win_info_ptr ();
369 CORE_ADDR pc;
370
371 symtab_and_line sal = find_frame_sal (fi);
372
373 const char *fullname = nullptr;
374 if (sal.symtab != nullptr)
375 fullname = symtab_to_fullname (sal.symtab);
376
377 if (get_frame_pc_if_available (fi, &pc))
378 locator_changed_p
379 = tui_set_locator_info (get_frame_arch (fi),
380 (sal.symtab == 0
381 ? "??" : fullname),
382 tui_get_function_from_frame (fi),
383 sal.line,
384 pc);
385 else
386 locator_changed_p
387 = tui_set_locator_info (get_frame_arch (fi),
388 "??", _("<unavailable>"), sal.line, 0);
389
390 /* If the locator information has not changed, then frame information has
391 not changed. If frame information has not changed, then the windows'
392 contents will not change. So don't bother refreshing the windows. */
393 if (!locator_changed_p)
394 return 0;
395
396 tui_show_locator_content ();
397 for (struct tui_source_window_base *win_info : tui_source_windows ())
398 {
399 win_info->maybe_update (fi, sal, locator->line_no, locator->addr);
400 win_info->update_exec_info ();
401 }
402
403 return 1;
404 }
405 else
406 {
407 locator_changed_p
408 = tui_set_locator_info (NULL, NULL, NULL, 0, (CORE_ADDR) 0);
409
410 if (!locator_changed_p)
411 return 0;
412
413 tui_show_locator_content ();
414 for (struct tui_source_window_base *win_info : tui_source_windows ())
415 {
416 win_info->erase_source_content ();
417 win_info->update_exec_info ();
418 }
419
420 return 1;
421 }
422 }
423
424 /* Function to initialize gdb commands, for tui window stack
425 manipulation. */
426
427 void
428 _initialize_tui_stack (void)
429 {
430 add_com ("update", class_tui, tui_update_command,
431 _("Update the source window and locator to "
432 "display the current execution point."));
433 }
434
435 /* Command to update the display with the current execution point. */
436 static void
437 tui_update_command (const char *arg, int from_tty)
438 {
439 execute_command ("frame 0", from_tty);
440 }