# Copyright 2018-2023 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . load_lib gdb-python.exp # Test CLI output styling. standard_testfile # Compile the test executable. if {[build_executable "failed to build" $testfile $srcfile {debug macros}]} { return -1 } # The tests in this file are run multiple times with GDB's styles # disabled one at a time. This variable is the style that is # currently disabled. set currently_disabled_style "" # A wrapper around the 'style' function found in gdb-utils.exp, # filter out requests for the disabled style. proc limited_style { str style } { global currently_disabled_style if { $style != $currently_disabled_style } { return [style $str $style] } return $str } # A wrapper around 'clean_restart' from gdb.exp, this performs the # normal clean_restart, but then disables the currently disabled # style. proc clean_restart_and_disable { prefix args } { global currently_disabled_style with_test_prefix "$prefix" { eval "clean_restart $args" if { $currently_disabled_style != "" } { set st $currently_disabled_style gdb_test_no_output "set style $st background none" gdb_test_no_output "set style $st foreground none" gdb_test_no_output "set style $st intensity normal" } } } # The core of this test script. Run some tests of different aspects # of GDB's styling. # # Within this proc always use LIMITED_STYLE instead of STYLE, and # CLEAN_RESTART_AND_DISABLE instead of CLEAN_RESTART, this ensures # that the test operates as expected as styles are disabled. proc run_style_tests { } { global testfile srcfile hex binfile global currently_disabled_style decimal hex save_vars { env(TERM) } { # We need an ANSI-capable terminal to get the output. setenv TERM ansi # Restart GDB with the correct TERM variable setting, this # means that GDB will enable styling. clean_restart_and_disable "restart 1" ${binfile} set readnow [readnow] if {![runto_main]} { return } # Check that the source highlighter has not stripped away the # leading newlines. set main_line [gdb_get_line_number "break here"] gdb_test "list $main_line,$main_line" "return.*some_called_function.*" gdb_test_no_output "set style enabled off" set argv "" gdb_test_multiple "frame" "frame without styling" { -re -wrap "main \\(argc=.*, (argv=$hex)\\).*style\\.c:\[0-9\].*" { set argv $expect_out(1,string) pass $gdb_test_name } } gdb_test_no_output "set style enabled on" set main_expr [limited_style main function] set base_file_expr [limited_style ".*style\\.c" file] set file_expr "$base_file_expr:\[0-9\]+" set arg_expr [limited_style "arg." variable] gdb_test "frame" \ [multi_line \ "#0\\s+$main_expr\\s+\\($arg_expr=$decimal,\\s+$arg_expr=$hex\\)\\s+at\\s+$file_expr" \ "\[0-9\]+\\s+.*return.* break here .*"] gdb_test "info breakpoints" "$main_expr at $file_expr.*" gdb_test_no_output "set style sources off" gdb_test "frame" \ "\r\n\[^\033\]*break here.*" \ "frame without sources styling" gdb_test_no_output "set style sources on" gdb_test "break -q main" "file $base_file_expr.*" gdb_test "print &main" " = .* [limited_style $hex address] <$main_expr>" # Regression test for a bug where line-wrapping would occur at # the wrong spot with styling. There were different bugs at # different widths, so try two. foreach width {20 30} { set argv_len [string length $argv] if { $argv_len == 0 } { continue } # There was also a bug where the styling could be wrong in # the line listing; this is why the words from the source # code are spelled out in the final result line of the # test. set re1_styled \ [multi_line \ "#0\\s+$main_expr\\s+\\($arg_expr=$decimal,\\s+" \ "\\s+$arg_expr=$hex\\)" \ "\\s+at\\s+$file_expr" \ "\[0-9\]+\\s+.*return.* break here .*"] set re2_styled \ [multi_line \ "#0\\s+$main_expr\\s+\\($arg_expr=.*" \ "\\s+$arg_expr=$hex\\)\\s+at\\s+$file_expr" \ "\[0-9\]+\\s+.*return.* break here .*"] # The length of the line containing argv containing: # - 4 leading spaces # - argv string # - closing parenthesis set line_len [expr 4 + $argv_len + 1] if { $line_len > $width } { # At on the next line. set re_styled $re1_styled } else { # At on the same line as argv. set re_styled $re2_styled } # Override width for the duration of the command, letting # GDB reset back to 0. Doing this in the loop rather than # after, avoids trying to do "set width 30" while width is # 20, which causes horizontal scrolling in the case that # the fallback stub-termcap.c is used: # ^M} metadata]\\}" gdb_test "show logging file" \ "The current logfile is \"[limited_style .*? file]\"\\..*" # Check warnings are styled by setting a rubbish data # directory. gdb_test "set data-directory Makefile" \ "warning: [limited_style .*? file] is not a directory\\..*" gdb_test "show data-directory" \ "GDB's data directory is \"[limited_style .*? file]\"\\..*" # Check that deprecation styles command names. gdb_test_no_output "maintenance deprecate p \"new_p\"" \ "maintenance deprecate p \"new_p\" /1/" gdb_test "p 5" \ "Warning: '[limited_style p title]', an alias for the command '[limited_style print title]', is deprecated.*Use '[limited_style new_p title]'.*" \ "p deprecated warning, with replacement" # Check that the version string is styled in the output of 'show # version', and that this styling can be disabled. set vers [style "GNU gdb.*" version] set url [limited_style "http:.*html" file] gdb_test "show version" "${vers}.*<$url>.*" \ "'show version' is styled" } } # Check that disassembler styling can be disabled. The function that # we are disassembling has some minimal styling applied even if the # Python pygments module is not available, so, when we disable # disassembler styling, we should always see a change in output. proc test_disable_disassembler_styling { } { save_vars { env(TERM) } { # We need an ANSI-capable terminal to get the output. setenv TERM ansi # Restart GDB with the correct TERM variable setting, this # means that GDB will enable styling. clean_restart_and_disable "restart 3" $::binfile set styled_hex [limited_style $::hex address] set main [limited_style main function] foreach_with_prefix libopcodes { on off } { set command_failed false gdb_test_multiple "maint set libopcodes-styling enabled ${libopcodes}" "" { -re "^maint set libopcodes-styling enabled ${libopcodes}\r\n" { exp_continue } -re "Use of libopcodes styling not supported on architecture \[^\r\n\]+\r\n" { set command_failed true exp_continue } -re "^$::gdb_prompt $" { gdb_assert { !$command_failed || [string equal $libopcodes "on"] } \ $gdb_test_name } } if { $libopcodes == "on" && $command_failed } { # We tried to turn on libopcodes disassembler styling, # but this is not supported on this architecture. continue } foreach_with_prefix disasm_styling { on off } { gdb_test_no_output "set style disassembler enabled ${disasm_styling}" if { $libopcodes == "off" && $disasm_styling == "on" \ && !$::python_disassembly_styling} { # We have libopcodes based styling off, but # disassembler styling turned on. We're expecting # Python Pygments to be used to add styling. # # However, if we get here, then we don't have the # Pygments module, so skip this test. continue } set saw_header_line false set saw_styled_output_line false set saw_unstyled_output_line false gdb_test_multiple "disassemble main" "" { -re "disassemble main\r\n" { exp_continue } -re "^Dump of assembler code for function $main:" { set saw_header_line true exp_continue } -re "^\\s+${styled_hex}\\s+<\[^>\]+>:\\s+\[^\r\n\033\]+\r\n" { set saw_unstyled_output_line true exp_continue } -re "^\\s+${styled_hex}\\s+<\[^>\]+>:\\s+\[^\r\n\]+\033\[^\r\n\]+\r\n" { set saw_styled_output_line true exp_continue } -re "^End of assembler dump\\.\r\n" { exp_continue } -re "^$::gdb_prompt $" { gdb_assert { $saw_header_line } if { $disasm_styling } { gdb_assert { $saw_styled_output_line } gdb_assert { !$saw_unstyled_output_line } } else { gdb_assert { !$saw_styled_output_line } gdb_assert { $saw_unstyled_output_line } } } } } } } } # Disassemble a single isntruction at the start of main, then strip # off the address and symbol information, returning just the # disassembled instruction part. proc get_single_disassembled_insn {} { set disasm_line [capture_command_output "x/1i *main" ""] regexp "^\[^:\]+:\\s*(.*)$" $disasm_line whole_match insn return $insn } # Check that, if the user is using Python Pygments for disassembler # styling, then the styling correctly switches off when an error is # detected in the Python code. proc test_disassembler_error_handling { } { # This test requires the Python Pygments module to be installed # and used by GDB. if { !$::python_disassembly_styling } { return } save_vars { env(TERM) } { # We need an ANSI-capable terminal to get the output. setenv TERM ansi # Restart GDB with the correct TERM variable setting, this # means that GDB will enable styling. clean_restart_and_disable "restart 4" $::binfile # Disable use of libopcodes for styling. As this function is # only called when Python Pygments module is available, we # should now be using that module to style the disassembler # output. gdb_test_no_output "maint set libopcodes-styling enabled off" # Disassemble a single instruction and ensure that the output # has styling markers in it. set insn_before [get_single_disassembled_insn] gdb_assert { [regexp "\033" $insn_before] } \ "have style markers when Pygments is working fine" # Now replace the standard function that colorizes the # disassembler output, with a new function that always returns # None, this should cause GDB to stop using the Pygments # module for disassembler styling. gdb_py_test_silent_cmd \ [multi_line_input \ "python" \ "def replacement_colorize_disasm(content,gdbarch):" \ " return None" \ "gdb.styling.colorize_disasm = replacement_colorize_disasm" \ "end"] \ "setup replacement colorize_disasm function" \ true set insn_after [get_single_disassembled_insn] gdb_assert { ![regexp "\033" $insn_after] } \ "have no style markers when Pygments is broken" } } # A separate test from the above as the styled text this checks can't # currently be disabled (the text is printed too early in GDB's # startup process). proc test_startup_version_string { } { gdb_exit save_vars { ::INTERNAL_GDBFLAGS } { set ::INTERNAL_GDBFLAGS [string map {"-q" ""} $::INTERNAL_GDBFLAGS] gdb_spawn } # Deliberate use of base STYLE proc here as the style of the # startup version string can't (currently) be controlled. set vers [style "GNU gdb.*" version] gdb_test "" "${vers}.*" "version is styled at startup" } # Check to see if the Python styling of disassembler output is # expected or not, this styling requires Python support in GDB, and # the Python pygments module to be available. clean_restart ${binfile} if {[allow_python_tests] && [gdb_py_module_available "pygments"]} { set python_disassembly_styling true } else { set python_disassembly_styling false } # Run tests with all styles in their default state. with_test_prefix "all styles enabled" { run_style_tests } # Now, for each style in turn. Disable that style only and run the # test again. Things in that style should NOT now be styled. foreach style { title file function highlight variable \ address metadata } { set currently_disabled_style $style with_test_prefix "disable style $style" { run_style_tests } } # Check that the disassembler styling can be disabled. test_disable_disassembler_styling # Check that GDB handles an error in the Python Pygments disassembly # styling code. test_disassembler_error_handling # Finally, check the styling of the version string during startup. test_startup_version_string