tui-regs.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659
  1. /* TUI display registers in window.
  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 "arch-utils.h"
  17. #include "tui/tui.h"
  18. #include "tui/tui-data.h"
  19. #include "symtab.h"
  20. #include "gdbtypes.h"
  21. #include "gdbcmd.h"
  22. #include "frame.h"
  23. #include "regcache.h"
  24. #include "inferior.h"
  25. #include "target.h"
  26. #include "tui/tui-layout.h"
  27. #include "tui/tui-win.h"
  28. #include "tui/tui-wingeneral.h"
  29. #include "tui/tui-file.h"
  30. #include "tui/tui-regs.h"
  31. #include "tui/tui-io.h"
  32. #include "reggroups.h"
  33. #include "valprint.h"
  34. #include "completer.h"
  35. #include "gdb_curses.h"
  36. /* A subclass of string_file that expands tab characters. */
  37. class tab_expansion_file : public string_file
  38. {
  39. public:
  40. tab_expansion_file () = default;
  41. void write (const char *buf, long length_buf) override;
  42. private:
  43. int m_column = 0;
  44. };
  45. void
  46. tab_expansion_file::write (const char *buf, long length_buf)
  47. {
  48. for (long i = 0; i < length_buf; ++i)
  49. {
  50. if (buf[i] == '\t')
  51. {
  52. do
  53. {
  54. string_file::write (" ", 1);
  55. ++m_column;
  56. }
  57. while ((m_column % 8) != 0);
  58. }
  59. else
  60. {
  61. string_file::write (&buf[i], 1);
  62. if (buf[i] == '\n')
  63. m_column = 0;
  64. else
  65. ++m_column;
  66. }
  67. }
  68. }
  69. /* Get the register from the frame and return a printable
  70. representation of it. */
  71. static std::string
  72. tui_register_format (struct frame_info *frame, int regnum)
  73. {
  74. struct gdbarch *gdbarch = get_frame_arch (frame);
  75. /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
  76. tab_expansion_file stream;
  77. scoped_restore save_pagination
  78. = make_scoped_restore (&pagination_enabled, 0);
  79. scoped_restore save_stdout
  80. = make_scoped_restore (&gdb_stdout, &stream);
  81. gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
  82. /* Remove the possible \n. */
  83. std::string str = stream.release ();
  84. if (!str.empty () && str.back () == '\n')
  85. str.resize (str.size () - 1);
  86. return str;
  87. }
  88. /* Get the register value from the given frame and format it for the
  89. display. When changep is set, check if the new register value has
  90. changed with respect to the previous call. */
  91. static void
  92. tui_get_register (struct frame_info *frame,
  93. struct tui_data_item_window *data,
  94. int regnum, bool *changedp)
  95. {
  96. if (changedp)
  97. *changedp = false;
  98. if (target_has_registers ())
  99. {
  100. std::string new_content = tui_register_format (frame, regnum);
  101. if (changedp != NULL && data->content != new_content)
  102. *changedp = true;
  103. data->content = std::move (new_content);
  104. }
  105. }
  106. /* See tui-regs.h. */
  107. int
  108. tui_data_window::last_regs_line_no () const
  109. {
  110. int num_lines = m_regs_content.size () / m_regs_column_count;
  111. if (m_regs_content.size () % m_regs_column_count)
  112. num_lines++;
  113. return num_lines;
  114. }
  115. /* See tui-regs.h. */
  116. int
  117. tui_data_window::line_from_reg_element_no (int element_no) const
  118. {
  119. if (element_no < m_regs_content.size ())
  120. {
  121. int i, line = (-1);
  122. i = 1;
  123. while (line == (-1))
  124. {
  125. if (element_no < m_regs_column_count * i)
  126. line = i - 1;
  127. else
  128. i++;
  129. }
  130. return line;
  131. }
  132. else
  133. return (-1);
  134. }
  135. /* See tui-regs.h. */
  136. int
  137. tui_data_window::first_reg_element_no_inline (int line_no) const
  138. {
  139. if (line_no * m_regs_column_count <= m_regs_content.size ())
  140. return ((line_no + 1) * m_regs_column_count) - m_regs_column_count;
  141. else
  142. return (-1);
  143. }
  144. /* Show the registers of the given group in the data window
  145. and refresh the window. */
  146. void
  147. tui_data_window::show_registers (const reggroup *group)
  148. {
  149. if (group == 0)
  150. group = general_reggroup;
  151. if (target_has_registers () && target_has_stack () && target_has_memory ())
  152. {
  153. show_register_group (group, get_selected_frame (NULL),
  154. group == m_current_group);
  155. /* Clear all notation of changed values. */
  156. for (auto &&data_item_win : m_regs_content)
  157. data_item_win.highlight = false;
  158. m_current_group = group;
  159. }
  160. else
  161. {
  162. m_current_group = 0;
  163. m_regs_content.clear ();
  164. }
  165. rerender ();
  166. }
  167. /* Set the data window to display the registers of the register group
  168. using the given frame. Values are refreshed only when
  169. refresh_values_only is true. */
  170. void
  171. tui_data_window::show_register_group (const reggroup *group,
  172. struct frame_info *frame,
  173. bool refresh_values_only)
  174. {
  175. struct gdbarch *gdbarch = get_frame_arch (frame);
  176. int nr_regs;
  177. int regnum, pos;
  178. /* Make a new title showing which group we display. */
  179. title = string_printf ("Register group: %s", group->name ());
  180. /* See how many registers must be displayed. */
  181. nr_regs = 0;
  182. for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
  183. {
  184. const char *name;
  185. /* Must be in the group. */
  186. if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
  187. continue;
  188. /* If the register name is empty, it is undefined for this
  189. processor, so don't display anything. */
  190. name = gdbarch_register_name (gdbarch, regnum);
  191. if (name == 0 || *name == '\0')
  192. continue;
  193. nr_regs++;
  194. }
  195. m_regs_content.resize (nr_regs);
  196. /* Now set the register names and values. */
  197. pos = 0;
  198. for (regnum = 0; regnum < gdbarch_num_cooked_regs (gdbarch); regnum++)
  199. {
  200. struct tui_data_item_window *data_item_win;
  201. const char *name;
  202. /* Must be in the group. */
  203. if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
  204. continue;
  205. /* If the register name is empty, it is undefined for this
  206. processor, so don't display anything. */
  207. name = gdbarch_register_name (gdbarch, regnum);
  208. if (name == 0 || *name == '\0')
  209. continue;
  210. data_item_win = &m_regs_content[pos];
  211. if (!refresh_values_only)
  212. {
  213. data_item_win->regno = regnum;
  214. data_item_win->highlight = false;
  215. }
  216. tui_get_register (frame, data_item_win, regnum, 0);
  217. pos++;
  218. }
  219. }
  220. /* See tui-regs.h. */
  221. void
  222. tui_data_window::display_registers_from (int start_element_no)
  223. {
  224. int max_len = 0;
  225. for (auto &&data_item_win : m_regs_content)
  226. {
  227. int len = data_item_win.content.size ();
  228. if (len > max_len)
  229. max_len = len;
  230. }
  231. m_item_width = max_len + 1;
  232. int i;
  233. /* Mark register windows above the visible area. */
  234. for (i = 0; i < start_element_no; i++)
  235. m_regs_content[i].y = 0;
  236. m_regs_column_count = (width - 2) / m_item_width;
  237. if (m_regs_column_count == 0)
  238. m_regs_column_count = 1;
  239. m_item_width = (width - 2) / m_regs_column_count;
  240. /* Now create each data "sub" window, and write the display into
  241. it. */
  242. int cur_y = 1;
  243. while (i < m_regs_content.size () && cur_y <= height - 2)
  244. {
  245. for (int j = 0;
  246. j < m_regs_column_count && i < m_regs_content.size ();
  247. j++)
  248. {
  249. /* Create the window if necessary. */
  250. m_regs_content[i].x = (m_item_width * j) + 1;
  251. m_regs_content[i].y = cur_y;
  252. m_regs_content[i].visible = true;
  253. m_regs_content[i].rerender (handle.get (), m_item_width);
  254. i++; /* Next register. */
  255. }
  256. cur_y++; /* Next row. */
  257. }
  258. /* Mark register windows below the visible area. */
  259. for (; i < m_regs_content.size (); i++)
  260. m_regs_content[i].y = 0;
  261. refresh_window ();
  262. }
  263. /* See tui-regs.h. */
  264. void
  265. tui_data_window::display_reg_element_at_line (int start_element_no,
  266. int start_line_no)
  267. {
  268. int element_no = start_element_no;
  269. if (start_element_no != 0 && start_line_no != 0)
  270. {
  271. int last_line_no, first_line_on_last_page;
  272. last_line_no = last_regs_line_no ();
  273. first_line_on_last_page = last_line_no - (height - 2);
  274. if (first_line_on_last_page < 0)
  275. first_line_on_last_page = 0;
  276. /* If the element_no causes us to scroll past the end of the
  277. registers, adjust what element to really start the
  278. display at. */
  279. if (start_line_no > first_line_on_last_page)
  280. element_no = first_reg_element_no_inline (first_line_on_last_page);
  281. }
  282. display_registers_from (element_no);
  283. }
  284. /* See tui-regs.h. */
  285. int
  286. tui_data_window::display_registers_from_line (int line_no)
  287. {
  288. int element_no;
  289. if (line_no < 0)
  290. line_no = 0;
  291. else
  292. {
  293. /* Make sure that we don't display off the end of the
  294. registers. */
  295. if (line_no >= last_regs_line_no ())
  296. {
  297. line_no = line_from_reg_element_no (m_regs_content.size () - 1);
  298. if (line_no < 0)
  299. line_no = 0;
  300. }
  301. }
  302. element_no = first_reg_element_no_inline (line_no);
  303. if (element_no < m_regs_content.size ())
  304. display_reg_element_at_line (element_no, line_no);
  305. else
  306. line_no = (-1);
  307. return line_no;
  308. }
  309. /* Answer the index first element displayed. If none are displayed,
  310. then return (-1). */
  311. int
  312. tui_data_window::first_data_item_displayed ()
  313. {
  314. for (int i = 0; i < m_regs_content.size (); i++)
  315. {
  316. if (m_regs_content[i].visible)
  317. return i;
  318. }
  319. return -1;
  320. }
  321. /* See tui-regs.h. */
  322. void
  323. tui_data_window::delete_data_content_windows ()
  324. {
  325. for (auto &win : m_regs_content)
  326. win.visible = false;
  327. }
  328. void
  329. tui_data_window::erase_data_content (const char *prompt)
  330. {
  331. werase (handle.get ());
  332. check_and_display_highlight_if_needed ();
  333. if (prompt != NULL)
  334. {
  335. int half_width = (width - 2) / 2;
  336. int x_pos;
  337. if (strlen (prompt) >= half_width)
  338. x_pos = 1;
  339. else
  340. x_pos = half_width - strlen (prompt);
  341. mvwaddstr (handle.get (), (height / 2), x_pos, (char *) prompt);
  342. }
  343. tui_wrefresh (handle.get ());
  344. }
  345. /* See tui-regs.h. */
  346. void
  347. tui_data_window::rerender ()
  348. {
  349. if (m_regs_content.empty ())
  350. erase_data_content (_("[ Register Values Unavailable ]"));
  351. else
  352. {
  353. erase_data_content (NULL);
  354. delete_data_content_windows ();
  355. display_registers_from (0);
  356. }
  357. }
  358. /* Scroll the data window vertically forward or backward. */
  359. void
  360. tui_data_window::do_scroll_vertical (int num_to_scroll)
  361. {
  362. int first_element_no;
  363. int first_line = (-1);
  364. first_element_no = first_data_item_displayed ();
  365. if (first_element_no < m_regs_content.size ())
  366. first_line = line_from_reg_element_no (first_element_no);
  367. else
  368. { /* Calculate the first line from the element number which is in
  369. the general data content. */
  370. }
  371. if (first_line >= 0)
  372. {
  373. first_line += num_to_scroll;
  374. erase_data_content (NULL);
  375. delete_data_content_windows ();
  376. display_registers_from_line (first_line);
  377. }
  378. }
  379. /* This function check all displayed registers for changes in values,
  380. given a particular frame. If the values have changed, they are
  381. updated with the new value and highlighted. */
  382. void
  383. tui_data_window::check_register_values (struct frame_info *frame)
  384. {
  385. if (m_regs_content.empty ())
  386. show_registers (m_current_group);
  387. else
  388. {
  389. for (auto &&data_item_win : m_regs_content)
  390. {
  391. int was_hilighted;
  392. was_hilighted = data_item_win.highlight;
  393. tui_get_register (frame, &data_item_win,
  394. data_item_win.regno,
  395. &data_item_win.highlight);
  396. /* Register windows whose y == 0 are outside the visible area. */
  397. if ((data_item_win.highlight || was_hilighted)
  398. && data_item_win.y > 0)
  399. data_item_win.rerender (handle.get (), m_item_width);
  400. }
  401. }
  402. tui_wrefresh (handle.get ());
  403. }
  404. /* Display a register in a window. If hilite is TRUE, then the value
  405. will be displayed in reverse video. */
  406. void
  407. tui_data_item_window::rerender (WINDOW *handle, int field_width)
  408. {
  409. if (highlight)
  410. /* We ignore the return value, casting it to void in order to avoid
  411. a compiler warning. The warning itself was introduced by a patch
  412. to ncurses 5.7 dated 2009-08-29, changing this macro to expand
  413. to code that causes the compiler to generate an unused-value
  414. warning. */
  415. (void) wstandout (handle);
  416. mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
  417. if (content.size () < field_width)
  418. waddstr (handle, n_spaces (field_width - content.size ()));
  419. if (highlight)
  420. /* We ignore the return value, casting it to void in order to avoid
  421. a compiler warning. The warning itself was introduced by a patch
  422. to ncurses 5.7 dated 2009-08-29, changing this macro to expand
  423. to code that causes the compiler to generate an unused-value
  424. warning. */
  425. (void) wstandend (handle);
  426. }
  427. /* Helper for "tui reg next", returns the next register group after
  428. CURRENT_GROUP in the register group list for GDBARCH, with wrap around
  429. behaviour.
  430. If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
  431. just been displayed and has no current group selected) or the currently
  432. selected register group can't be found (e.g. if the architecture has
  433. changed since the register window was last updated), then the first
  434. register group will be returned. */
  435. static const reggroup *
  436. tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
  437. {
  438. const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
  439. auto it = std::find (groups.begin (), groups.end (), current_group);
  440. if (it != groups.end ())
  441. it++;
  442. if (it == groups.end ())
  443. return groups.front ();
  444. return *it;
  445. }
  446. /* Helper for "tui reg prev", returns the register group previous to
  447. CURRENT_GROUP in the register group list for GDBARCH, with wrap around
  448. behaviour.
  449. If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
  450. just been displayed and has no current group selected) or the currently
  451. selected register group can't be found (e.g. if the architecture has
  452. changed since the register window was last updated), then the last
  453. register group will be returned. */
  454. static const reggroup *
  455. tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
  456. {
  457. const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
  458. auto it = std::find (groups.rbegin (), groups.rend (), current_group);
  459. if (it != groups.rend ())
  460. it++;
  461. if (it == groups.rend ())
  462. return groups.back ();
  463. return *it;
  464. }
  465. /* Implement the 'tui reg' command. Changes the register group displayed
  466. in the tui register window. Displays the tui register window if it is
  467. not already on display. */
  468. static void
  469. tui_reg_command (const char *args, int from_tty)
  470. {
  471. struct gdbarch *gdbarch = get_current_arch ();
  472. if (args != NULL)
  473. {
  474. size_t len = strlen (args);
  475. /* Make sure the curses mode is enabled. */
  476. tui_enable ();
  477. tui_suppress_output suppress;
  478. /* Make sure the register window is visible. If not, select an
  479. appropriate layout. We need to do this before trying to run the
  480. 'next' or 'prev' commands. */
  481. if (TUI_DATA_WIN == NULL || !TUI_DATA_WIN->is_visible ())
  482. tui_regs_layout ();
  483. const reggroup *match = nullptr;
  484. const reggroup *current_group = TUI_DATA_WIN->get_current_group ();
  485. if (strncmp (args, "next", len) == 0)
  486. match = tui_reg_next (current_group, gdbarch);
  487. else if (strncmp (args, "prev", len) == 0)
  488. match = tui_reg_prev (current_group, gdbarch);
  489. else
  490. {
  491. /* This loop matches on the initial part of a register group
  492. name. If this initial part in ARGS matches only one register
  493. group then the switch is made. */
  494. for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
  495. {
  496. if (strncmp (group->name (), args, len) == 0)
  497. {
  498. if (match != NULL)
  499. error (_("ambiguous register group name '%s'"), args);
  500. match = group;
  501. }
  502. }
  503. }
  504. if (match == NULL)
  505. error (_("unknown register group '%s'"), args);
  506. TUI_DATA_WIN->show_registers (match);
  507. }
  508. else
  509. {
  510. gdb_printf (_("\"tui reg\" must be followed by the name of "
  511. "either a register group,\nor one of 'next' "
  512. "or 'prev'. Known register groups are:\n"));
  513. bool first = true;
  514. for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
  515. {
  516. if (!first)
  517. gdb_printf (", ");
  518. first = false;
  519. gdb_printf ("%s", group->name ());
  520. }
  521. gdb_printf ("\n");
  522. }
  523. }
  524. /* Complete names of register groups, and add the special "prev" and "next"
  525. names. */
  526. static void
  527. tui_reggroup_completer (struct cmd_list_element *ignore,
  528. completion_tracker &tracker,
  529. const char *text, const char *word)
  530. {
  531. static const char * const extra[] = { "next", "prev", NULL };
  532. reggroup_completer (ignore, tracker, text, word);
  533. complete_on_enum (tracker, extra, text, word);
  534. }
  535. void _initialize_tui_regs ();
  536. void
  537. _initialize_tui_regs ()
  538. {
  539. struct cmd_list_element **tuicmd, *cmd;
  540. tuicmd = tui_get_cmd_list ();
  541. cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
  542. TUI command to control the register window.\n\
  543. Usage: tui reg NAME\n\
  544. NAME is the name of the register group to display"), tuicmd);
  545. set_cmd_completer (cmd, tui_reggroup_completer);
  546. }