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