forked from Imagelibrary/binutils-gdb
This updates the copyright headers to include 2025. I did this by running gdb/copyright.py and then manually modifying a few files as noted by the script. Approved-By: Eli Zaretskii <eliz@gnu.org>
280 lines
8.1 KiB
Plaintext
280 lines
8.1 KiB
Plaintext
# Copyright 2021-2025 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 <http://www.gnu.org/licenses/>.
|
|
|
|
# Test that string values are correctly allocated inside GDB when doing
|
|
# various operations that yield strings.
|
|
#
|
|
# The issue that lead to this test was a missing NULL terminator in the
|
|
# C-string values. We verify that we can print the null terminator of these
|
|
# strings.
|
|
|
|
load_lib "trace-support.exp"
|
|
load_lib "gdb-guile.exp"
|
|
|
|
standard_testfile
|
|
|
|
if {[build_executable "failed to prepare" $testfile $srcfile ]} {
|
|
return
|
|
}
|
|
|
|
set user_conv_funcs {$_gdb_setting $_gdb_setting_str}
|
|
set maint_conv_funcs {$_gdb_maint_setting $_gdb_maint_setting_str}
|
|
|
|
# Add language (LANG) appropriate quotation marks around string STR.
|
|
proc quote_for_lang {lang str} {
|
|
if {$lang == "fortran"} {
|
|
return "'$str'"
|
|
} else {
|
|
return "\"$str\""
|
|
}
|
|
}
|
|
|
|
# Check that the string contained in the convenienced variable $v is
|
|
# EXPECTED_STR.
|
|
#
|
|
# In particular, check that the null terminator is there and that we can't
|
|
# access a character past the end of the string.
|
|
|
|
proc check_v_string { expected_str } {
|
|
set len [string length $expected_str]
|
|
|
|
for { set i 0 } { $i < $len } { incr i } {
|
|
set c [string index $expected_str $i]
|
|
gdb_test "print \$v\[$i\]" "= $::decimal '$c'"
|
|
}
|
|
|
|
# Check that the string ends with a null terminator.
|
|
gdb_test "print \$v\[$i\]" {= 0 '\\000'}
|
|
|
|
# Check that we can't access a character after the end of the string.
|
|
incr i
|
|
gdb_test "print \$v\[$i\]" "no such vector element"
|
|
}
|
|
|
|
# Test with string values made by $_gdb_setting & co.
|
|
|
|
proc_with_prefix test_setting { } {
|
|
clean_restart
|
|
|
|
# This is an internal GDB implementation detail, but the variable backing
|
|
# a string setting starts as nullptr (unless explicitly initialized at
|
|
# startup). When assigning an empty value, the variable then points to an
|
|
# empty string. Test both cases, as it triggers different code paths (in
|
|
# addition to a non-empty value).
|
|
#
|
|
# Use "set trace-user" and "maintenance set test-settings string" as they
|
|
# are both not initialized at startup.
|
|
with_test_prefix "user setting" {
|
|
with_test_prefix "not set" {
|
|
foreach_with_prefix conv_func $::user_conv_funcs {
|
|
gdb_test_no_output "set \$v = ${conv_func}(\"trace-user\")"
|
|
check_v_string ""
|
|
}
|
|
}
|
|
|
|
with_test_prefix "set to empty" {
|
|
gdb_test "set trace-user"
|
|
foreach_with_prefix conv_func $::user_conv_funcs {
|
|
gdb_test_no_output "set \$v = ${conv_func}(\"trace-user\")"
|
|
check_v_string ""
|
|
}
|
|
}
|
|
|
|
with_test_prefix "set" {
|
|
gdb_test "set trace-user poulet"
|
|
foreach_with_prefix conv_func $::user_conv_funcs {
|
|
gdb_test_no_output {set $v = $_gdb_setting("trace-user")}
|
|
check_v_string "poulet"
|
|
}
|
|
}
|
|
}
|
|
|
|
with_test_prefix "maintenance setting" {
|
|
with_test_prefix "not set" {
|
|
foreach_with_prefix conv_func $::maint_conv_funcs {
|
|
gdb_test_no_output \
|
|
"set \$v = ${conv_func}(\"test-settings string\")"
|
|
check_v_string ""
|
|
}
|
|
}
|
|
|
|
with_test_prefix "set to empty" {
|
|
gdb_test "maintenance set test-settings string"
|
|
foreach_with_prefix conv_func $::maint_conv_funcs {
|
|
gdb_test_no_output \
|
|
"set \$v = ${conv_func}(\"test-settings string\")"
|
|
check_v_string ""
|
|
}
|
|
}
|
|
|
|
with_test_prefix "set" {
|
|
gdb_test "maintenance set test-settings string perchaude"
|
|
foreach_with_prefix conv_func $::maint_conv_funcs {
|
|
gdb_test_no_output \
|
|
"set \$v = ${conv_func}(\"test-settings string\")"
|
|
check_v_string "perchaude"
|
|
}
|
|
}
|
|
}
|
|
|
|
# Test with a non-string setting, this tests yet another code path.
|
|
with_test_prefix "integer setting" {
|
|
gdb_test_no_output {set $v = $_gdb_setting_str("remotetimeout")}
|
|
check_v_string "2"
|
|
}
|
|
|
|
# Test string values made by $_gdb_setting & co. in all languages.
|
|
with_test_prefix "all langs" {
|
|
# Get list of supported languages.
|
|
set langs [gdb_supported_languages]
|
|
|
|
gdb_test "maintenance set test-settings string foo"
|
|
foreach_with_prefix lang $langs {
|
|
gdb_test_no_output "set language $lang"
|
|
|
|
if {$lang == "modula-2"} {
|
|
# The Modula-2 parser doesn't know how to build a
|
|
# suitable string expression.
|
|
gdb_test "print \"foo\"" "strings are not implemented"
|
|
continue
|
|
}
|
|
|
|
if {$lang == "rust"} {
|
|
# Rust strings are actually structs, without a running
|
|
# inferior into which the string data can be pushed
|
|
# GDB can't print anything.
|
|
gdb_test "print \"foo\"" \
|
|
"evaluation of this expression requires the target program to be active"
|
|
gdb_test "print \$_gdb_maint_setting(\"test-settings string\")" \
|
|
"evaluation of this expression requires the target program to be active"
|
|
continue
|
|
}
|
|
|
|
if {$lang == "unknown"} {
|
|
# Skipped because expression parsing is not supported
|
|
# for the "unknown" language. See gdb/28093 for more
|
|
# details.
|
|
continue
|
|
}
|
|
|
|
set print_output ""
|
|
set ptype_output ""
|
|
|
|
set foo_str [quote_for_lang $lang foo]
|
|
gdb_test_multiple "print $foo_str" "" {
|
|
-wrap -re " = (.*)" {
|
|
set print_output $expect_out(1,string)
|
|
pass $gdb_test_name
|
|
}
|
|
}
|
|
|
|
gdb_test_multiple "ptype $foo_str" "" {
|
|
-wrap -re " = (.*)" {
|
|
set ptype_output $expect_out(1,string)
|
|
pass $gdb_test_name
|
|
}
|
|
}
|
|
|
|
set cmd_str [quote_for_lang $lang "test-settings string"]
|
|
set ptype_output_re [string_to_regexp $ptype_output]
|
|
set print_output_re [string_to_regexp $print_output]
|
|
|
|
foreach_with_prefix conv_func $::maint_conv_funcs {
|
|
gdb_test "print ${conv_func}($cmd_str)" \
|
|
" = $print_output_re"
|
|
gdb_test "ptype \$" \
|
|
" = $ptype_output_re"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
# Test with a string value created by gdb.Value in Python.
|
|
|
|
proc_with_prefix test_python_value { } {
|
|
clean_restart
|
|
|
|
if {![allow_python_tests]} {
|
|
untested "skipping test_python_value"
|
|
return
|
|
}
|
|
|
|
gdb_test_no_output "python gdb.set_convenience_variable(\"v\", \"bar\")" \
|
|
"set convenience var"
|
|
check_v_string "bar"
|
|
}
|
|
|
|
# Test with a string value created by make-value in Guile.
|
|
|
|
proc_with_prefix test_guile_value { } {
|
|
clean_restart
|
|
|
|
if {![allow_guile_tests]} {
|
|
untested "skipping test_guile_value"
|
|
return
|
|
}
|
|
|
|
# We can't set a convenience var from Guile, but we can append to history.
|
|
# Do that, then transfer to a convenience var with a CLI command.
|
|
gdb_test_no_output "guile (use-modules (gdb))"
|
|
gdb_test_multiple "guile (history-append! (make-value \"foo\"))" "make value" {
|
|
-re -wrap "($::decimal)" {
|
|
set histnum $expect_out(1,string)
|
|
}
|
|
}
|
|
|
|
gdb_test_no_output "set \$v = \$$histnum"
|
|
check_v_string "foo"
|
|
}
|
|
|
|
# Test with a string value coming from a string internal var. The only internal
|
|
# vars of this type, at the time of writing, are $trace_func and $trace_file.
|
|
# They both require inspecting a trace frame. So if the target is capable start
|
|
# tracing, record one trace frame, and use $trace_func.
|
|
|
|
proc_with_prefix test_internal_var { } {
|
|
if {![gdb_trace_common_supports_arch]} {
|
|
unsupported "arch does not support trace"
|
|
return
|
|
}
|
|
|
|
clean_restart $::binfile
|
|
|
|
if {![runto_main]} {
|
|
fail "could not run to main"
|
|
return
|
|
}
|
|
|
|
if {![gdb_target_supports_trace]} {
|
|
unsupported "target does not support trace"
|
|
return
|
|
}
|
|
|
|
gdb_breakpoint "end"
|
|
gdb_test "trace trace_me" "Tracepoint $::decimal at $::hex.*"
|
|
gdb_test_no_output "tstart"
|
|
gdb_continue_to_breakpoint "breakpoint at end"
|
|
gdb_test_no_output "tstop"
|
|
gdb_test "tfind" "Found trace frame 0, tracepoint $::decimal.*"
|
|
gdb_test_no_output "set \$v = \$trace_func"
|
|
gdb_test "tfind none" "No longer looking at any trace frame.*"
|
|
check_v_string "trace_me"
|
|
}
|
|
|
|
test_setting
|
|
test_python_value
|
|
test_guile_value
|
|
test_internal_var
|