tui-stack.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  1. /* TUI display locator.
  2. Copyright (C) 1998-2022 Free Software Foundation, Inc.
  3. Contributed by Hewlett-Packard Company.
  4. This file is part of GDB.
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 3 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. #include "defs.h"
  16. #include "symtab.h"
  17. #include "breakpoint.h"
  18. #include "frame.h"
  19. #include "command.h"
  20. #include "inferior.h"
  21. #include "target.h"
  22. #include "top.h"
  23. #include "gdb-demangle.h"
  24. #include "source.h"
  25. #include "tui/tui.h"
  26. #include "tui/tui-data.h"
  27. #include "tui/tui-stack.h"
  28. #include "tui/tui-wingeneral.h"
  29. #include "tui/tui-source.h"
  30. #include "tui/tui-winsource.h"
  31. #include "tui/tui-file.h"
  32. #include "tui/tui-location.h"
  33. #include "gdb_curses.h"
  34. #define PROC_PREFIX "In: "
  35. #define LINE_PREFIX "L"
  36. #define PC_PREFIX "PC: "
  37. /* Strings to display in the TUI status line. */
  38. #define SINGLE_KEY "(SingleKey)"
  39. /* Minimum/Maximum length of some fields displayed in the TUI status
  40. line. */
  41. #define MIN_LINE_WIDTH 4 /* Use at least 4 digits for line
  42. numbers. */
  43. #define MIN_PROC_WIDTH 12
  44. #define MAX_TARGET_WIDTH 10
  45. #define MAX_PID_WIDTH 19
  46. std::string
  47. tui_locator_window::make_status_line () const
  48. {
  49. char line_buf[50];
  50. int status_size;
  51. int proc_width;
  52. const char *pid_name;
  53. int target_width;
  54. int pid_width;
  55. int line_width;
  56. std::string pid_name_holder;
  57. if (inferior_ptid == null_ptid)
  58. pid_name = "No process";
  59. else
  60. {
  61. pid_name_holder = target_pid_to_str (inferior_ptid);
  62. pid_name = pid_name_holder.c_str ();
  63. }
  64. target_width = strlen (target_shortname ());
  65. if (target_width > MAX_TARGET_WIDTH)
  66. target_width = MAX_TARGET_WIDTH;
  67. pid_width = strlen (pid_name);
  68. if (pid_width > MAX_PID_WIDTH)
  69. pid_width = MAX_PID_WIDTH;
  70. status_size = width;
  71. /* Translate line number and obtain its size. */
  72. int line_no = tui_location.line_no ();
  73. if (line_no > 0)
  74. xsnprintf (line_buf, sizeof (line_buf), "%d", line_no);
  75. else
  76. strcpy (line_buf, "??");
  77. line_width = strlen (line_buf);
  78. if (line_width < MIN_LINE_WIDTH)
  79. line_width = MIN_LINE_WIDTH;
  80. /* Translate PC address. */
  81. struct gdbarch *gdbarch = tui_location.gdbarch ();
  82. CORE_ADDR addr = tui_location.addr ();
  83. std::string pc_out (gdbarch
  84. ? paddress (gdbarch, addr)
  85. : "??");
  86. const char *pc_buf = pc_out.c_str ();
  87. int pc_width = pc_out.size ();
  88. /* First determine the amount of proc name width we have available.
  89. The +1 are for a space separator between fields.
  90. The -1 are to take into account the \0 counted by sizeof. */
  91. proc_width = (status_size
  92. - (target_width + 1)
  93. - (pid_width + 1)
  94. - (sizeof (PROC_PREFIX) - 1 + 1)
  95. - (sizeof (LINE_PREFIX) - 1 + line_width + 1)
  96. - (sizeof (PC_PREFIX) - 1 + pc_width + 1)
  97. - (tui_current_key_mode == TUI_SINGLE_KEY_MODE
  98. ? (sizeof (SINGLE_KEY) - 1 + 1)
  99. : 0));
  100. /* If there is no room to print the function name, try by removing
  101. some fields. */
  102. if (proc_width < MIN_PROC_WIDTH)
  103. {
  104. proc_width += target_width + 1;
  105. target_width = 0;
  106. if (proc_width < MIN_PROC_WIDTH)
  107. {
  108. proc_width += pid_width + 1;
  109. pid_width = 0;
  110. if (proc_width <= MIN_PROC_WIDTH)
  111. {
  112. proc_width += pc_width + sizeof (PC_PREFIX) - 1 + 1;
  113. pc_width = 0;
  114. if (proc_width < 0)
  115. {
  116. proc_width += line_width + sizeof (LINE_PREFIX) - 1 + 1;
  117. line_width = 0;
  118. if (proc_width < 0)
  119. proc_width = 0;
  120. }
  121. }
  122. }
  123. }
  124. /* Now create the locator line from the string version of the
  125. elements. */
  126. string_file string;
  127. if (target_width > 0)
  128. string.printf ("%*.*s ", -target_width, target_width, target_shortname ());
  129. if (pid_width > 0)
  130. string.printf ("%*.*s ", -pid_width, pid_width, pid_name);
  131. /* Show whether we are in SingleKey mode. */
  132. if (tui_current_key_mode == TUI_SINGLE_KEY_MODE)
  133. {
  134. string.puts (SINGLE_KEY);
  135. string.puts (" ");
  136. }
  137. /* Procedure/class name. */
  138. if (proc_width > 0)
  139. {
  140. const std::string &proc_name = tui_location.proc_name ();
  141. if (proc_name.size () > proc_width)
  142. string.printf ("%s%*.*s* ", PROC_PREFIX,
  143. 1 - proc_width, proc_width - 1, proc_name.c_str ());
  144. else
  145. string.printf ("%s%*.*s ", PROC_PREFIX,
  146. -proc_width, proc_width, proc_name.c_str ());
  147. }
  148. if (line_width > 0)
  149. string.printf ("%s%*.*s ", LINE_PREFIX,
  150. -line_width, line_width, line_buf);
  151. if (pc_width > 0)
  152. {
  153. string.puts (PC_PREFIX);
  154. string.puts (pc_buf);
  155. }
  156. std::string string_val = string.release ();
  157. if (string.size () < status_size)
  158. string_val.append (status_size - string.size (), ' ');
  159. else if (string.size () > status_size)
  160. string_val.erase (status_size, string.size ());
  161. return string_val;
  162. }
  163. /* Get a printable name for the function at the address. The symbol
  164. name is demangled if demangling is turned on. Returns a pointer to
  165. a static area holding the result. */
  166. static char*
  167. tui_get_function_from_frame (struct frame_info *fi)
  168. {
  169. static char name[256];
  170. string_file stream;
  171. print_address_symbolic (get_frame_arch (fi), get_frame_pc (fi),
  172. &stream, demangle, "");
  173. /* Use simple heuristics to isolate the function name. The symbol
  174. can be demangled and we can have function parameters. Remove
  175. them because the status line is too short to display them. */
  176. const char *d = stream.c_str ();
  177. if (*d == '<')
  178. d++;
  179. strncpy (name, d, sizeof (name) - 1);
  180. name[sizeof (name) - 1] = 0;
  181. char *p = strchr (name, '(');
  182. if (!p)
  183. p = strchr (name, '>');
  184. if (p)
  185. *p = 0;
  186. p = strchr (name, '+');
  187. if (p)
  188. *p = 0;
  189. return name;
  190. }
  191. void
  192. tui_locator_window::rerender ()
  193. {
  194. gdb_assert (handle != NULL);
  195. std::string string = make_status_line ();
  196. scrollok (handle.get (), FALSE);
  197. wmove (handle.get (), 0, 0);
  198. /* We ignore the return value from wstandout and wstandend, casting them
  199. to void in order to avoid a compiler warning. The warning itself was
  200. introduced by a patch to ncurses 5.7 dated 2009-08-29, changing these
  201. macro to expand to code that causes the compiler to generate an
  202. unused-value warning. */
  203. (void) wstandout (handle.get ());
  204. waddstr (handle.get (), string.c_str ());
  205. wclrtoeol (handle.get ());
  206. (void) wstandend (handle.get ());
  207. refresh_window ();
  208. wmove (handle.get (), 0, 0);
  209. }
  210. /* Function to print the frame information for the TUI. The windows are
  211. refreshed only if frame information has changed since the last refresh.
  212. Return true if frame information has changed (and windows
  213. subsequently refreshed), false otherwise. */
  214. bool
  215. tui_show_frame_info (struct frame_info *fi)
  216. {
  217. bool locator_changed_p;
  218. if (fi != nullptr)
  219. {
  220. symtab_and_line sal = find_frame_sal (fi);
  221. const char *func_name;
  222. /* find_frame_sal does not always set PC, but we want to ensure
  223. that it is available in the SAL. */
  224. if (get_frame_pc_if_available (fi, &sal.pc))
  225. func_name = tui_get_function_from_frame (fi);
  226. else
  227. func_name = _("<unavailable>");
  228. locator_changed_p
  229. = tui_location.set_location (get_frame_arch (fi), sal, func_name);
  230. /* If the locator information has not changed, then frame information has
  231. not changed. If frame information has not changed, then the windows'
  232. contents will not change. So don't bother refreshing the windows. */
  233. if (!locator_changed_p)
  234. return false;
  235. for (struct tui_source_window_base *win_info : tui_source_windows ())
  236. {
  237. win_info->maybe_update (fi, sal);
  238. win_info->update_exec_info ();
  239. }
  240. }
  241. else
  242. {
  243. symtab_and_line sal {};
  244. locator_changed_p = tui_location.set_location (NULL, sal, "");
  245. if (!locator_changed_p)
  246. return false;
  247. for (struct tui_source_window_base *win_info : tui_source_windows ())
  248. win_info->erase_source_content ();
  249. }
  250. return true;
  251. }
  252. void
  253. tui_show_locator_content ()
  254. {
  255. if (tui_is_window_visible (STATUS_WIN))
  256. TUI_STATUS_WIN->rerender ();
  257. }
  258. /* Command to update the display with the current execution point. */
  259. static void
  260. tui_update_command (const char *arg, int from_tty)
  261. {
  262. execute_command ("frame 0", from_tty);
  263. }
  264. /* Function to initialize gdb commands, for tui window stack
  265. manipulation. */
  266. void _initialize_tui_stack ();
  267. void
  268. _initialize_tui_stack ()
  269. {
  270. add_com ("update", class_tui, tui_update_command,
  271. _("Update the source window and locator to "
  272. "display the current execution point.\n\
  273. Usage: update"));
  274. }