From 1df2f9ef6cae23a08a50a3b2f33ce2664ce9ae9e Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Mon, 21 Oct 2019 11:21:14 -0600 Subject: [PATCH] Style disassembly in the TUI This patch changes the TUI disassembly window to style its contents. The styling should be identical to what is seen in the CLI. This involved a bit of rearrangement, so that the source and disassembly windows could share both the copy_source_line utility function, and the ability to react to changes in "set style enabled". This version introduces a new function to strip the styling from the address string when computing the length. As a byproduct, it also removes the unused "insn_size" computation from tui_disasm_window::set_contents. gdb/ChangeLog 2019-11-05 Tom Tromey * tui/tui-source.h (struct tui_source_window): Inline constructor. Remove destructor. : Move to superclass. * tui/tui-winsource.h (tui_copy_source_line): Declare. (struct tui_source_window_base): Move private members to end. : Move from tui_source_window. * tui/tui-winsource.c (tui_copy_source_line): Move from tui-source.c. Rename from copy_source_line. Add special handling for negative line number. (tui_source_window_base::style_changed): Move from tui_source_window. (tui_source_window_base): Register observer. (~tui_source_window_base): New. * tui/tui-source.c (copy_source_line): Move to tui-winsource.c; rename. (tui_source_window::set_contents): Use tui_copy_source_line. (tui_source_window::tui_source_window): Move to tui-source.h. (tui_source_window::~tui_source_window): Remove. (tui_source_window::style_changed): Move to superclass. * tui/tui-disasm.c (tui_disassemble): Create string file with styling, when possible. Add "addr_size" parameter. (tui_disasm_window::set_contents): Use tui_copy_source_line. Don't compute maximum size. (len_without_escapes): New function Change-Id: I8722635eeecbbb1633d943a65b856404c2d467b0 --- gdb/ChangeLog | 27 ++++++++++ gdb/tui/tui-disasm.c | 77 ++++++++++++++++++---------- gdb/tui/tui-source.c | 109 ++-------------------------------------- gdb/tui/tui-source.h | 11 ++-- gdb/tui/tui-winsource.c | 99 ++++++++++++++++++++++++++++++++++++ gdb/tui/tui-winsource.h | 24 +++++++-- 6 files changed, 205 insertions(+), 142 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0c05afeb13c..00d21fac1e7 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,30 @@ +2019-11-05 Tom Tromey + + * tui/tui-source.h (struct tui_source_window): Inline + constructor. Remove destructor. + : Move to superclass. + * tui/tui-winsource.h (tui_copy_source_line): Declare. + (struct tui_source_window_base): Move private members to end. + : Move from tui_source_window. + * tui/tui-winsource.c (tui_copy_source_line): Move from + tui-source.c. Rename from copy_source_line. Add special handling + for negative line number. + (tui_source_window_base::style_changed): Move from + tui_source_window. + (tui_source_window_base): Register observer. + (~tui_source_window_base): New. + * tui/tui-source.c (copy_source_line): Move to tui-winsource.c; + rename. + (tui_source_window::set_contents): Use tui_copy_source_line. + (tui_source_window::tui_source_window): Move to tui-source.h. + (tui_source_window::~tui_source_window): Remove. + (tui_source_window::style_changed): Move to superclass. + * tui/tui-disasm.c (tui_disassemble): Create string file with + styling, when possible. Add "addr_size" parameter. + (tui_disasm_window::set_contents): Use tui_copy_source_line. + Don't compute maximum size. + (len_without_escapes): New function + 2019-11-05 Tom Tromey * tui/tui-winsource.h (struct tui_source_element) : Now a diff --git a/gdb/tui/tui-disasm.c b/gdb/tui/tui-disasm.c index 91c9845f5dc..71783266391 100644 --- a/gdb/tui/tui-disasm.c +++ b/gdb/tui/tui-disasm.c @@ -39,6 +39,7 @@ #include "tui/tui-source.h" #include "progspace.h" #include "objfiles.h" +#include "cli/cli-style.h" #include "gdb_curses.h" @@ -49,15 +50,47 @@ struct tui_asm_line std::string insn; }; +/* Helper function to find the number of characters in STR, skipping + any ANSI escape sequences. */ +static size_t +len_without_escapes (const std::string &str) +{ + size_t len = 0; + const char *ptr = str.c_str (); + char c; + + while ((c = *ptr++) != '\0') + { + if (c == '\033') + { + ui_file_style style; + size_t n_read; + if (style.parse (ptr, &n_read)) + ptr += n_read; + else + { + /* Shouldn't happen, but just skip the ESC if it somehow + does. */ + ++ptr; + } + } + else + ++len; + } + return len; +} + /* Function to set the disassembly window's content. Disassemble count lines starting at pc. Return address of the count'th instruction after pc. */ static CORE_ADDR tui_disassemble (struct gdbarch *gdbarch, std::vector &asm_lines, - CORE_ADDR pc, int pos, int count) + CORE_ADDR pc, int pos, int count, + size_t *addr_size = nullptr) { - string_file gdb_dis_out; + bool term_out = source_styling && gdb_stdout->can_emit_style_escape (); + string_file gdb_dis_out (term_out); /* Now construct each line. */ for (int i = 0; i < count; ++i) @@ -68,6 +101,17 @@ tui_disassemble (struct gdbarch *gdbarch, gdb_dis_out.clear (); + if (addr_size != nullptr) + { + size_t new_size; + + if (term_out) + new_size = len_without_escapes (asm_lines[pos + i].addr_string); + else + new_size = asm_lines[pos + i].addr_string.size (); + *addr_size = std::max (*addr_size, new_size); + } + pc = pc + gdb_print_insn (gdbarch, pc, &gdb_dis_out, NULL); asm_lines[pos + i].insn = std::move (gdb_dis_out.string ()); @@ -164,8 +208,7 @@ tui_disasm_window::set_contents (struct gdbarch *arch, struct tui_locator_window *locator = tui_locator_win_info_ptr (); int tab_len = tui_tab_width; int insn_pos; - int addr_size, insn_size; - + gdb_assert (line_or_addr.loa == LOA_ADDRESS); CORE_ADDR pc = line_or_addr.u.addr; if (pc == 0) @@ -182,23 +225,8 @@ tui_disasm_window::set_contents (struct gdbarch *arch, /* Get temporary table that will hold all strings (addr & insn). */ std::vector asm_lines (max_lines); - - tui_disassemble (gdbarch, asm_lines, pc, 0, max_lines); - - /* Determine maximum address- and instruction lengths. */ - addr_size = 0; - insn_size = 0; - for (i = 0; i < max_lines; i++) - { - size_t len = asm_lines[i].addr_string.size (); - - if (len > addr_size) - addr_size = len; - - len = asm_lines[i].insn.size (); - if (len > insn_size) - insn_size = len; - } + size_t addr_size = 0; + tui_disassemble (gdbarch, asm_lines, pc, 0, max_lines, &addr_size); /* Align instructions to the same column. */ insn_pos = (1 + (addr_size / tab_len)) * tab_len; @@ -215,11 +243,8 @@ tui_disasm_window::set_contents (struct gdbarch *arch, - asm_lines[i].addr_string.size ()) + asm_lines[i].insn); - /* Now copy the line taking the offset into account. */ - if (line.size () > offset) - src->line = line.substr (offset, line_width); - else - src->line.clear (); + const char *ptr = line.c_str (); + src->line = tui_copy_source_line (&ptr, -1, offset, line_width); src->line_or_addr.loa = LOA_ADDRESS; src->line_or_addr.u.addr = asm_lines[i].addr; diff --git a/gdb/tui/tui-source.c b/gdb/tui/tui-source.c index f956645d898..915f9e36315 100644 --- a/gdb/tui/tui-source.c +++ b/gdb/tui/tui-source.c @@ -37,90 +37,6 @@ #include "tui/tui-source.h" #include "gdb_curses.h" -/* A helper function for tui_set_source_content that extracts some - source text from PTR. LINE_NO is the line number; FIRST_COL is the - first column to extract, and LINE_WIDTH is the number of characters - to display. Returns a string holding the desired text. */ - -static std::string -copy_source_line (const char **ptr, int line_no, int first_col, - int line_width) -{ - const char *lineptr = *ptr; - - /* Init the line with the line number. */ - std::string result = string_printf ("%-6d", line_no); - int len = result.size (); - len = len - ((len / tui_tab_width) * tui_tab_width); - result.append (len, ' '); - - int column = 0; - char c; - do - { - int skip_bytes; - - c = *lineptr; - if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes)) - { - /* We always have to preserve escapes. */ - result.append (lineptr, lineptr + skip_bytes); - lineptr += skip_bytes; - continue; - } - - ++lineptr; - ++column; - - auto process_tab = [&] () - { - int max_tab_len = tui_tab_width; - - --column; - for (int j = column % max_tab_len; - j < max_tab_len && column < first_col + line_width; - column++, j++) - if (column >= first_col) - result.push_back (' '); - }; - - /* We have to process all the text in order to pick up all the - escapes. */ - if (column <= first_col || column > first_col + line_width) - { - if (c == '\t') - process_tab (); - continue; - } - - if (c == '\n' || c == '\r' || c == '\0') - { - /* Nothing. */ - } - else if (c < 040 && c != '\t') - { - result.push_back ('^'); - result.push_back (c + 0100); - } - else if (c == 0177) - { - result.push_back ('^'); - result.push_back ('?'); - } - else if (c == '\t') - process_tab (); - else - result.push_back (c); - } - while (c != '\0' && c != '\n' && c != '\r'); - - if (c == '\r' && *lineptr == '\n') - ++lineptr; - *ptr = lineptr; - - return result; -} - /* Function to display source in the source window. */ enum tui_status tui_source_window::set_contents (struct gdbarch *arch, @@ -171,8 +87,9 @@ tui_source_window::set_contents (struct gdbarch *arch, std::string text; if (*iter != '\0') - text = copy_source_line (&iter, cur_line_no, horizontal_offset, - line_width); + text = tui_copy_source_line (&iter, cur_line_no, + horizontal_offset, + line_width); /* Set whether element is the execution point and whether there is a break point on it. */ @@ -249,26 +166,6 @@ tui_source_window::do_scroll_vertical (int num_to_scroll) } } -tui_source_window::tui_source_window () - : tui_source_window_base (SRC_WIN) -{ - gdb::observers::source_styling_changed.attach - (std::bind (&tui_source_window::style_changed, this), - m_observable); -} - -tui_source_window::~tui_source_window () -{ - gdb::observers::source_styling_changed.detach (m_observable); -} - -void -tui_source_window::style_changed () -{ - if (tui_active && is_visible ()) - refill (); -} - bool tui_source_window::location_matches_p (struct bp_location *loc, int line_no) { diff --git a/gdb/tui/tui-source.h b/gdb/tui/tui-source.h index 3ef737c56e9..a2b7754e7ee 100644 --- a/gdb/tui/tui-source.h +++ b/gdb/tui/tui-source.h @@ -31,8 +31,10 @@ struct symtab; struct tui_source_window : public tui_source_window_base { - tui_source_window (); - ~tui_source_window (); + tui_source_window () + : tui_source_window_base (SRC_WIN) + { + } DISABLE_COPY_AND_ASSIGN (tui_source_window); @@ -70,17 +72,12 @@ protected: private: - void style_changed (); - /* Answer whether a particular line number or address is displayed in the current source window. */ bool line_is_displayed (int line) const; /* It is the resolved form as returned by symtab_to_fullname. */ gdb::unique_xmalloc_ptr m_fullname; - - /* A token used to register and unregister an observer. */ - gdb::observers::token m_observable; }; #endif /* TUI_TUI_SOURCE_H */ diff --git a/gdb/tui/tui-winsource.c b/gdb/tui/tui-winsource.c index 5d0bcb47b11..3ca723c8b26 100644 --- a/gdb/tui/tui-winsource.c +++ b/gdb/tui/tui-winsource.c @@ -65,7 +65,98 @@ tui_display_main () } } +/* See tui-winsource.h. */ + +std::string +tui_copy_source_line (const char **ptr, int line_no, int first_col, + int line_width) +{ + const char *lineptr = *ptr; + + /* Init the line with the line number. */ + std::string result; + + if (line_no > 0) + { + result = string_printf ("%-6d", line_no); + int len = result.size (); + len = len - ((len / tui_tab_width) * tui_tab_width); + result.append (len, ' '); + } + + int column = 0; + char c; + do + { + int skip_bytes; + + c = *lineptr; + if (c == '\033' && skip_ansi_escape (lineptr, &skip_bytes)) + { + /* We always have to preserve escapes. */ + result.append (lineptr, lineptr + skip_bytes); + lineptr += skip_bytes; + continue; + } + + ++lineptr; + ++column; + + auto process_tab = [&] () + { + int max_tab_len = tui_tab_width; + + --column; + for (int j = column % max_tab_len; + j < max_tab_len && column < first_col + line_width; + column++, j++) + if (column >= first_col) + result.push_back (' '); + }; + + /* We have to process all the text in order to pick up all the + escapes. */ + if (column <= first_col || column > first_col + line_width) + { + if (c == '\t') + process_tab (); + continue; + } + + if (c == '\n' || c == '\r' || c == '\0') + { + /* Nothing. */ + } + else if (c < 040 && c != '\t') + { + result.push_back ('^'); + result.push_back (c + 0100); + } + else if (c == 0177) + { + result.push_back ('^'); + result.push_back ('?'); + } + else if (c == '\t') + process_tab (); + else + result.push_back (c); + } + while (c != '\0' && c != '\n' && c != '\r'); + + if (c == '\r' && *lineptr == '\n') + ++lineptr; + *ptr = lineptr; + return result; +} + +void +tui_source_window_base::style_changed () +{ + if (tui_active && is_visible ()) + refill (); +} /* Function to display source in the source window. This function initializes the horizontal scroll to 0. */ @@ -253,8 +344,16 @@ tui_source_window_base::tui_source_window_base (enum tui_win_type type) gdb_assert (type == SRC_WIN || type == DISASSEM_WIN); start_line_or_addr.loa = LOA_ADDRESS; start_line_or_addr.u.addr = 0; + + gdb::observers::source_styling_changed.attach + (std::bind (&tui_source_window::style_changed, this), + m_observable); } +tui_source_window_base::~tui_source_window_base () +{ + gdb::observers::source_styling_changed.detach (m_observable); +} /* See tui-data.h. */ diff --git a/gdb/tui/tui-winsource.h b/gdb/tui/tui-winsource.h index 185d3dd5e0a..7c3c626add1 100644 --- a/gdb/tui/tui-winsource.h +++ b/gdb/tui/tui-winsource.h @@ -74,11 +74,9 @@ struct tui_source_element struct tui_source_window_base : public tui_win_info { -private: - void show_source_content (); - protected: explicit tui_source_window_base (enum tui_win_type type); + ~tui_source_window_base (); DISABLE_COPY_AND_ASSIGN (tui_source_window_base); @@ -140,6 +138,16 @@ public: struct gdbarch *gdbarch = nullptr; std::vector content; + +private: + + void show_source_content (); + + /* Called when the user "set style enabled" setting is changed. */ + void style_changed (); + + /* A token used to register and unregister an observer. */ + gdb::observers::token m_observable; }; @@ -227,6 +235,16 @@ extern void tui_update_source_windows_with_addr (struct gdbarch *, CORE_ADDR); extern void tui_update_source_windows_with_line (struct symtab *, int); +/* Extract some source text from PTR. LINE_NO is the line number. If + it is positive, it is printed at the start of the line. FIRST_COL + is the first column to extract, and LINE_WIDTH is the number of + characters to display. Returns a string holding the desired text. + PTR is updated to point to the start of the next line. */ + +extern std::string tui_copy_source_line (const char **ptr, + int line_no, int first_col, + int line_width); + /* Constant definitions. */ #define SCROLL_THRESHOLD 2 /* Threshold for lazy scroll. */ -- 2.30.2