xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/tui/tui-stack.c (revision 8b657b0747480f8989760d71343d6dd33f8d4cf9)
1 /* TUI display locator.
2 
3    Copyright (C) 1998-2023 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 #include "tui/tui-location.h"
40 
41 #include "gdb_curses.h"
42 
43 #define PROC_PREFIX             "In: "
44 #define LINE_PREFIX             "L"
45 #define PC_PREFIX               "PC: "
46 
47 /* Strings to display in the TUI status line.  */
48 #define 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 
59 
60 std::string
61 tui_locator_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   /* First determine the amount of proc name width we have available.
110      The +1 are for a space separator between fields.
111      The -1 are to take into account the \0 counted by sizeof.  */
112   proc_width = (status_size
113 		- (target_width + 1)
114 		- (pid_width + 1)
115 		- (sizeof (PROC_PREFIX) - 1 + 1)
116 		- (sizeof (LINE_PREFIX) - 1 + line_width + 1)
117 		- (sizeof (PC_PREFIX) - 1 + pc_width + 1)
118 		- (tui_current_key_mode == TUI_SINGLE_KEY_MODE
119 		   ? (sizeof (SINGLE_KEY) - 1 + 1)
120 		   : 0));
121 
122   /* If there is no room to print the function name, try by removing
123      some fields.  */
124   if (proc_width < MIN_PROC_WIDTH)
125     {
126       proc_width += target_width + 1;
127       target_width = 0;
128       if (proc_width < MIN_PROC_WIDTH)
129 	{
130 	  proc_width += pid_width + 1;
131 	  pid_width = 0;
132 	  if (proc_width <= MIN_PROC_WIDTH)
133 	    {
134 	      proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
135 	      pc_width = 0;
136 	      if (proc_width < 0)
137 		{
138 		  proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
139 		  line_width = 0;
140 		  if (proc_width < 0)
141 		    proc_width = 0;
142 		}
143 	    }
144 	}
145     }
146 
147   /* Now create the locator line from the string version of the
148      elements.  */
149   string_file string;
150 
151   if (target_width > 0)
152     string.printf ("%*.*s ", -target_width, target_width, target_shortname ());
153   if (pid_width > 0)
154     string.printf ("%*.*s ", -pid_width, pid_width, pid_name);
155 
156   /* Show whether we are in SingleKey mode.  */
157   if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
158     {
159       string.puts (SINGLE_KEY);
160       string.puts (" ");
161     }
162 
163   /* Procedure/class name.  */
164   if (proc_width > 0)
165     {
166       const std::string &proc_name = tui_location.proc_name ();
167       if (proc_name.size () > proc_width)
168 	string.printf ("%s%*.*s* ", PROC_PREFIX,
169 		       1 - proc_width, proc_width - 1, proc_name.c_str ());
170       else
171 	string.printf ("%s%*.*s ", PROC_PREFIX,
172 		       -proc_width, proc_width, proc_name.c_str ());
173     }
174 
175   if (line_width > 0)
176     string.printf ("%s%*.*s ", LINE_PREFIX,
177 		   -line_width, line_width, line_buf);
178   if (pc_width > 0)
179     {
180       string.puts (PC_PREFIX);
181       string.puts (pc_buf);
182     }
183 
184   std::string string_val = string.release ();
185 
186   if (string.size () < status_size)
187     string_val.append (status_size - string.size (), ' ');
188   else if (string.size () > status_size)
189     string_val.erase (status_size, string.size ());
190 
191   return string_val;
192 }
193 
194 /* Get a printable name for the function at the address.  The symbol
195    name is demangled if demangling is turned on.  Returns a pointer to
196    a static area holding the result.  */
197 static char*
198 tui_get_function_from_frame (frame_info_ptr fi)
199 {
200   static char name[256];
201   string_file stream;
202 
203   print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi),
204 			  &stream, demangle, "");
205 
206   /* Use simple heuristics to isolate the function name.  The symbol
207      can be demangled and we can have function parameters.  Remove
208      them because the status line is too short to display them.  */
209   const char *d = stream.c_str ();
210   if (*d == '<')
211     d++;
212   strncpy (name, d, sizeof (name) - 1);
213   name[sizeof (name) - 1] = 0;
214 
215   char *p = strchr (name, '(');
216   if (!p)
217     p = strchr (name, '>');
218   if (p)
219     *p = 0;
220   p = strchr (name, '+');
221   if (p)
222     *p = 0;
223   return name;
224 }
225 
226 void
227 tui_locator_window::rerender ()
228 {
229   gdb_assert (handle != NULL);
230 
231   std::string string = make_status_line ();
232   scrollok (handle.get (), FALSE);
233   wmove (handle.get (), 0, 0);
234   /* We ignore the return value from wstandout and wstandend, casting them
235      to void in order to avoid a compiler warning.  The warning itself was
236      introduced by a patch to ncurses 5.7 dated 2009-08-29, changing these
237      macro to expand to code that causes the compiler to generate an
238      unused-value warning.  */
239   (void) wstandout (handle.get ());
240   waddstr (handle.get (), string.c_str ());
241   wclrtoeol (handle.get ());
242   (void) wstandend (handle.get ());
243   refresh_window ();
244   wmove (handle.get (), 0, 0);
245 }
246 
247 /* Function to print the frame information for the TUI.  The windows are
248    refreshed only if frame information has changed since the last refresh.
249 
250    Return true if frame information has changed (and windows
251    subsequently refreshed), false otherwise.  */
252 
253 bool
254 tui_show_frame_info (frame_info_ptr fi)
255 {
256   bool locator_changed_p;
257 
258   if (fi != nullptr)
259     {
260       symtab_and_line sal = find_frame_sal (fi);
261 
262       const char *func_name;
263       /* find_frame_sal does not always set PC, but we want to ensure
264 	 that it is available in the SAL.  */
265       if (get_frame_pc_if_available (fi, &sal.pc))
266 	func_name = tui_get_function_from_frame (fi);
267       else
268 	func_name = _("<unavailable>");
269 
270       locator_changed_p
271 	= tui_location.set_location (get_frame_arch (fi), sal, func_name);
272 
273       /* If the locator information has not changed, then frame information has
274 	 not changed.  If frame information has not changed, then the windows'
275 	 contents will not change.  So don't bother refreshing the windows.  */
276       if (!locator_changed_p)
277 	return false;
278 
279       for (struct tui_source_window_base *win_info : tui_source_windows ())
280 	{
281 	  win_info->maybe_update (fi, sal);
282 	  win_info->update_exec_info ();
283 	}
284     }
285   else
286     {
287       symtab_and_line sal {};
288 
289       locator_changed_p = tui_location.set_location (NULL, sal, "");
290 
291       if (!locator_changed_p)
292 	return false;
293 
294       for (struct tui_source_window_base *win_info : tui_source_windows ())
295 	win_info->erase_source_content ();
296     }
297 
298   return true;
299 }
300 
301 void
302 tui_show_locator_content ()
303 {
304   if (tui_is_window_visible (STATUS_WIN))
305     TUI_STATUS_WIN->rerender ();
306 }
307 
308 /* Command to update the display with the current execution point.  */
309 static void
310 tui_update_command (const char *arg, int from_tty)
311 {
312   execute_command ("frame 0", from_tty);
313 }
314 
315 /* Function to initialize gdb commands, for tui window stack
316    manipulation.  */
317 
318 void _initialize_tui_stack ();
319 void
320 _initialize_tui_stack ()
321 {
322   add_com ("update", class_tui, tui_update_command,
323 	   _("Update the source window and locator to "
324 	     "display the current execution point.\n\
325 Usage: update"));
326 }
327