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