1# Copyright 2018-2024 Free Software Foundation, Inc.
2
3# This program is free software; you can redistribute it and/or modify
4# it under the terms of the GNU General Public License as published by
5# the Free Software Foundation; either version 3 of the License, or
6# (at your option) any later version.
7#
8# This program is distributed in the hope that it will be useful,
9# but WITHOUT ANY WARRANTY; without even the implied warranty of
10# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11# GNU General Public License for more details.
12#
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
16load_lib gdb-python.exp
17
18# Test CLI output styling.
19
20standard_testfile
21
22# Compile the test executable.
23if {[build_executable "failed to build" $testfile $srcfile {debug macros}]} {
24    return -1
25}
26
27# The tests in this file are run multiple times with GDB's styles
28# disabled one at a time.  This variable is the style that is
29# currently disabled.
30set currently_disabled_style ""
31
32# A wrapper around the 'style' function found in gdb-utils.exp,
33# filter out requests for the disabled style.
34proc limited_style { str style } {
35    global currently_disabled_style
36
37    if { $style != $currently_disabled_style } {
38	return [style $str $style]
39    }
40
41    return $str
42}
43
44# A wrapper around 'clean_restart' from gdb.exp, this performs the
45# normal clean_restart, but then disables the currently disabled
46# style.
47proc clean_restart_and_disable { prefix args } {
48    global currently_disabled_style
49
50    with_test_prefix "$prefix" {
51	eval "clean_restart $args"
52
53	if { $currently_disabled_style != "" } {
54	    set st $currently_disabled_style
55	    gdb_test_no_output "set style $st background none"
56	    gdb_test_no_output "set style $st foreground none"
57	    gdb_test_no_output "set style $st intensity normal"
58	}
59    }
60}
61
62# The core of this test script.  Run some tests of different aspects
63# of GDB's styling.
64#
65# Within this proc always use LIMITED_STYLE instead of STYLE, and
66# CLEAN_RESTART_AND_DISABLE instead of CLEAN_RESTART, this ensures
67# that the test operates as expected as styles are disabled.
68proc run_style_tests { } {
69    global testfile srcfile hex binfile
70    global currently_disabled_style decimal hex
71
72    with_ansi_styling_terminal {
73	# Restart GDB with the correct TERM variable setting, this
74	# means that GDB will enable styling.
75	clean_restart_and_disable "restart 1" ${binfile}
76
77	set readnow [readnow]
78
79	if {![runto_main]} {
80	    return
81	}
82
83	# Check that the source highlighter has not stripped away the
84	# leading newlines.
85	set main_line [gdb_get_line_number "break here"]
86	gdb_test "list $main_line,$main_line" "return.*some_called_function.*"
87
88	gdb_test_no_output "set style enabled off"
89
90	set argv ""
91	gdb_test_multiple "frame" "frame without styling" {
92	    -re -wrap "main \\(argc=.*, (argv=$hex.*)\\).*style\\.c:\[0-9\].*" {
93		set argv $expect_out(1,string)
94		pass $gdb_test_name
95	    }
96	}
97
98	gdb_test_no_output "set style enabled on"
99
100	set main_expr [limited_style main function]
101	set base_file_expr [limited_style ".*style\\.c" file]
102	set file_expr "$base_file_expr:\[0-9\]+"
103	set arg_expr [limited_style "arg." variable]
104
105	# On some embedded targets that don't fully support argc/argv,
106	# argv may print as "0x0" or as an address with a symbol name
107	# following, so use a regexp general enough to match that and
108	# do not make assumptions about how long the address string is.
109	gdb_test "frame" \
110	    [multi_line \
111		 "#0\\s+$main_expr\\s+\\($arg_expr=$decimal,\\s+$arg_expr=$hex.*\\)\\s+at\\s+$file_expr" \
112		 "\[0-9\]+\\s+.*return.* break here .*"]
113	gdb_test "info breakpoints" "$main_expr at $file_expr.*"
114
115	gdb_test_no_output "set style sources off"
116	gdb_test "frame" \
117	    "\r\n\[^\033\]*break here.*" \
118	    "frame without sources styling"
119	gdb_test_no_output "set style sources on"
120
121	gdb_test "break -q main" "file $base_file_expr.*"
122
123	gdb_test "print &main" " = .* [limited_style $hex address] <$main_expr>"
124
125	# Regression test for a bug where line-wrapping would occur at
126	# the wrong spot with styling.  There were different bugs at
127	# different widths, so try two.
128	foreach width {20 30} {
129	    set argv_len [string length $argv]
130	    if { $argv_len == 0 } {
131		continue
132	    }
133
134	    # There was also a bug where the styling could be wrong in
135	    # the line listing; this is why the words from the source
136	    # code are spelled out in the final result line of the
137	    # test.
138	    set re0_styled \
139		[multi_line \
140		     "#0\\s+$main_expr\\s+\\($arg_expr=$decimal,\\s+$arg_expr=$hex\\)" \
141		     "\\s+at\\s+$file_expr" \
142		     "\[0-9\]+\\s+.*return.* break here .*"]
143	    set re1_styled \
144		[multi_line \
145		     "#0\\s+$main_expr\\s+\\($arg_expr=$decimal,\\s+" \
146		     "\\s+$arg_expr=$hex.*\\)" \
147		     "\\s+at\\s+$file_expr" \
148		     "\[0-9\]+\\s+.*return.* break here .*"]
149	    set re2_styled \
150		[multi_line \
151		     "#0\\s+$main_expr\\s+\\($arg_expr=.*" \
152		     "\\s+$arg_expr=$hex.*\\)\\s+at\\s+$file_expr" \
153		     "\[0-9\]+\\s+.*return.* break here .*"]
154
155	    # The length of the line containing argv containing:
156	    # - 4 leading spaces
157	    # - argv string
158	    # - closing parenthesis
159	    set line_len [expr 4 + $argv_len + 1]
160
161	    if { $argv == "argv=0x0" && $width >= 27 } {
162		# Embedded target with no argv support.
163		# #0  main (argc=0, argv=0x0)
164		set re_styled $re0_styled
165	    } elseif { $line_len > $width } {
166		# At on the next line.
167		set re_styled $re1_styled
168	    } else {
169		# At on the same line as argv.
170		set re_styled $re2_styled
171	    }
172
173	    # Override width for the duration of the command, letting
174	    # GDB reset back to 0.  Doing this in the loop rather than
175	    # after, avoids trying to do "set width 30" while width is
176	    # 20, which causes horizontal scrolling in the case that
177	    # the fallback stub-termcap.c is used:
178	    # ^M<et width 30^M
179	    # (gdb) FAIL: gdb.base/style.exp: all styles enabled: set width 30
180	    gdb_test "with width $width -- frame" $re_styled \
181		"frame when width=$width"
182	}
183
184	set macro_line [gdb_get_line_number "\#define SOME_MACRO"]
185	gdb_test "info macro SOME_MACRO" \
186	    "Defined at $base_file_expr:$macro_line\r\n#define SOME_MACRO 23"
187
188	gdb_test_no_output "set width 0"
189
190	# If disassembler styling is being done by the Python pygments
191	# module, then we can't be sure how the 'some_called_function'
192	# symbol will be styled.  However, if pygments is not being
193	# used then we can know how the symbol name will be styled.
194	set main [limited_style main function]
195	if { $::python_disassembly_styling } {
196	    set func "some_called_function"
197	} else {
198	    set func [limited_style some_called_function function]
199	}
200	# Somewhere should see the call to the function.
201	gdb_test "disassemble main" \
202	    [concat "Dump of assembler code for function $main:.*" \
203		 "[limited_style $hex address].*$func.*"]
204
205	set ifield [limited_style int_field variable]
206	set sfield [limited_style string_field variable]
207	set efield [limited_style e_field variable]
208	set evalue [limited_style VALUE_TWO variable]
209	set lhs [limited_style "\\\$$decimal" variable]
210	gdb_test "print struct_value" \
211	    "$lhs = \{$ifield = 23,.*$sfield = .*,.*$efield = $evalue.*"
212
213	set ffield [limited_style field variable]
214	set cstart [string_to_regexp "/* XXX "]
215	set cend [string_to_regexp " */"]
216	set p1field [limited_style "$cstart.*$decimal.*-bit.*padding.*$cend" \
217			 highlight]
218	set p2field [limited_style "$cstart.*$decimal.*-byte.*padding.*$cend" \
219			 highlight]
220
221	gdb_test "ptype/o just_bitfield_value" \
222	    [multi_line \
223		 ".* type = struct just_bitfield {" \
224		 ".* unsigned int $ffield : 3;" \
225		 "$p1field" \
226		 "$p2field" \
227		 "" \
228		 ".* total size.*: *$decimal *$cend" \
229		 " *}.*"]
230
231	set address_style_expr [limited_style ".*\".*address.*\".*style.*" address]
232	set color "blue"
233	if { $currently_disabled_style == "address" } {
234	    set color "none"
235	}
236	gdb_test "show style address foreground" \
237	    "The ${address_style_expr} foreground color is: ${color}" \
238	    "style name and style word styled using its own style in show style"
239
240	set aliases_expr [limited_style ".*aliases.*" title]
241	set breakpoints_expr [limited_style ".*breakpoints.*" title]
242	gdb_test "help" \
243	    [multi_line \
244		 "List of classes of commands:" \
245		 "" \
246		 "${aliases_expr} -- User-defined aliases of other commands\." \
247		 "${breakpoints_expr} -- Making program stop at certain points\." \
248		 ".*" \
249		] \
250	    "help classes of commands styled with title"
251
252	set taas_expr  [limited_style ".*taas.*" title]
253	set tfaas_expr  [limited_style ".*tfaas.*" title]
254	set cut_for_thre_expr [limited_style "cut for 'thre" highlight]
255	gdb_test "apropos -v cut for 'thre" \
256	    [multi_line \
257		 "" \
258		 "${taas_expr}" \
259		 "Apply a command to all .*" \
260		 "Usage:.*" \
261		 "short${cut_for_thre_expr}ad apply.*" \
262		 "" \
263		 "${tfaas_expr}" \
264		 "Apply a command to all .*" \
265		 "Usage:.*" \
266		 "short${cut_for_thre_expr}ad apply.*" \
267		]
268
269	clean_restart_and_disable "restart 2"
270
271	set quoted [string_to_regexp $binfile]
272	set pass_re "Reading symbols from [limited_style $quoted file]\.\.\."
273	if { $readnow } {
274	    set pass_re \
275		[multi_line \
276		     $pass_re \
277		     "Expanding full symbols from [limited_style $quoted file]\.\.\."]
278	}
279	gdb_test "file $binfile" \
280	    $pass_re \
281	    "filename is styled when loading symbol file"
282
283	gdb_test "pwd" "Working directory [limited_style .*? file].*"
284
285	gdb_test_no_output "set print repeat 3"
286	gdb_test "print {0,0,0,0,0,0,0,0}" \
287	    " = \\{0 [limited_style {<repeats.*8.*times>} metadata]\\}"
288
289	gdb_test "show logging file" \
290	    "The current logfile is \"[limited_style .*? file]\"\\..*"
291
292	# Check warnings are styled by setting a rubbish data
293	# directory.
294	gdb_test "set data-directory Makefile" \
295	    "warning: [limited_style .*? file] is not a directory\\..*"
296	gdb_test "show data-directory" \
297	    "GDB's data directory is \"[limited_style .*? file]\"\\..*"
298
299	# Check that deprecation styles command names.
300	gdb_test_no_output "maintenance deprecate p \"new_p\"" \
301	    "maintenance deprecate p \"new_p\" /1/"
302	gdb_test "p 5" \
303	    "Warning: '[limited_style p title]', an alias for the command '[limited_style print title]', is deprecated.*Use '[limited_style new_p title]'.*" \
304	    "p deprecated warning, with replacement"
305
306	# Check that the version string is styled in the output of 'show
307	# version', and that this styling can be disabled.
308	set vers [style "GNU gdb.*" version]
309	set url [limited_style "http:.*html" file]
310	gdb_test "show version" "${vers}.*<$url>.*" \
311	    "'show version' is styled"
312    }
313}
314
315# Check that disassembler styling can be disabled.  The function that
316# we are disassembling has some minimal styling applied even if the
317# Python pygments module is not available, so, when we disable
318# disassembler styling, we should always see a change in output.
319proc test_disable_disassembler_styling { } {
320    save_vars { env(TERM) env(NO_COLOR) } {
321	# We need an ANSI-capable terminal to get the output.
322	setenv TERM ansi
323	setenv NO_COLOR ""
324
325	# Restart GDB with the correct TERM variable setting, this
326	# means that GDB will enable styling.
327	clean_restart_and_disable "restart 3" $::binfile
328
329	set styled_hex [limited_style $::hex address]
330	set main [limited_style main function]
331
332	foreach_with_prefix libopcodes { on off } {
333
334	    set command_failed false
335	    gdb_test_multiple "maint set libopcodes-styling enabled ${libopcodes}" "" {
336		-re "^maint set libopcodes-styling enabled ${libopcodes}\r\n" {
337		    exp_continue
338		}
339
340		-re "Use of libopcodes styling not supported on architecture \[^\r\n\]+\r\n" {
341		    set command_failed true
342		    exp_continue
343		}
344
345		-re "^$::gdb_prompt $" {
346		    gdb_assert { !$command_failed || [string equal $libopcodes "on"] } \
347			$gdb_test_name
348		}
349	    }
350
351	    if { $libopcodes == "on" && $command_failed } {
352		# We tried to turn on libopcodes disassembler styling,
353		# but this is not supported on this architecture.
354		continue
355	    }
356
357	    foreach_with_prefix disasm_styling { on off } {
358		gdb_test_no_output "set style disassembler enabled ${disasm_styling}"
359
360		if { $libopcodes == "off" && $disasm_styling == "on" \
361			 && !$::python_disassembly_styling} {
362		    # We have libopcodes based styling off, but
363		    # disassembler styling turned on.  We're expecting
364		    # Python Pygments to be used to add styling.
365		    #
366		    # However, if we get here, then we don't have the
367		    # Pygments module, so skip this test.
368		    continue
369		}
370
371		set saw_header_line false
372		set saw_styled_output_line false
373		set saw_unstyled_output_line false
374		gdb_test_multiple "disassemble main" "" {
375		    -re "disassemble main\r\n" {
376			exp_continue
377		    }
378		    -re "^Dump of assembler code for function $main:" {
379			set saw_header_line true
380			exp_continue
381		    }
382		    -re "^\\s+${styled_hex}\\s+<\[^>\]+>:\\s+\[^\r\n\033\]+\r\n" {
383			set saw_unstyled_output_line true
384			exp_continue
385		    }
386		    -re "^\\s+${styled_hex}\\s+<\[^>\]+>:\\s+\[^\r\n\]+\033\[^\r\n\]+\r\n" {
387			set saw_styled_output_line true
388			exp_continue
389		    }
390		    -re "^End of assembler dump\\.\r\n" {
391			exp_continue
392		    }
393		    -re "^$::gdb_prompt $" {
394			gdb_assert { $saw_header_line }
395			if { $disasm_styling } {
396			    gdb_assert { $saw_styled_output_line }
397			    gdb_assert { !$saw_unstyled_output_line }
398			} else {
399			    gdb_assert { !$saw_styled_output_line }
400			    gdb_assert { $saw_unstyled_output_line }
401			}
402		    }
403		}
404	    }
405	}
406    }
407}
408
409# Disassemble a single isntruction at the start of main, then strip
410# off the address and symbol information, returning just the
411# disassembled instruction part.
412proc get_single_disassembled_insn {} {
413    set disasm_line [capture_command_output "x/1i *main" ""]
414    regexp "^\[^:\]+:\\s*(.*)$" $disasm_line whole_match insn
415    return $insn
416}
417
418# Check that, if the user is using Python Pygments for disassembler
419# styling, then the styling correctly switches off when an error is
420# detected in the Python code.
421proc test_disassembler_error_handling { } {
422
423    # This test requires the Python Pygments module to be installed
424    # and used by GDB.
425    if { !$::python_disassembly_styling } {
426	return
427    }
428
429    save_vars { env(TERM) env(NO_COLOR) } {
430	# We need an ANSI-capable terminal to get the output.
431	setenv TERM ansi
432	setenv NO_COLOR ""
433
434	# Restart GDB with the correct TERM variable setting, this
435	# means that GDB will enable styling.
436	clean_restart_and_disable "restart 4" $::binfile
437
438	# Disable use of libopcodes for styling.  As this function is
439	# only called when Python Pygments module is available, we
440	# should now be using that module to style the disassembler
441	# output.
442	gdb_test_no_output "maint set libopcodes-styling enabled off"
443
444	# Disassemble a single instruction and ensure that the output
445	# has styling markers in it.
446	set insn_before [get_single_disassembled_insn]
447	gdb_assert { [regexp "\033" $insn_before] } \
448	    "have style markers when Pygments is working fine"
449
450	# Now replace the standard function that colorizes the
451	# disassembler output, with a new function that always returns
452	# None, this should cause GDB to stop using the Pygments
453	# module for disassembler styling.
454	gdb_py_test_silent_cmd \
455	    [multi_line_input \
456		 "python" \
457		 "def replacement_colorize_disasm(content,gdbarch):" \
458		 "  return None" \
459		 "gdb.styling.colorize_disasm = replacement_colorize_disasm" \
460		 "end"] \
461	    "setup replacement colorize_disasm function" \
462	    true
463
464	set insn_after [get_single_disassembled_insn]
465	gdb_assert { ![regexp "\033" $insn_after] } \
466	    "have no style markers when Pygments is broken"
467    }
468}
469
470# A separate test from the above as the styled text this checks can't
471# currently be disabled (the text is printed too early in GDB's
472# startup process).
473proc test_startup_version_string { } {
474    gdb_exit
475
476    save_vars { ::INTERNAL_GDBFLAGS } {
477	set ::INTERNAL_GDBFLAGS [string map {"-q" ""} $::INTERNAL_GDBFLAGS]
478
479	gdb_spawn
480    }
481
482    # Deliberate use of base STYLE proc here as the style of the
483    # startup version string can't (currently) be controlled.
484    set vers [style "GNU gdb.*" version]
485    gdb_test "" "${vers}.*" "version is styled at startup"
486}
487
488# Check to see if the Python styling of disassembler output is
489# expected or not, this styling requires Python support in GDB, and
490# the Python pygments module to be available.
491clean_restart ${binfile}
492if {[allow_python_tests] && [gdb_py_module_available "pygments"]} {
493    set python_disassembly_styling true
494} else {
495    set python_disassembly_styling false
496}
497
498# Run tests with all styles in their default state.
499with_test_prefix "all styles enabled" {
500    run_style_tests
501}
502
503# Now, for each style in turn.  Disable that style only and run the
504# test again.  Things in that style should NOT now be styled.
505foreach style { title file function highlight variable \
506		    address metadata } {
507    set currently_disabled_style $style
508    with_test_prefix "disable style $style" {
509	run_style_tests
510    }
511}
512
513# Check that the disassembler styling can be disabled.
514test_disable_disassembler_styling
515
516# Check that GDB handles an error in the Python Pygments disassembly
517# styling code.
518test_disassembler_error_handling
519
520# Finally, check the styling of the version string during startup.
521test_startup_version_string
522