arm, objdump: print obsolote warning when 26-bit set in instructions
[binutils-gdb.git] / gdb / tui / tui-regs.c
blob38ddd2336fe0a9409628691413399bddf9addd05
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 "frame.h"
26 #include "regcache.h"
27 #include "inferior.h"
28 #include "target.h"
29 #include "tui/tui-layout.h"
30 #include "tui/tui-win.h"
31 #include "tui/tui-wingeneral.h"
32 #include "tui/tui-regs.h"
33 #include "reggroups.h"
34 #include "completer.h"
36 #include "gdb_curses.h"
38 /* A subclass of string_file that expands tab characters. */
39 class tab_expansion_file : public string_file
41 public:
43 tab_expansion_file () = default;
45 void write (const char *buf, long length_buf) override;
47 private:
49 int m_column = 0;
52 void
53 tab_expansion_file::write (const char *buf, long length_buf)
55 for (long i = 0; i < length_buf; ++i)
57 if (buf[i] == '\t')
61 string_file::write (" ", 1);
62 ++m_column;
64 while ((m_column % 8) != 0);
66 else
68 string_file::write (&buf[i], 1);
69 if (buf[i] == '\n')
70 m_column = 0;
71 else
72 ++m_column;
77 /* Get the register from the frame and return a printable
78 representation of it. */
80 static std::string
81 tui_register_format (const frame_info_ptr &frame, int regnum)
83 struct gdbarch *gdbarch = get_frame_arch (frame);
85 /* Expand tabs into spaces, since ncurses on MS-Windows doesn't. */
86 tab_expansion_file stream;
87 gdbarch_print_registers_info (gdbarch, &stream, frame, regnum, 1);
89 /* Remove the possible \n. */
90 std::string str = stream.release ();
91 if (!str.empty () && str.back () == '\n')
92 str.pop_back ();
94 return str;
97 /* Compute the register value from the given frame and format it for
98 the display. Update 'content' and set 'm_highlight' if the
99 contents changed. */
100 void
101 tui_register_info::update (const frame_info_ptr &frame)
103 std::string new_content = tui_register_format (frame, m_regno);
104 m_highlight = content != new_content;
105 content = std::move (new_content);
108 /* See tui-regs.h. */
111 tui_data_window::last_regs_line_no () const
113 int num_lines = m_regs_content.size () / m_regs_column_count;
114 if (m_regs_content.size () % m_regs_column_count)
115 num_lines++;
116 return num_lines;
119 /* See tui-regs.h. */
122 tui_data_window::line_from_reg_element_no (int element_no) const
124 if (element_no < m_regs_content.size ())
126 int i, line = (-1);
128 i = 1;
129 while (line == (-1))
131 if (element_no < m_regs_column_count * i)
132 line = i - 1;
133 else
134 i++;
137 return line;
139 else
140 return (-1);
143 /* See tui-regs.h. */
146 tui_data_window::first_reg_element_no_inline (int line_no) const
148 if (line_no * m_regs_column_count <= m_regs_content.size ())
149 return ((line_no + 1) * m_regs_column_count) - m_regs_column_count;
150 else
151 return (-1);
154 /* See tui-regs.h. */
156 void
157 tui_data_window::set_register_group (const reggroup *group)
159 update_register_data (group);
160 rerender ();
163 /* Set the data window to display the registers of the register group
164 using the given frame. */
166 void
167 tui_data_window::update_register_data (const reggroup *group)
169 if (!target_has_registers ()
170 || !target_has_stack ()
171 || !target_has_memory ())
173 set_title (_("Registers"));
174 m_current_group = nullptr;
175 m_gdbarch = nullptr;
176 m_regs_content.clear ();
177 return;
180 if (group == nullptr)
181 group = general_reggroup;
183 frame_info_ptr frame = get_selected_frame (nullptr);
184 struct gdbarch *gdbarch = get_frame_arch (frame);
186 if (m_current_group == group && m_gdbarch == gdbarch)
188 /* Nothing to do here. */
189 return;
192 m_current_group = group;
193 m_gdbarch = gdbarch;
195 /* Make a new title showing which group we display. */
196 this->set_title (string_printf ("Register group: %s", group->name ()));
198 /* Create the registers. */
199 m_regs_content.clear ();
201 for (int regnum = 0;
202 regnum < gdbarch_num_cooked_regs (gdbarch);
203 regnum++)
205 /* Must be in the group. */
206 if (!gdbarch_register_reggroup_p (gdbarch, regnum, group))
207 continue;
209 /* If the register name is empty, it is undefined for this
210 processor, so don't display anything. */
211 const char *name = gdbarch_register_name (gdbarch, regnum);
212 if (*name == '\0')
213 continue;
215 m_regs_content.emplace_back (regnum, frame);
219 /* See tui-regs.h. */
221 void
222 tui_data_window::display_registers_from (int start_element_no)
224 werase (handle.get ());
225 check_and_display_highlight_if_needed ();
227 /* In case the regs window is not boxed, we'll write the last char in the
228 last line here, causing a scroll, so prevent that. */
229 scrollok (handle.get (), FALSE);
231 int max_len = 0;
232 for (auto &&data_item_win : m_regs_content)
234 int len = data_item_win.content.size ();
236 if (len > max_len)
237 max_len = len;
239 m_item_width = max_len + 1;
241 int i;
242 /* Mark register windows above the visible area. */
243 for (i = 0; i < start_element_no; i++)
244 m_regs_content[i].y = 0;
246 m_regs_column_count = (width - box_size ()) / m_item_width;
247 if (m_regs_column_count == 0)
248 m_regs_column_count = 1;
249 m_item_width = (width - box_size ()) / m_regs_column_count;
251 /* Now create each data "sub" window, and write the display into
252 it. */
253 int cur_y = box_width ();
254 while (i < m_regs_content.size () && cur_y <= height - box_size ())
256 for (int j = 0;
257 j < m_regs_column_count && i < m_regs_content.size ();
258 j++)
260 /* Create the window if necessary. */
261 m_regs_content[i].x = box_width () + (m_item_width * j);
262 m_regs_content[i].y = cur_y;
263 m_regs_content[i].rerender (handle.get (), m_item_width);
264 i++; /* Next register. */
266 cur_y++; /* Next row. */
269 /* Mark register windows below the visible area. */
270 for (; i < m_regs_content.size (); i++)
271 m_regs_content[i].y = 0;
274 /* See tui-regs.h. */
276 void
277 tui_data_window::display_reg_element_at_line (int start_element_no,
278 int start_line_no)
280 int element_no = start_element_no;
282 if (start_element_no != 0 && start_line_no != 0)
284 int last_line_no, first_line_on_last_page;
286 last_line_no = last_regs_line_no ();
287 first_line_on_last_page = last_line_no - (height - box_size ());
288 if (first_line_on_last_page < 0)
289 first_line_on_last_page = 0;
291 /* If the element_no causes us to scroll past the end of the
292 registers, adjust what element to really start the
293 display at. */
294 if (start_line_no > first_line_on_last_page)
295 element_no = first_reg_element_no_inline (first_line_on_last_page);
297 display_registers_from (element_no);
300 /* See tui-regs.h. */
303 tui_data_window::display_registers_from_line (int line_no)
305 int element_no;
307 if (line_no < 0)
308 line_no = 0;
309 else
311 /* Make sure that we don't display off the end of the
312 registers. */
313 if (line_no >= last_regs_line_no ())
315 line_no = line_from_reg_element_no (m_regs_content.size () - 1);
316 if (line_no < 0)
317 line_no = 0;
321 element_no = first_reg_element_no_inline (line_no);
322 if (element_no < m_regs_content.size ())
323 display_reg_element_at_line (element_no, line_no);
324 else
325 line_no = (-1);
327 return line_no;
331 /* Answer the index first element displayed. If none are displayed,
332 then return (-1). */
334 tui_data_window::first_data_item_displayed ()
336 for (int i = 0; i < m_regs_content.size (); i++)
338 if (m_regs_content[i].visible ())
339 return i;
342 return -1;
345 void
346 tui_data_window::erase_data_content ()
348 center_string (_("[ Register Values Unavailable ]"));
351 /* See tui-regs.h. */
353 void
354 tui_data_window::rerender ()
356 if (m_regs_content.empty ())
357 erase_data_content ();
358 else
359 display_registers_from (0);
360 refresh_window ();
364 /* Scroll the data window vertically forward or backward. */
365 void
366 tui_data_window::do_scroll_vertical (int num_to_scroll)
368 int first_element_no;
369 int first_line = (-1);
371 first_element_no = first_data_item_displayed ();
372 if (first_element_no < m_regs_content.size ())
373 first_line = line_from_reg_element_no (first_element_no);
374 else
375 { /* Calculate the first line from the element number which is in
376 the general data content. */
379 if (first_line >= 0)
381 first_line += num_to_scroll;
382 display_registers_from_line (first_line);
383 refresh_window ();
387 /* This function check all displayed registers for changes in values,
388 given a particular frame. If the values have changed, they are
389 updated with the new value and highlighted. */
390 void
391 tui_data_window::check_register_values (const frame_info_ptr &frame)
393 /* If the frame architecture changed, we need to reset the register
394 group. */
395 if (frame == nullptr || get_frame_arch (frame) != m_gdbarch)
396 set_register_group (nullptr);
397 else
399 for (tui_register_info &data_item_win : m_regs_content)
401 bool was_hilighted = data_item_win.highlighted ();
403 data_item_win.update (frame);
405 if ((data_item_win.highlighted () || was_hilighted)
406 && data_item_win.visible ())
407 data_item_win.rerender (handle.get (), m_item_width);
409 refresh_window ();
413 /* Display a register in a window. */
414 void
415 tui_register_info::rerender (WINDOW *handle, int field_width)
417 if (m_highlight)
418 /* We ignore the return value, casting it to void in order to avoid
419 a compiler warning. The warning itself was introduced by a patch
420 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
421 to code that causes the compiler to generate an unused-value
422 warning. */
423 (void) wstandout (handle);
425 mvwaddnstr (handle, y, x, content.c_str (), field_width - 1);
426 if (content.size () < field_width)
427 waddstr (handle, n_spaces (field_width - content.size ()));
429 if (m_highlight)
430 /* We ignore the return value, casting it to void in order to avoid
431 a compiler warning. The warning itself was introduced by a patch
432 to ncurses 5.7 dated 2009-08-29, changing this macro to expand
433 to code that causes the compiler to generate an unused-value
434 warning. */
435 (void) wstandend (handle);
438 /* Helper for "tui reg next", returns the next register group after
439 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
440 behaviour.
442 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
443 just been displayed and has no current group selected) or the currently
444 selected register group can't be found (e.g. if the architecture has
445 changed since the register window was last updated), then the first
446 register group will be returned. */
448 static const reggroup *
449 tui_reg_next (const reggroup *current_group, struct gdbarch *gdbarch)
451 const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
452 auto it = std::find (groups.begin (), groups.end (), current_group);
453 if (it != groups.end ())
454 it++;
455 if (it == groups.end ())
456 return groups.front ();
457 return *it;
460 /* Helper for "tui reg prev", returns the register group previous to
461 CURRENT_GROUP in the register group list for GDBARCH, with wrap around
462 behaviour.
464 If CURRENT_GROUP is nullptr (e.g. if the tui register window has only
465 just been displayed and has no current group selected) or the currently
466 selected register group can't be found (e.g. if the architecture has
467 changed since the register window was last updated), then the last
468 register group will be returned. */
470 static const reggroup *
471 tui_reg_prev (const reggroup *current_group, struct gdbarch *gdbarch)
473 const std::vector<const reggroup *> &groups = gdbarch_reggroups (gdbarch);
474 auto it = std::find (groups.rbegin (), groups.rend (), current_group);
475 if (it != groups.rend ())
476 it++;
477 if (it == groups.rend ())
478 return groups.back ();
479 return *it;
482 /* Implement the 'tui reg' command. Changes the register group displayed
483 in the tui register window. Displays the tui register window if it is
484 not already on display. */
486 static void
487 tui_reg_command (const char *args, int from_tty)
489 struct gdbarch *gdbarch = get_current_arch ();
491 if (args != NULL)
493 size_t len = strlen (args);
495 tui_batch_rendering suppress;
497 /* Make sure the curses mode is enabled. */
498 tui_enable ();
500 /* Make sure the register window is visible. If not, select an
501 appropriate layout. We need to do this before trying to run the
502 'next' or 'prev' commands. */
503 if (tui_data_win () == nullptr || !tui_data_win ()->is_visible ())
504 tui_regs_layout ();
506 const reggroup *match = nullptr;
507 const reggroup *current_group = tui_data_win ()->get_current_group ();
508 if (strncmp (args, "next", len) == 0)
509 match = tui_reg_next (current_group, gdbarch);
510 else if (strncmp (args, "prev", len) == 0)
511 match = tui_reg_prev (current_group, gdbarch);
512 else
514 /* This loop matches on the initial part of a register group
515 name. If this initial part in ARGS matches only one register
516 group then the switch is made. */
517 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
519 if (strncmp (group->name (), args, len) == 0)
521 if (match != NULL)
522 error (_("ambiguous register group name '%s'"), args);
523 match = group;
528 if (match == NULL)
529 error (_("unknown register group '%s'"), args);
531 tui_data_win ()->set_register_group (match);
533 else
535 gdb_printf (_("\"tui reg\" must be followed by the name of "
536 "either a register group,\nor one of 'next' "
537 "or 'prev'. Known register groups are:\n"));
539 bool first = true;
540 for (const struct reggroup *group : gdbarch_reggroups (gdbarch))
542 if (!first)
543 gdb_printf (", ");
544 first = false;
545 gdb_printf ("%s", group->name ());
548 gdb_printf ("\n");
552 /* Complete names of register groups, and add the special "prev" and "next"
553 names. */
555 static void
556 tui_reggroup_completer (struct cmd_list_element *ignore,
557 completion_tracker &tracker,
558 const char *text, const char *word)
560 static const char * const extra[] = { "next", "prev", NULL };
562 reggroup_completer (ignore, tracker, text, word);
564 complete_on_enum (tracker, extra, text, word);
567 void _initialize_tui_regs ();
568 void
569 _initialize_tui_regs ()
571 struct cmd_list_element **tuicmd, *cmd;
573 tuicmd = tui_get_cmd_list ();
575 cmd = add_cmd ("reg", class_tui, tui_reg_command, _("\
576 TUI command to control the register window.\n\
577 Usage: tui reg NAME\n\
578 NAME is the name of the register group to display"), tuicmd);
579 set_cmd_completer (cmd, tui_reggroup_completer);