xref: /openbsd/gnu/usr.bin/binutils/gdb/tui/tui-stack.c (revision a19b5bdc)
1 /* TUI display locator.
2 
3    Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4    Foundation, Inc.
5 
6    Contributed by Hewlett-Packard Company.
7 
8    This file is part of GDB.
9 
10    This program is free software; you can redistribute it and/or modify
11    it under the terms of the GNU General Public License as published by
12    the Free Software Foundation; either version 2 of the License, or
13    (at your option) any later version.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 59 Temple Place - Suite 330,
23    Boston, MA 02111-1307, USA.  */
24 
25 #include "defs.h"
26 #include "symtab.h"
27 #include "breakpoint.h"
28 #include "frame.h"
29 #include "command.h"
30 #include "inferior.h"
31 #include "target.h"
32 #include "top.h"
33 #include "gdb_string.h"
34 #include "tui/tui.h"
35 #include "tui/tui-data.h"
36 #include "tui/tui-stack.h"
37 #include "tui/tui-wingeneral.h"
38 #include "tui/tui-source.h"
39 #include "tui/tui-winsource.h"
40 #include "tui/tui-file.h"
41 
42 #include "gdb_curses.h"
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 filename portion of the locator.  */
50 static void tui_set_locator_filename (const char *filename);
51 
52 /* Update the locator, with the provided arguments.  */
53 static void tui_set_locator_info (const char *filename, const char *procname,
54                                   int lineno, CORE_ADDR addr);
55 
56 static void tui_update_command (char *, int);
57 
58 
59 /* Create the status line to display as much information as we
60    can on this single line: target name, process number, current
61    function, current line, current PC, SingleKey mode.  */
62 static char*
tui_make_status_line(struct tui_locator_element * loc)63 tui_make_status_line (struct tui_locator_element* loc)
64 {
65   char* string;
66   char line_buf[50], *pname;
67   char* buf;
68   int status_size;
69   int i, proc_width;
70   const char* pid_name;
71   const char* pc_buf;
72   int target_width;
73   int pid_width;
74   int line_width;
75   int pc_width;
76   struct ui_file *pc_out;
77 
78   if (ptid_equal (inferior_ptid, null_ptid))
79     pid_name = "No process";
80   else
81     pid_name = target_pid_to_str (inferior_ptid);
82 
83   target_width = strlen (target_shortname);
84   if (target_width > MAX_TARGET_WIDTH)
85     target_width = MAX_TARGET_WIDTH;
86 
87   pid_width = strlen (pid_name);
88   if (pid_width > MAX_PID_WIDTH)
89     pid_width = MAX_PID_WIDTH;
90 
91   status_size = tui_term_width ();
92   string = (char *) xmalloc (status_size + 1);
93   buf = (char*) alloca (status_size + 1);
94 
95   /* Translate line number and obtain its size.  */
96   if (loc->line_no > 0)
97     sprintf (line_buf, "%d", loc->line_no);
98   else
99     strcpy (line_buf, "??");
100   line_width = strlen (line_buf);
101   if (line_width < MIN_LINE_WIDTH)
102     line_width = MIN_LINE_WIDTH;
103 
104   /* Translate PC address.  */
105   pc_out = tui_sfileopen (128);
106   print_address_numeric (loc->addr, 1, pc_out);
107   pc_buf = tui_file_get_strbuf (pc_out);
108   pc_width = strlen (pc_buf);
109 
110   /* First determine the amount of proc name width we have available.
111      The +1 are for a space separator between fields.
112      The -1 are to take into account the \0 counted by sizeof.  */
113   proc_width = (status_size
114                 - (target_width + 1)
115                 - (pid_width + 1)
116                 - (sizeof (PROC_PREFIX) - 1 + 1)
117                 - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
118                 - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
119                 - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
120                    ? (sizeof (SINGLE_KEY) - 1 + 1)
121                    : 0));
122 
123   /* If there is no room to print the function name, try by removing
124      some fields.  */
125   if (proc_width < MIN_PROC_WIDTH)
126     {
127       proc_width += target_width + 1;
128       target_width = 0;
129       if (proc_width < MIN_PROC_WIDTH)
130         {
131           proc_width += pid_width + 1;
132           pid_width = 0;
133           if (proc_width <= MIN_PROC_WIDTH)
134             {
135               proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
136               pc_width = 0;
137               if (proc_width < 0)
138                 {
139                   proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
140                   line_width = 0;
141                   if (proc_width < 0)
142                     proc_width = 0;
143                 }
144             }
145         }
146     }
147 
148   /* Now convert elements to string form */
149   pname = loc->proc_name;
150 
151   /* Now create the locator line from the string version
152      of the elements.  We could use sprintf() here but
153      that wouldn't ensure that we don't overrun the size
154      of the allocated buffer.  strcat_to_buf() will.  */
155   *string = (char) 0;
156 
157   if (target_width > 0)
158     {
159       sprintf (buf, "%*.*s ",
160                -target_width, target_width, target_shortname);
161       strcat_to_buf (string, status_size, buf);
162     }
163   if (pid_width > 0)
164     {
165       sprintf (buf, "%*.*s ",
166                -pid_width, pid_width, pid_name);
167       strcat_to_buf (string, status_size, buf);
168     }
169 
170   /* Show whether we are in SingleKey mode.  */
171   if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
172     {
173       strcat_to_buf (string, status_size, SINGLE_KEY);
174       strcat_to_buf (string, status_size, " ");
175     }
176 
177   /* procedure/class name */
178   if (proc_width > 0)
179     {
180       if (strlen (pname) > proc_width)
181         sprintf (buf, "%s%*.*s* ", PROC_PREFIX,
182                  1 - proc_width, proc_width - 1, pname);
183       else
184         sprintf (buf, "%s%*.*s ", PROC_PREFIX,
185                  -proc_width, proc_width, pname);
186       strcat_to_buf (string, status_size, buf);
187     }
188 
189   if (line_width > 0)
190     {
191       sprintf (buf, "%s%*.*s ", LINE_PREFIX,
192                -line_width, line_width, line_buf);
193       strcat_to_buf (string, status_size, buf);
194     }
195   if (pc_width > 0)
196     {
197       strcat_to_buf (string, status_size, PC_PREFIX);
198       strcat_to_buf (string, status_size, pc_buf);
199     }
200 
201 
202   for (i = strlen (string); i < status_size; i++)
203     string[i] = ' ';
204   string[status_size] = (char) 0;
205 
206   ui_file_delete (pc_out);
207   return string;
208 }
209 
210 /* Get a printable name for the function at the address.
211    The symbol name is demangled if demangling is turned on.
212    Returns a pointer to a static area holding the result.  */
213 static char*
tui_get_function_from_frame(struct frame_info * fi)214 tui_get_function_from_frame (struct frame_info *fi)
215 {
216   static char name[256];
217   struct ui_file *stream = tui_sfileopen (256);
218   char *p;
219 
220   print_address_symbolic (get_frame_pc (fi), stream, demangle, "");
221   p = tui_file_get_strbuf (stream);
222 
223   /* Use simple heuristics to isolate the function name.  The symbol can
224      be demangled and we can have function parameters.  Remove them because
225      the status line is too short to display them.  */
226   if (*p == '<')
227     p++;
228   strncpy (name, p, sizeof (name));
229   p = strchr (name, '(');
230   if (!p)
231     p = strchr (name, '>');
232   if (p)
233     *p = 0;
234   p = strchr (name, '+');
235   if (p)
236     *p = 0;
237   ui_file_delete (stream);
238   return name;
239 }
240 
241 void
tui_show_locator_content(void)242 tui_show_locator_content (void)
243 {
244   char *string;
245   struct tui_gen_win_info * locator;
246 
247   locator = tui_locator_win_info_ptr ();
248 
249   if (locator != NULL && locator->handle != (WINDOW *) NULL)
250     {
251       struct tui_win_element * element;
252 
253       element = (struct tui_win_element *) locator->content[0];
254 
255       string = tui_make_status_line (&element->which_element.locator);
256       wmove (locator->handle, 0, 0);
257       wstandout (locator->handle);
258       waddstr (locator->handle, string);
259       wclrtoeol (locator->handle);
260       wstandend (locator->handle);
261       tui_refresh_win (locator);
262       wmove (locator->handle, 0, 0);
263       xfree (string);
264       locator->content_in_use = TRUE;
265     }
266 }
267 
268 
269 /* Set the filename portion of the locator.  */
270 static void
tui_set_locator_filename(const char * filename)271 tui_set_locator_filename (const char *filename)
272 {
273   struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
274   struct tui_locator_element * element;
275 
276   if (locator->content[0] == NULL)
277     {
278       tui_set_locator_info (filename, NULL, 0, 0);
279       return;
280     }
281 
282   element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
283   element->file_name[0] = 0;
284   strcat_to_buf (element->file_name, MAX_LOCATOR_ELEMENT_LEN, filename);
285 }
286 
287 /* Update the locator, with the provided arguments.  */
288 static void
tui_set_locator_info(const char * filename,const char * procname,int lineno,CORE_ADDR addr)289 tui_set_locator_info (const char *filename, const char *procname, int lineno,
290                       CORE_ADDR addr)
291 {
292   struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
293   struct tui_locator_element * element;
294 
295   /* Allocate the locator content if necessary.  */
296   if (locator->content_size <= 0)
297     {
298       locator->content = (void **) tui_alloc_content (1, locator->type);
299       locator->content_size = 1;
300     }
301 
302   element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
303   element->proc_name[0] = (char) 0;
304   strcat_to_buf (element->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
305   element->line_no = lineno;
306   element->addr = addr;
307   tui_set_locator_filename (filename);
308 }
309 
310 /* Update only the filename portion of the locator.  */
311 void
tui_update_locator_filename(const char * filename)312 tui_update_locator_filename (const char *filename)
313 {
314   tui_set_locator_filename (filename);
315   tui_show_locator_content ();
316 }
317 
318 /* Function to print the frame information for the TUI.  */
319 void
tui_show_frame_info(struct frame_info * fi)320 tui_show_frame_info (struct frame_info *fi)
321 {
322   struct tui_win_info * win_info;
323   int i;
324 
325   if (fi)
326     {
327       int start_line, i;
328       CORE_ADDR low;
329       struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
330       int source_already_displayed;
331       struct symtab_and_line sal;
332 
333       find_frame_sal (fi, &sal);
334 
335       source_already_displayed = sal.symtab != 0
336         && tui_source_is_displayed (sal.symtab->filename);
337       tui_set_locator_info (sal.symtab == 0 ? "??" : sal.symtab->filename,
338                             tui_get_function_from_frame (fi),
339                             sal.line,
340                             get_frame_pc (fi));
341       tui_show_locator_content ();
342       start_line = 0;
343       for (i = 0; i < (tui_source_windows ())->count; i++)
344 	{
345 	  union tui_which_element *item;
346 	  win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
347 
348 	  item = &((struct tui_win_element *) locator->content[0])->which_element;
349 	  if (win_info == TUI_SRC_WIN)
350 	    {
351 	      start_line = (item->locator.line_no -
352 			   (win_info->generic.viewport_height / 2)) + 1;
353 	      if (start_line <= 0)
354 		start_line = 1;
355 	    }
356 	  else
357 	    {
358 	      if (find_pc_partial_function (get_frame_pc (fi), (char **) NULL,
359 					    &low, NULL) == 0)
360 		error ("No function contains program counter for selected frame.\n");
361 	      else
362 		low = tui_get_low_disassembly_address (low, get_frame_pc (fi));
363 	    }
364 
365 	  if (win_info == TUI_SRC_WIN)
366 	    {
367 	      union tui_line_or_address l;
368 	      l.line_no = start_line;
369 	      if (!(source_already_displayed
370 		    && tui_line_is_displayed (item->locator.line_no, win_info, TRUE)))
371 		tui_update_source_window (win_info, sal.symtab, l, TRUE);
372 	      else
373 		{
374 		  l.line_no = item->locator.line_no;
375 		  tui_set_is_exec_point_at (l, win_info);
376 		}
377 	    }
378 	  else
379 	    {
380 	      if (win_info == TUI_DISASM_WIN)
381 		{
382 		  union tui_line_or_address a;
383 		  a.addr = low;
384 		  if (!tui_addr_is_displayed (item->locator.addr, win_info, TRUE))
385 		    tui_update_source_window (win_info, sal.symtab, a, TRUE);
386 		  else
387 		    {
388 		      a.addr = item->locator.addr;
389 		      tui_set_is_exec_point_at (a, win_info);
390 		    }
391 		}
392 	    }
393 	  tui_update_exec_info (win_info);
394 	}
395     }
396   else
397     {
398       tui_set_locator_info (NULL, NULL, 0, (CORE_ADDR) 0);
399       tui_show_locator_content ();
400       for (i = 0; i < (tui_source_windows ())->count; i++)
401 	{
402 	  win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
403 	  tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
404 	  tui_update_exec_info (win_info);
405 	}
406     }
407 }
408 
409 /* Function to initialize gdb commands, for tui window stack
410    manipulation.  */
411 void
_initialize_tui_stack(void)412 _initialize_tui_stack (void)
413 {
414   add_com ("update", class_tui, tui_update_command,
415            "Update the source window and locator to display the current "
416            "execution point.\n");
417 }
418 
419 /* Command to update the display with the current execution point.  */
420 static void
tui_update_command(char * arg,int from_tty)421 tui_update_command (char *arg, int from_tty)
422 {
423   char cmd[sizeof("frame 0")];
424 
425   strcpy (cmd, "frame 0");
426   execute_command (cmd, from_tty);
427 }
428