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