Merge from vendor branch GDB:
[dragonfly.git] / contrib / gdb-6 / gdb / tui / tui-stack.c
1 /* TUI display locator.
2
3    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006, 2007
4    Free Software 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 3 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, see <http://www.gnu.org/licenses/>.  */
22
23 #include "defs.h"
24 #include "symtab.h"
25 #include "breakpoint.h"
26 #include "frame.h"
27 #include "command.h"
28 #include "inferior.h"
29 #include "target.h"
30 #include "top.h"
31 #include "gdb_string.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 /* Get a printable name for the function at the address.
43    The symbol name is demangled if demangling is turned on.
44    Returns a pointer to a static area holding the result.  */
45 static char *tui_get_function_from_frame (struct frame_info *fi);
46
47 /* Set the filename portion of the locator.  */
48 static void tui_set_locator_filename (const char *filename);
49
50 /* Update the locator, with the provided arguments.  */
51 static void tui_set_locator_info (const char *filename,
52                                   const char *procname,
53                                   int lineno, CORE_ADDR addr);
54
55 static void tui_update_command (char *, int);
56 \f
57
58 /* Create the status line to display as much information as we can on
59    this single line: target name, process number, current function,
60    current line, current PC, SingleKey mode.  */
61 static char*
62 tui_make_status_line (struct tui_locator_element *loc)
63 {
64   char *string;
65   char line_buf[50], *pname;
66   char *buf;
67   int status_size;
68   int i, proc_width;
69   const char *pid_name;
70   const char *pc_buf;
71   int target_width;
72   int pid_width;
73   int line_width;
74   int pc_width;
75   struct ui_file *pc_out;
76
77   if (ptid_equal (inferior_ptid, null_ptid))
78     pid_name = "No process";
79   else
80     pid_name = target_pid_to_str (inferior_ptid);
81
82   target_width = strlen (target_shortname);
83   if (target_width > MAX_TARGET_WIDTH)
84     target_width = MAX_TARGET_WIDTH;
85
86   pid_width = strlen (pid_name);
87   if (pid_width > MAX_PID_WIDTH)
88     pid_width = MAX_PID_WIDTH;
89
90   status_size = tui_term_width ();
91   string = (char *) xmalloc (status_size + 1);
92   buf = (char*) alloca (status_size + 1);
93
94   /* Translate line number and obtain its size.  */
95   if (loc->line_no > 0)
96     sprintf (line_buf, "%d", loc->line_no);
97   else
98     strcpy (line_buf, "??");
99   line_width = strlen (line_buf);
100   if (line_width < MIN_LINE_WIDTH)
101     line_width = MIN_LINE_WIDTH;
102
103   /* Translate PC address.  */
104   pc_out = tui_sfileopen (128);
105   deprecated_print_address_numeric (loc->addr, 1, pc_out);
106   pc_buf = tui_file_get_strbuf (pc_out);
107   pc_width = strlen (pc_buf);
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 convert elements to string form.  */
148   pname = loc->proc_name;
149
150   /* Now create the locator line from the string version of the
151      elements.  We could use sprintf() here but that wouldn't ensure
152      that we don't overrun the size of the allocated buffer.
153      strcat_to_buf() will.  */
154   *string = (char) 0;
155
156   if (target_width > 0)
157     {
158       sprintf (buf, "%*.*s ",
159                -target_width, target_width, target_shortname);
160       strcat_to_buf (string, status_size, buf);
161     }
162   if (pid_width > 0)
163     {
164       sprintf (buf, "%*.*s ",
165                -pid_width, pid_width, pid_name);
166       strcat_to_buf (string, status_size, buf);
167     }
168   
169   /* Show whether we are in SingleKey mode.  */
170   if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
171     {
172       strcat_to_buf (string, status_size, SINGLE_KEY);
173       strcat_to_buf (string, status_size, " ");
174     }
175
176   /* Procedure/class name.  */
177   if (proc_width > 0)
178     {
179       if (strlen (pname) > proc_width)
180         sprintf (buf, "%s%*.*s* ", PROC_PREFIX,
181                  1 - proc_width, proc_width - 1, pname);
182       else
183         sprintf (buf, "%s%*.*s ", PROC_PREFIX,
184                  -proc_width, proc_width, pname);
185       strcat_to_buf (string, status_size, buf);
186     }
187
188   if (line_width > 0)
189     {
190       sprintf (buf, "%s%*.*s ", LINE_PREFIX,
191                -line_width, line_width, line_buf);
192       strcat_to_buf (string, status_size, buf);
193     }
194   if (pc_width > 0)
195     {
196       strcat_to_buf (string, status_size, PC_PREFIX);
197       strcat_to_buf (string, status_size, pc_buf);
198     }
199   
200   
201   for (i = strlen (string); i < status_size; i++)
202     string[i] = ' ';
203   string[status_size] = (char) 0;
204
205   ui_file_delete (pc_out);
206   return string;
207 }
208
209 /* Get a printable name for the function at the address.  The symbol
210    name is demangled if demangling is turned on.  Returns a pointer to
211    a static area holding the result.  */
212 static char*
213 tui_get_function_from_frame (struct frame_info *fi)
214 {
215   static char name[256];
216   struct ui_file *stream = tui_sfileopen (256);
217   char *p;
218
219   print_address_symbolic (get_frame_pc (fi), stream, demangle, "");
220   p = tui_file_get_strbuf (stream);
221
222   /* Use simple heuristics to isolate the function name.  The symbol
223      can be demangled and we can have function parameters.  Remove
224      them because the status line is too short to display them.  */
225   if (*p == '<')
226     p++;
227   strncpy (name, p, sizeof (name));
228   p = strchr (name, '(');
229   if (!p)
230     p = strchr (name, '>');
231   if (p)
232     *p = 0;
233   p = strchr (name, '+');
234   if (p)
235     *p = 0;
236   ui_file_delete (stream);
237   return name;
238 }
239
240 void
241 tui_show_locator_content (void)
242 {
243   char *string;
244   struct tui_gen_win_info *locator;
245
246   locator = tui_locator_win_info_ptr ();
247
248   if (locator != NULL && locator->handle != (WINDOW *) NULL)
249     {
250       struct tui_win_element *element;
251
252       element = (struct tui_win_element *) locator->content[0];
253
254       string = tui_make_status_line (&element->which_element.locator);
255       wmove (locator->handle, 0, 0);
256       wstandout (locator->handle);
257       waddstr (locator->handle, string);
258       wclrtoeol (locator->handle);
259       wstandend (locator->handle);
260       tui_refresh_win (locator);
261       wmove (locator->handle, 0, 0);
262       xfree (string);
263       locator->content_in_use = TRUE;
264     }
265 }
266
267
268 /* Set the filename portion of the locator.  */
269 static void
270 tui_set_locator_filename (const char *filename)
271 {
272   struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
273   struct tui_locator_element *element;
274
275   if (locator->content[0] == NULL)
276     {
277       tui_set_locator_info (filename, NULL, 0, 0);
278       return;
279     }
280
281   element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
282   element->file_name[0] = 0;
283   strcat_to_buf (element->file_name, MAX_LOCATOR_ELEMENT_LEN, filename);
284 }
285
286 /* Update the locator, with the provided arguments.  */
287 static void
288 tui_set_locator_info (const char *filename, 
289                       const char *procname, 
290                       int lineno,
291                       CORE_ADDR addr)
292 {
293   struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
294   struct tui_locator_element *element;
295
296   /* Allocate the locator content if necessary.  */
297   if (locator->content_size <= 0)
298     {
299       locator->content = (void **) tui_alloc_content (1, locator->type);
300       locator->content_size = 1;
301     }
302
303   element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
304   element->proc_name[0] = (char) 0;
305   strcat_to_buf (element->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
306   element->line_no = lineno;
307   element->addr = addr;
308   tui_set_locator_filename (filename);
309 }
310
311 /* Update only the filename portion of the locator.  */
312 void
313 tui_update_locator_filename (const char *filename)
314 {
315   tui_set_locator_filename (filename);
316   tui_show_locator_content ();
317 }
318
319 /* Function to print the frame information for the TUI.  */
320 void
321 tui_show_frame_info (struct frame_info *fi)
322 {
323   struct tui_win_info *win_info;
324   int i;
325
326   if (fi)
327     {
328       int start_line, i;
329       CORE_ADDR low;
330       struct tui_gen_win_info *locator = tui_locator_win_info_ptr ();
331       int source_already_displayed;
332       struct symtab_and_line sal;
333
334       find_frame_sal (fi, &sal);
335
336       source_already_displayed = sal.symtab != 0
337         && tui_source_is_displayed (sal.symtab->filename);
338       tui_set_locator_info (sal.symtab == 0 ? "??" : sal.symtab->filename,
339                             tui_get_function_from_frame (fi),
340                             sal.line,
341                             get_frame_pc (fi));
342       tui_show_locator_content ();
343       start_line = 0;
344       for (i = 0; i < (tui_source_windows ())->count; i++)
345         {
346           union tui_which_element *item;
347           win_info = (tui_source_windows ())->list[i];
348
349           item = &((struct tui_win_element *) locator->content[0])->which_element;
350           if (win_info == TUI_SRC_WIN)
351             {
352               start_line = (item->locator.line_no -
353                            (win_info->generic.viewport_height / 2)) + 1;
354               if (start_line <= 0)
355                 start_line = 1;
356             }
357           else
358             {
359               if (find_pc_partial_function (get_frame_pc (fi), (char **) NULL,
360                                             &low, (CORE_ADDR) 0) == 0)
361                 error (_("No function contains program counter for selected frame."));
362               else
363                 low = tui_get_low_disassembly_address (low, get_frame_pc (fi));
364             }
365
366           if (win_info == TUI_SRC_WIN)
367             {
368               struct tui_line_or_address l;
369               l.loa = LOA_LINE;
370               l.u.line_no = start_line;
371               if (!(source_already_displayed
372                     && tui_line_is_displayed (item->locator.line_no, win_info, TRUE)))
373                 tui_update_source_window (win_info, sal.symtab, l, TRUE);
374               else
375                 {
376                   l.u.line_no = item->locator.line_no;
377                   tui_set_is_exec_point_at (l, win_info);
378                 }
379             }
380           else
381             {
382               if (win_info == TUI_DISASM_WIN)
383                 {
384                   struct tui_line_or_address a;
385                   a.loa = LOA_ADDRESS;
386                   a.u.addr = low;
387                   if (!tui_addr_is_displayed (item->locator.addr, win_info, TRUE))
388                     tui_update_source_window (win_info, sal.symtab, a, TRUE);
389                   else
390                     {
391                       a.u.addr = item->locator.addr;
392                       tui_set_is_exec_point_at (a, win_info);
393                     }
394                 }
395             }
396           tui_update_exec_info (win_info);
397         }
398     }
399   else
400     {
401       tui_set_locator_info (NULL, NULL, 0, (CORE_ADDR) 0);
402       tui_show_locator_content ();
403       for (i = 0; i < (tui_source_windows ())->count; i++)
404         {
405           win_info = (tui_source_windows ())->list[i];
406           tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
407           tui_update_exec_info (win_info);
408         }
409     }
410 }
411
412 /* Function to initialize gdb commands, for tui window stack
413    manipulation.  */
414 void
415 _initialize_tui_stack (void)
416 {
417   add_com ("update", class_tui, tui_update_command, _("\
418 Update the source window and locator to display the current execution point.\n"));
419 }
420
421 /* Command to update the display with the current execution point.  */
422 static void
423 tui_update_command (char *arg, int from_tty)
424 {
425   char cmd[sizeof("frame 0")];
426
427   strcpy (cmd, "frame 0");
428   execute_command (cmd, from_tty);
429 }