1130803Smarcel/* TUI display locator.
2130803Smarcel
3130803Smarcel   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software
4130803Smarcel   Foundation, Inc.
5130803Smarcel
6130803Smarcel   Contributed by Hewlett-Packard Company.
7130803Smarcel
8130803Smarcel   This file is part of GDB.
9130803Smarcel
10130803Smarcel   This program is free software; you can redistribute it and/or modify
11130803Smarcel   it under the terms of the GNU General Public License as published by
12130803Smarcel   the Free Software Foundation; either version 2 of the License, or
13130803Smarcel   (at your option) any later version.
14130803Smarcel
15130803Smarcel   This program is distributed in the hope that it will be useful,
16130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
17130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18130803Smarcel   GNU General Public License for more details.
19130803Smarcel
20130803Smarcel   You should have received a copy of the GNU General Public License
21130803Smarcel   along with this program; if not, write to the Free Software
22130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
23130803Smarcel   Boston, MA 02111-1307, USA.  */
24130803Smarcel
25130803Smarcel#include "defs.h"
26130803Smarcel#include "symtab.h"
27130803Smarcel#include "breakpoint.h"
28130803Smarcel#include "frame.h"
29130803Smarcel#include "command.h"
30130803Smarcel#include "inferior.h"
31130803Smarcel#include "target.h"
32130803Smarcel#include "top.h"
33130803Smarcel#include "gdb_string.h"
34130803Smarcel#include "tui/tui.h"
35130803Smarcel#include "tui/tui-data.h"
36130803Smarcel#include "tui/tui-stack.h"
37130803Smarcel#include "tui/tui-wingeneral.h"
38130803Smarcel#include "tui/tui-source.h"
39130803Smarcel#include "tui/tui-winsource.h"
40130803Smarcel#include "tui/tui-file.h"
41130803Smarcel
42130803Smarcel#include "gdb_curses.h"
43130803Smarcel
44130803Smarcel/* Get a printable name for the function at the address.
45130803Smarcel   The symbol name is demangled if demangling is turned on.
46130803Smarcel   Returns a pointer to a static area holding the result.  */
47130803Smarcelstatic char* tui_get_function_from_frame (struct frame_info *fi);
48130803Smarcel
49130803Smarcel/* Set the filename portion of the locator.  */
50130803Smarcelstatic void tui_set_locator_filename (const char *filename);
51130803Smarcel
52130803Smarcel/* Update the locator, with the provided arguments.  */
53130803Smarcelstatic void tui_set_locator_info (const char *filename, const char *procname,
54130803Smarcel                                  int lineno, CORE_ADDR addr);
55130803Smarcel
56130803Smarcelstatic void tui_update_command (char *, int);
57130803Smarcel
58130803Smarcel
59130803Smarcel/* Create the status line to display as much information as we
60130803Smarcel   can on this single line: target name, process number, current
61130803Smarcel   function, current line, current PC, SingleKey mode.  */
62130803Smarcelstatic char*
63130803Smarceltui_make_status_line (struct tui_locator_element* loc)
64130803Smarcel{
65130803Smarcel  char* string;
66130803Smarcel  char line_buf[50], *pname;
67130803Smarcel  char* buf;
68130803Smarcel  int status_size;
69130803Smarcel  int i, proc_width;
70130803Smarcel  const char* pid_name;
71130803Smarcel  const char* pc_buf;
72130803Smarcel  int target_width;
73130803Smarcel  int pid_width;
74130803Smarcel  int line_width;
75130803Smarcel  int pc_width;
76130803Smarcel  struct ui_file *pc_out;
77130803Smarcel
78130803Smarcel  if (ptid_equal (inferior_ptid, null_ptid))
79130803Smarcel    pid_name = "No process";
80130803Smarcel  else
81130803Smarcel    pid_name = target_pid_to_str (inferior_ptid);
82130803Smarcel
83130803Smarcel  target_width = strlen (target_shortname);
84130803Smarcel  if (target_width > MAX_TARGET_WIDTH)
85130803Smarcel    target_width = MAX_TARGET_WIDTH;
86130803Smarcel
87130803Smarcel  pid_width = strlen (pid_name);
88130803Smarcel  if (pid_width > MAX_PID_WIDTH)
89130803Smarcel    pid_width = MAX_PID_WIDTH;
90130803Smarcel
91130803Smarcel  status_size = tui_term_width ();
92130803Smarcel  string = (char *) xmalloc (status_size + 1);
93130803Smarcel  buf = (char*) alloca (status_size + 1);
94130803Smarcel
95130803Smarcel  /* Translate line number and obtain its size.  */
96130803Smarcel  if (loc->line_no > 0)
97130803Smarcel    sprintf (line_buf, "%d", loc->line_no);
98130803Smarcel  else
99130803Smarcel    strcpy (line_buf, "??");
100130803Smarcel  line_width = strlen (line_buf);
101130803Smarcel  if (line_width < MIN_LINE_WIDTH)
102130803Smarcel    line_width = MIN_LINE_WIDTH;
103130803Smarcel
104130803Smarcel  /* Translate PC address.  */
105130803Smarcel  pc_out = tui_sfileopen (128);
106130803Smarcel  print_address_numeric (loc->addr, 1, pc_out);
107130803Smarcel  pc_buf = tui_file_get_strbuf (pc_out);
108130803Smarcel  pc_width = strlen (pc_buf);
109130803Smarcel
110130803Smarcel  /* First determine the amount of proc name width we have available.
111130803Smarcel     The +1 are for a space separator between fields.
112130803Smarcel     The -1 are to take into account the \0 counted by sizeof.  */
113130803Smarcel  proc_width = (status_size
114130803Smarcel                - (target_width + 1)
115130803Smarcel                - (pid_width + 1)
116130803Smarcel                - (sizeof (PROC_PREFIX) - 1 + 1)
117130803Smarcel                - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
118130803Smarcel                - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
119130803Smarcel                - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
120130803Smarcel                   ? (sizeof (SINGLE_KEY) - 1 + 1)
121130803Smarcel                   : 0));
122130803Smarcel
123130803Smarcel  /* If there is no room to print the function name, try by removing
124130803Smarcel     some fields.  */
125130803Smarcel  if (proc_width < MIN_PROC_WIDTH)
126130803Smarcel    {
127130803Smarcel      proc_width += target_width + 1;
128130803Smarcel      target_width = 0;
129130803Smarcel      if (proc_width < MIN_PROC_WIDTH)
130130803Smarcel        {
131130803Smarcel          proc_width += pid_width + 1;
132130803Smarcel          pid_width = 0;
133130803Smarcel          if (proc_width <= MIN_PROC_WIDTH)
134130803Smarcel            {
135130803Smarcel              proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
136130803Smarcel              pc_width = 0;
137130803Smarcel              if (proc_width < 0)
138130803Smarcel                {
139130803Smarcel                  proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
140130803Smarcel                  line_width = 0;
141130803Smarcel                  if (proc_width < 0)
142130803Smarcel                    proc_width = 0;
143130803Smarcel                }
144130803Smarcel            }
145130803Smarcel        }
146130803Smarcel    }
147130803Smarcel
148130803Smarcel  /* Now convert elements to string form */
149130803Smarcel  pname = loc->proc_name;
150130803Smarcel
151130803Smarcel  /* Now create the locator line from the string version
152130803Smarcel     of the elements.  We could use sprintf() here but
153130803Smarcel     that wouldn't ensure that we don't overrun the size
154130803Smarcel     of the allocated buffer.  strcat_to_buf() will.  */
155130803Smarcel  *string = (char) 0;
156130803Smarcel
157130803Smarcel  if (target_width > 0)
158130803Smarcel    {
159130803Smarcel      sprintf (buf, "%*.*s ",
160130803Smarcel               -target_width, target_width, target_shortname);
161130803Smarcel      strcat_to_buf (string, status_size, buf);
162130803Smarcel    }
163130803Smarcel  if (pid_width > 0)
164130803Smarcel    {
165130803Smarcel      sprintf (buf, "%*.*s ",
166130803Smarcel               -pid_width, pid_width, pid_name);
167130803Smarcel      strcat_to_buf (string, status_size, buf);
168130803Smarcel    }
169130803Smarcel
170130803Smarcel  /* Show whether we are in SingleKey mode.  */
171130803Smarcel  if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
172130803Smarcel    {
173130803Smarcel      strcat_to_buf (string, status_size, SINGLE_KEY);
174130803Smarcel      strcat_to_buf (string, status_size, " ");
175130803Smarcel    }
176130803Smarcel
177130803Smarcel  /* procedure/class name */
178130803Smarcel  if (proc_width > 0)
179130803Smarcel    {
180130803Smarcel      if (strlen (pname) > proc_width)
181130803Smarcel        sprintf (buf, "%s%*.*s* ", PROC_PREFIX,
182130803Smarcel                 1 - proc_width, proc_width - 1, pname);
183130803Smarcel      else
184130803Smarcel        sprintf (buf, "%s%*.*s ", PROC_PREFIX,
185130803Smarcel                 -proc_width, proc_width, pname);
186130803Smarcel      strcat_to_buf (string, status_size, buf);
187130803Smarcel    }
188130803Smarcel
189130803Smarcel  if (line_width > 0)
190130803Smarcel    {
191130803Smarcel      sprintf (buf, "%s%*.*s ", LINE_PREFIX,
192130803Smarcel               -line_width, line_width, line_buf);
193130803Smarcel      strcat_to_buf (string, status_size, buf);
194130803Smarcel    }
195130803Smarcel  if (pc_width > 0)
196130803Smarcel    {
197130803Smarcel      strcat_to_buf (string, status_size, PC_PREFIX);
198130803Smarcel      strcat_to_buf (string, status_size, pc_buf);
199130803Smarcel    }
200130803Smarcel
201130803Smarcel
202130803Smarcel  for (i = strlen (string); i < status_size; i++)
203130803Smarcel    string[i] = ' ';
204130803Smarcel  string[status_size] = (char) 0;
205130803Smarcel
206130803Smarcel  ui_file_delete (pc_out);
207130803Smarcel  return string;
208130803Smarcel}
209130803Smarcel
210130803Smarcel/* Get a printable name for the function at the address.
211130803Smarcel   The symbol name is demangled if demangling is turned on.
212130803Smarcel   Returns a pointer to a static area holding the result.  */
213130803Smarcelstatic char*
214130803Smarceltui_get_function_from_frame (struct frame_info *fi)
215130803Smarcel{
216130803Smarcel  static char name[256];
217130803Smarcel  struct ui_file *stream = tui_sfileopen (256);
218130803Smarcel  char *p;
219130803Smarcel
220130803Smarcel  print_address_symbolic (get_frame_pc (fi), stream, demangle, "");
221130803Smarcel  p = tui_file_get_strbuf (stream);
222130803Smarcel
223130803Smarcel  /* Use simple heuristics to isolate the function name.  The symbol can
224130803Smarcel     be demangled and we can have function parameters.  Remove them because
225130803Smarcel     the status line is too short to display them.  */
226130803Smarcel  if (*p == '<')
227130803Smarcel    p++;
228130803Smarcel  strncpy (name, p, sizeof (name));
229130803Smarcel  p = strchr (name, '(');
230130803Smarcel  if (!p)
231130803Smarcel    p = strchr (name, '>');
232130803Smarcel  if (p)
233130803Smarcel    *p = 0;
234130803Smarcel  p = strchr (name, '+');
235130803Smarcel  if (p)
236130803Smarcel    *p = 0;
237130803Smarcel  ui_file_delete (stream);
238130803Smarcel  return name;
239130803Smarcel}
240130803Smarcel
241130803Smarcelvoid
242130803Smarceltui_show_locator_content (void)
243130803Smarcel{
244130803Smarcel  char *string;
245130803Smarcel  struct tui_gen_win_info * locator;
246130803Smarcel
247130803Smarcel  locator = tui_locator_win_info_ptr ();
248130803Smarcel
249130803Smarcel  if (locator != NULL && locator->handle != (WINDOW *) NULL)
250130803Smarcel    {
251130803Smarcel      struct tui_win_element * element;
252130803Smarcel
253130803Smarcel      element = (struct tui_win_element *) locator->content[0];
254130803Smarcel
255130803Smarcel      string = tui_make_status_line (&element->which_element.locator);
256130803Smarcel      wmove (locator->handle, 0, 0);
257130803Smarcel      wstandout (locator->handle);
258130803Smarcel      waddstr (locator->handle, string);
259130803Smarcel      wclrtoeol (locator->handle);
260130803Smarcel      wstandend (locator->handle);
261130803Smarcel      tui_refresh_win (locator);
262130803Smarcel      wmove (locator->handle, 0, 0);
263130803Smarcel      xfree (string);
264130803Smarcel      locator->content_in_use = TRUE;
265130803Smarcel    }
266130803Smarcel}
267130803Smarcel
268130803Smarcel
269130803Smarcel/* Set the filename portion of the locator.  */
270130803Smarcelstatic void
271130803Smarceltui_set_locator_filename (const char *filename)
272130803Smarcel{
273130803Smarcel  struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
274130803Smarcel  struct tui_locator_element * element;
275130803Smarcel
276130803Smarcel  if (locator->content[0] == NULL)
277130803Smarcel    {
278130803Smarcel      tui_set_locator_info (filename, NULL, 0, 0);
279130803Smarcel      return;
280130803Smarcel    }
281130803Smarcel
282130803Smarcel  element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
283130803Smarcel  element->file_name[0] = 0;
284130803Smarcel  strcat_to_buf (element->file_name, MAX_LOCATOR_ELEMENT_LEN, filename);
285130803Smarcel}
286130803Smarcel
287130803Smarcel/* Update the locator, with the provided arguments.  */
288130803Smarcelstatic void
289130803Smarceltui_set_locator_info (const char *filename, const char *procname, int lineno,
290130803Smarcel                      CORE_ADDR addr)
291130803Smarcel{
292130803Smarcel  struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
293130803Smarcel  struct tui_locator_element * element;
294130803Smarcel
295130803Smarcel  /* Allocate the locator content if necessary.  */
296130803Smarcel  if (locator->content_size <= 0)
297130803Smarcel    {
298130803Smarcel      locator->content = (void **) tui_alloc_content (1, locator->type);
299130803Smarcel      locator->content_size = 1;
300130803Smarcel    }
301130803Smarcel
302130803Smarcel  element = &((struct tui_win_element *) locator->content[0])->which_element.locator;
303130803Smarcel  element->proc_name[0] = (char) 0;
304130803Smarcel  strcat_to_buf (element->proc_name, MAX_LOCATOR_ELEMENT_LEN, procname);
305130803Smarcel  element->line_no = lineno;
306130803Smarcel  element->addr = addr;
307130803Smarcel  tui_set_locator_filename (filename);
308130803Smarcel}
309130803Smarcel
310130803Smarcel/* Update only the filename portion of the locator.  */
311130803Smarcelvoid
312130803Smarceltui_update_locator_filename (const char *filename)
313130803Smarcel{
314130803Smarcel  tui_set_locator_filename (filename);
315130803Smarcel  tui_show_locator_content ();
316130803Smarcel}
317130803Smarcel
318130803Smarcel/* Function to print the frame information for the TUI.  */
319130803Smarcelvoid
320130803Smarceltui_show_frame_info (struct frame_info *fi)
321130803Smarcel{
322130803Smarcel  struct tui_win_info * win_info;
323130803Smarcel  int i;
324130803Smarcel
325130803Smarcel  if (fi)
326130803Smarcel    {
327130803Smarcel      int start_line, i;
328130803Smarcel      CORE_ADDR low;
329130803Smarcel      struct tui_gen_win_info * locator = tui_locator_win_info_ptr ();
330130803Smarcel      int source_already_displayed;
331130803Smarcel      struct symtab_and_line sal;
332130803Smarcel
333130803Smarcel      find_frame_sal (fi, &sal);
334130803Smarcel
335130803Smarcel      source_already_displayed = sal.symtab != 0
336130803Smarcel        && tui_source_is_displayed (sal.symtab->filename);
337130803Smarcel      tui_set_locator_info (sal.symtab == 0 ? "??" : sal.symtab->filename,
338130803Smarcel                            tui_get_function_from_frame (fi),
339130803Smarcel                            sal.line,
340130803Smarcel                            get_frame_pc (fi));
341130803Smarcel      tui_show_locator_content ();
342130803Smarcel      start_line = 0;
343130803Smarcel      for (i = 0; i < (tui_source_windows ())->count; i++)
344130803Smarcel	{
345130803Smarcel	  union tui_which_element *item;
346130803Smarcel	  win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
347130803Smarcel
348130803Smarcel	  item = &((struct tui_win_element *) locator->content[0])->which_element;
349130803Smarcel	  if (win_info == TUI_SRC_WIN)
350130803Smarcel	    {
351130803Smarcel	      start_line = (item->locator.line_no -
352130803Smarcel			   (win_info->generic.viewport_height / 2)) + 1;
353130803Smarcel	      if (start_line <= 0)
354130803Smarcel		start_line = 1;
355130803Smarcel	    }
356130803Smarcel	  else
357130803Smarcel	    {
358130803Smarcel	      if (find_pc_partial_function (get_frame_pc (fi), (char **) NULL,
359130803Smarcel					    &low, (CORE_ADDR) NULL) == 0)
360130803Smarcel		error ("No function contains program counter for selected frame.\n");
361130803Smarcel	      else
362130803Smarcel		low = tui_get_low_disassembly_address (low, get_frame_pc (fi));
363130803Smarcel	    }
364130803Smarcel
365130803Smarcel	  if (win_info == TUI_SRC_WIN)
366130803Smarcel	    {
367130803Smarcel	      union tui_line_or_address l;
368130803Smarcel	      l.line_no = start_line;
369130803Smarcel	      if (!(source_already_displayed
370130803Smarcel		    && tui_line_is_displayed (item->locator.line_no, win_info, TRUE)))
371130803Smarcel		tui_update_source_window (win_info, sal.symtab, l, TRUE);
372130803Smarcel	      else
373130803Smarcel		{
374130803Smarcel		  l.line_no = item->locator.line_no;
375130803Smarcel		  tui_set_is_exec_point_at (l, win_info);
376130803Smarcel		}
377130803Smarcel	    }
378130803Smarcel	  else
379130803Smarcel	    {
380130803Smarcel	      if (win_info == TUI_DISASM_WIN)
381130803Smarcel		{
382130803Smarcel		  union tui_line_or_address a;
383130803Smarcel		  a.addr = low;
384130803Smarcel		  if (!tui_addr_is_displayed (item->locator.addr, win_info, TRUE))
385130803Smarcel		    tui_update_source_window (win_info, sal.symtab, a, TRUE);
386130803Smarcel		  else
387130803Smarcel		    {
388130803Smarcel		      a.addr = item->locator.addr;
389130803Smarcel		      tui_set_is_exec_point_at (a, win_info);
390130803Smarcel		    }
391130803Smarcel		}
392130803Smarcel	    }
393130803Smarcel	  tui_update_exec_info (win_info);
394130803Smarcel	}
395130803Smarcel    }
396130803Smarcel  else
397130803Smarcel    {
398130803Smarcel      tui_set_locator_info (NULL, NULL, 0, (CORE_ADDR) 0);
399130803Smarcel      tui_show_locator_content ();
400130803Smarcel      for (i = 0; i < (tui_source_windows ())->count; i++)
401130803Smarcel	{
402130803Smarcel	  win_info = (struct tui_win_info *) (tui_source_windows ())->list[i];
403130803Smarcel	  tui_clear_source_content (win_info, EMPTY_SOURCE_PROMPT);
404130803Smarcel	  tui_update_exec_info (win_info);
405130803Smarcel	}
406130803Smarcel    }
407130803Smarcel}
408130803Smarcel
409130803Smarcel/* Function to initialize gdb commands, for tui window stack
410130803Smarcel   manipulation.  */
411130803Smarcelvoid
412130803Smarcel_initialize_tui_stack (void)
413130803Smarcel{
414130803Smarcel  add_com ("update", class_tui, tui_update_command,
415130803Smarcel           "Update the source window and locator to display the current "
416130803Smarcel           "execution point.\n");
417130803Smarcel}
418130803Smarcel
419130803Smarcel/* Command to update the display with the current execution point.  */
420130803Smarcelstatic void
421130803Smarceltui_update_command (char *arg, int from_tty)
422130803Smarcel{
423130803Smarcel  char cmd[sizeof("frame 0")];
424130803Smarcel
425130803Smarcel  strcpy (cmd, "frame 0");
426130803Smarcel  execute_command (cmd, from_tty);
427130803Smarcel}
428