More updated translations
[binutils-gdb.git] / gdb / tui / tui-regs.c
blob5158c0662ea761a36e9f72f3d70bc51c941b02ce
1 /* TUI display registers in window.
3 Copyright (C) 1998-2024 Free Software Foundation, Inc.
5 Contributed by Hewlett-Packard Company.
7 This file is part of GDB.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>. */
22 #include "arch-utils.h"
23 #include "tui/tui.h"
24 #include "symtab.h"
25 #include "cli/cli-style.h"
26 #include "frame.h"
27 #include "regcache.h"
28 #include "inferior.h"
29 #include "target.h"
30 #include "tui/tui-layout.h"
31 #include "tui/tui-win.h"
32 #include "tui/tui-wingeneral.h"
33 #include "tui/tui-regs.h"
34 #include "reggroups.h"
35 #include "completer.h"
37 #include "gdb_curses.h"
39 /* A subclass of string_file that expands tab characters. */
40 class tab_expansion_file : public string_file
42 public:
44 tab_expansion_file () = default;
46 void write (const char *buf, long length_buf) override;
48 private:
50 int m_column = 0;
53 void
54 tab_expansion_file::write (const char *buf, long length_buf)
56 for (long i = 0; i < length_buf; ++i)
58 if (buf[i] == '\t')
62 string_file::write (" ", 1);
63 ++m_column;
65 while ((m_column % 8) != 0);
67 else
69 string_file::write (&buf[i], 1);
70 if (buf[i] == '\n')
71 m_column = 0;
72 else
73 ++m_column;
78 /* Get the register from the frame and return a printable
79 representation of it. */
81 static std::string
82 tui_register_format (const frame_info_ptr &frame, int regnum)
84 struct gdbarch *gdbarch = get_frame_arch (frame);
86 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
87 tab_expansion_file stream;
88 gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
90 /* Remove the possible \n. */
91 std::string str = stream.release ();
92 if (!str.empty () && str.back () == '\n')
93 str.pop_back ();
95 return str;
98 /* Compute the register value from the given frame and format it for
99 the display. Update 'content' and set 'm_highlight' if the
100 contents changed. */
101 void
102 tui_register_info::update (const frame_info_ptr &frame)
104 std::string new_content = tui_register_format (frame, m_regno);
105 m_highlight = content != new_content;
106 content = std::move (new_content);
109 /* See tui-regs.h. */
112 tui_data_window::last_regs_line_no () const
114 int num_lines = m_regs_content.size () / m_regs_column_count;
115 if (m_regs_content.size () % m_regs_column_count)
116 num_lines++;
117 return num_lines;
120 /* See tui-regs.h. */
123 tui_data_window::line_from_reg_element_no (int element_no) const
125 if (element_no < m_regs_content.size ())
127 int i, line = (-1);
129 i = 1;
130 while (line == (-1))
132 if (element_no < m_regs_column_count * i)
133 line = i - 1;
134 else
135 i++;
138 return line;
140 else
141 return (-1);
144 /* See tui-regs.h. */
147 tui_data_window::first_reg_element_no_inline (int line_no) const
149 if (line_no * m_regs_column_count <= m_regs_content.size ())
150 return ((line_no + 1) * m_regs_column_count) - m_regs_column_count;
151 else
152 return (-1);
155 /* See tui-regs.h. */
157 void
158 tui_data_window::set_register_group (const reggroup *group)
160 update_register_data (group);
161 rerender ();
164 /* Set the data window to display the registers of the register group
165 using the given frame. */
167 void
168 tui_data_window::update_register_data (const reggroup *group)
170 if (!target_has_registers ()
171 || !target_has_stack ()
172 || !target_has_memory ())
174 set_title (_("Registers"));
175 m_current_group = nullptr;
176 m_gdbarch = nullptr;
177 m_regs_content.clear ();
178 return;
181 if (group == nullptr)
182 group = general_reggroup;
184 frame_info_ptr frame = get_selected_frame (nullptr);
185 struct gdbarch *gdbarch = get_frame_arch (frame);
187 if (m_current_group == group && m_gdbarch == gdbarch)
189 /* Nothing to do here. */
190 return;
193 m_current_group = group;
194 m_gdbarch = gdbarch;
196 /* Make a new title showing which group we display. */
197 this->set_title (string_printf ("Register group: %s", group->name ()));
199 /* Create the registers. */
200 m_regs_content.clear ();
202 for (int regnum = 0;
203 regnum < gdbarch_num_cooked_regs (gdbarch);
204 regnum++)
206 /* Must be in the group. */
207 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
208 continue;
210 /* If the register name is empty, it is undefined for this
211 processor, so don't display anything. */
212 const char *name = gdbarch_register_name (gdbarch, regnum);
213 if (*name == '\0')
214 continue;
216 m_regs_content.emplace_back (regnum, frame);
220 /* See tui-regs.h. */
222 void
223 tui_data_window::display_registers_from (int start_element_no)
225 werase (handle.get ());
226 check_and_display_highlight_if_needed ();
228 /* In case the regs window is not boxed, we'll write the last char in the
229 last line here, causing a scroll, so prevent that. */
230 scrollok (handle.get (), FALSE);
232 int max_len = 0;
233 for (auto &&data_item_win : m_regs_content)
235 int len = data_item_win.content.size ();
237 if (len > max_len)
238 max_len = len;
240 m_item_width = max_len + 1;
242 int i;
243 /* Mark register windows above the visible area. */
244 for (i = 0; i < start_element_no; i++)
245 m_regs_content[i].y = 0;
247 m_regs_column_count = (width - box_size ()) / m_item_width;
248 if (m_regs_column_count == 0)
249 m_regs_column_count = 1;
250 m_item_width = (width - box_size ()) / m_regs_column_count;
252 /* Now create each data "sub" window, and write the display into
253 it. */
254 int cur_y = box_width ();
255 while (i < m_regs_content.size () && cur_y <= height - box_size ())
257 for (int j = 0;
258 j < m_regs_column_count && i < m_regs_content.size ();
259 j++)
261 /* Create the window if necessary. */
262 m_regs_content[i].x = box_width () + (m_item_width * j);
263 m_regs_content[i].y = cur_y;
264 m_regs_content[i].rerender (handle.get (), m_item_width);
265 i++; /* Next register. */
267 cur_y++; /* Next row. */
270 /* Mark register windows below the visible area. */
271 for (; i < m_regs_content.size (); i++)
272 m_regs_content[i].y = 0;
275 /* See tui-regs.h. */
277 void
278 tui_data_window::display_reg_element_at_line (int start_element_no,
279 int start_line_no)
281 int element_no = start_element_no;
283 if (start_element_no != 0 && start_line_no != 0)
285 int last_line_no, first_line_on_last_page;
287 last_line_no = last_regs_line_no ();
288 first_line_on_last_page = last_line_no - (height - box_size ());
289 if (first_line_on_last_page < 0)
290 first_line_on_last_page = 0;
292 /* If the element_no causes us to scroll past the end of the
293 registers, adjust what element to really start the
294 display at. */
295 if (start_line_no > first_line_on_last_page)
296 element_no = first_reg_element_no_inline (first_line_on_last_page);
298 display_registers_from (element_no);
301 /* See tui-regs.h. */
304 tui_data_window::display_registers_from_line (int line_no)
306 int element_no;
308 if (line_no < 0)
309 line_no = 0;
310 else
312 /* Make sure that we don't display off the end of the
313 registers. */
314 if (line_no >= last_regs_line_no ())
316 line_no = line_from_reg_element_no (m_regs_content.size () - 1);
317 if (line_no < 0)
318 line_no = 0;
322 element_no = first_reg_element_no_inline (line_no);
323 if (element_no < m_regs_content.size ())
324 display_reg_element_at_line (element_no, line_no);
325 else
326 line_no = (-1);
328 return line_no;
332 /* Answer the index first element displayed. If none are displayed,
333 then return (-1). */
335 tui_data_window::first_data_item_displayed ()
337 for (int i = 0; i < m_regs_content.size (); i++)
339 if (m_regs_content[i].visible ())
340 return i;
343 return -1;
346 void
347 tui_data_window::erase_data_content ()
349 center_string (_("[ Register Values Unavailable ]"));
352 /* See tui-regs.h. */
354 void
355 tui_data_window::rerender ()
357 if (m_regs_content.empty ())
358 erase_data_content ();
359 else
360 display_registers_from (0);
361 refresh_window ();
365 /* Scroll the data window vertically forward or backward. */
366 void
367 tui_data_window::do_scroll_vertical (int num_to_scroll)
369 int first_element_no;
370 int first_line = (-1);
372 first_element_no = first_data_item_displayed ();
373 if (first_element_no < m_regs_content.size ())
374 first_line = line_from_reg_element_no (first_element_no);
375 else
376 { /* Calculate the first line from the element number which is in
377 the general data content. */
380 if (first_line >= 0)
382 first_line += num_to_scroll;
383 display_registers_from_line (first_line);
384 refresh_window ();
388 /* This function check all displayed registers for changes in values,
389 given a particular frame. If the values have changed, they are
390 updated with the new value and highlighted. */
391 void
392 tui_data_window::check_register_values (const frame_info_ptr &frame)
394 /* If the frame architecture changed, we need to reset the register
395 group. */
396 if (frame == nullptr || get_frame_arch (frame) != m_gdbarch)
397 set_register_group (nullptr);
398 else
400 for (tui_register_info &data_item_win : m_regs_content)
402 bool was_hilighted = data_item_win.highlighted ();
404 data_item_win.update (frame);
406 if ((data_item_win.highlighted () || was_hilighted)
407 && data_item_win.visible ())
408 data_item_win.rerender (handle.get (), m_item_width);
410 refresh_window ();
414 /* Display a register in a window. */
415 void
416 tui_register_info::rerender (WINDOW *handle, int field_width)
418 if (m_highlight)
419 /* We ignore the return value, casting it to void in order to avoid
420 a compiler warning. The warning itself was introduced by a patch
421 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
422 to code that causes the compiler to generate an unused-value
423 warning. */
424 (void) wstandout (handle);
426 mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
427 if (content.size () < field_width)
428 waddstr (handle, n_spaces (field_width - content.size ()));
430 if (m_highlight)
431 /* We ignore the return value, casting it to void in order to avoid
432 a compiler warning. The warning itself was introduced by a patch
433 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
434 to code that causes the compiler to generate an unused-value
435 warning. */
436 (void) wstandend (handle);
439 /* Helper for "tui reg next", returns the next register group after
440 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
441 behavior.
443 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
444 just been displayed and has no current group selected) or the currently
445 selected register group can't be found (e.g. if the architecture has
446 changed since the register window was last updated), then the first
447 register group will be returned. */
449 static const reggroup *
450 tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
452 const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
453 auto it = std::find (groups.begin (), groups.end (), current_group);
454 if (it != groups.end ())
455 it++;
456 if (it == groups.end ())
457 return groups.front ();
458 return *it;
461 /* Helper for "tui reg prev", returns the register group previous to
462 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
463 behavior.
465 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
466 just been displayed and has no current group selected) or the currently
467 selected register group can't be found (e.g. if the architecture has
468 changed since the register window was last updated), then the last
469 register group will be returned. */
471 static const reggroup *
472 tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
474 const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
475 auto it = std::find (groups.rbegin (), groups.rend (), current_group);
476 if (it != groups.rend ())
477 it++;
478 if (it == groups.rend ())
479 return groups.back ();
480 return *it;
483 /* Implement the 'tui reg' command. Changes the register group displayed
484 in the tui register window. Displays the tui register window if it is
485 not already on display. */
487 static void
488 tui_reg_command (const char *args, int from_tty)
490 struct gdbarch *gdbarch = get_current_arch ();
492 if (args != NULL)
494 size_t len = strlen (args);
496 tui_batch_rendering suppress;
498 /* Make sure the curses mode is enabled. */
499 tui_enable ();
501 /* Make sure the register window is visible. If not, select an
502 appropriate layout. We need to do this before trying to run the
503 'next' or 'prev' commands. */
504 if (tui_data_win () == nullptr || !tui_data_win ()->is_visible ())
505 tui_regs_layout ();
507 const reggroup *match = nullptr;
508 const reggroup *current_group = tui_data_win ()->get_current_group ();
509 if (strncmp (args, "next", len) == 0)
510 match = tui_reg_next (current_group, gdbarch);
511 else if (strncmp (args, "prev", len) == 0)
512 match = tui_reg_prev (current_group, gdbarch);
513 else
515 /* This loop matches on the initial part of a register group
516 name. If this initial part in ARGS matches only one register
517 group then the switch is made. */
518 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
520 if (strncmp (group->name (), args, len) == 0)
522 if (match != NULL)
523 error (_("ambiguous register group name '%s'"), args);
524 match = group;
529 if (match == NULL)
530 error (_("unknown register group '%s'"), args);
532 tui_data_win ()->set_register_group (match);
534 else
536 gdb_printf (_("\"%ps\" must be followed by the name of "
537 "either a register group,\nor one of 'next' "
538 "or 'prev'. Known register groups are:\n"),
539 styled_string (command_style.style (), "tui reg"));
541 bool first = true;
542 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
544 if (!first)
545 gdb_printf (", ");
546 first = false;
547 gdb_printf ("%s", group->name ());
550 gdb_printf ("\n");
554 /* Complete names of register groups, and add the special "prev" and "next"
555 names. */
557 static void
558 tui_reggroup_completer (struct cmd_list_element *ignore,
559 completion_tracker &tracker,
560 const char *text, const char *word)
562 static const char * const extra[] = { "next", "prev", NULL };
564 reggroup_completer (ignore, tracker, text, word);
566 complete_on_enum (tracker, extra, text, word);
569 void _initialize_tui_regs ();
570 void
571 _initialize_tui_regs ()
573 struct cmd_list_element **tuicmd, *cmd;
575 tuicmd = tui_get_cmd_list ();
577 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
578 TUI command to control the register window.\n\
579 Usage: tui reg NAME\n\
580 NAME is the name of the register group to display"), tuicmd);
581 set_cmd_completer (cmd, tui_reggroup_completer);