aboutsummaryrefslogtreecommitdiff
path: root/gdb/testsuite/gdb.base/cached-source-file.exp
blob: b063362628a239b9d7e452de1d5904565ccf556d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
# Copyright (C) 2020-2024 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 for PR tui/25126.
#
# The bug is about a regression that makes GDB not reload its source
# code cache when the inferior's symbols are reloaded, which leads to
# wrong backtraces/listings.
#
# This bug is reproducible even without using the TUI.

standard_testfile

# Only run on native boards.
require !use_gdb_stub
if { [target_info gdb_protocol] == "extended-remote" } {
    return -1
}

# Because we need to modify the source file later, it's better if we
# just copy it to our output directory (instead of messing with the
# user's source directory).
set newsrc [standard_output_file $testfile].c
file copy -force -- $srcdir/$subdir/$srcfile $newsrc
set srcfile $newsrc

if { [prepare_for_testing "failed to prepare" $testfile $srcfile] } {
    return -1
}

# Get the line number for the line with the "break-here" marker.
set bp_line [gdb_get_line_number "break-here" $srcfile]

gdb_assert { [runto "$srcfile:$bp_line"] } \
    "run to break-here marker"

# Do a "list" and check that the printed line matches the line of the
# original source file.
gdb_test_no_output "set listsize 1"
gdb_test "list" "$bp_line\[ \t\]+printf \\(\"hello\\\\n\"\\); /\\* break-here \\*/" \
    "check the first version of the source file"

# Modify the original source file, and add an extra line into it.
# This only works locally because of the TCL commands.
set bkpsrc [standard_output_file $testfile].c.bkp
set bkpsrcfd [open $bkpsrc w]
set srcfd [open $srcfile r]

while { [gets $srcfd line] != -1 } {
    if { [string first "break-here" $line] != -1 } {
	# Put a "printf" line before the "break-here" line.
	puts $bkpsrcfd "  printf (\"foo\\n\"); /* new-marker */"
    }
    puts $bkpsrcfd $line
}

close $bkpsrcfd
close $srcfd
file rename -force -- $bkpsrc $srcfile
# We have to wait 1 second because of the way GDB checks whether the
# binary has changed or not.  GDB uses stat(2) and currently checks
# 'st_mtime', whose precision is measured in seconds.  Since the copy,
# rename, and rebuild can take less than 1 second, GDB might mistakenly
# assume that the binary is unchanged.
sleep 1

# Recompile the modified source.  We use "gdb_compile" here instead of
# "prepare_for_testing" because we don't want to call "clean_restart".
if { [gdb_compile "${srcfile}" "${binfile}" executable {debug}] != "" } {
    return -1
}

# Rerun the program.  This should not only force GDB to reload the
# source cache, but also to break at BP_LINE again, which now has
# different contents.
set q \
    [multi_line \
	 "The program being debugged has been started already\\." \
	 "Start it from the beginning\\? \\(y or n\\) "]
set binregex [string_to_regexp $binfile]
set re \
    [multi_line \
	 "\\`$binregex\\' has changed; re-reading symbols\\.(" \
	 "Expanding full symbols from $binfile\\.\\.\\.)?" \
	 "Starting program: ${binregex}.*"]
gdb_test "run" $re "rerun program" $q y

# Again, perform the listing and check that the line indeed has
# changed for GDB.
gdb_test "list" "${bp_line}\[ \t\]+printf \\(\"foo\\\\n\"\\); /\\\* new-marker \\\*/.*" \
    "verify that the source code is properly reloaded"

# Modify the source file again.  As before, this only works locally
# because of the TCL commands.
set bkpsrc [standard_output_file $testfile].c.bkp
set bkpsrcfd [open $bkpsrc w]
set srcfd [open $srcfile r]

while { [gets $srcfd line] != -1 } {
    if { [string first "new-marker" $line] != -1 } {
	# Modify the printf line that we added previously.
	puts $bkpsrcfd "  printf (\"foo\\n\"); /* new-marker updated */"
    } else {
	puts $bkpsrcfd $line
    }
}

close $bkpsrcfd
close $srcfd
file rename -force -- $bkpsrc $srcfile

# As before, delay so that at least one second has passed.  GDB still
# will not spot that the source file has changed, as GDB doesn't do a
# time check unless the binary has also changed, this delay just
# allows us to confirm this behavior.
sleep 1

# List the printf line again, we should not see the file changes yet
# as the binary is unchanged, so the cached contents will still be
# used.
gdb_test "list ${bp_line}" "${bp_line}\[ \t\]+printf \\(\"foo\\\\n\"\\); /\\\* new-marker \\\*/.*" \
    "verify that the source code change is not seen yet"

gdb_test "maint flush source-cache" "Source cache flushed\\."

# List the printf line again.  After the cache flush GDB will re-read
# the source file and we should now see the changes.
gdb_test "list ${bp_line}" "${bp_line}\[ \t\]+printf \\(\"foo\\\\n\"\\); /\\\* new-marker updated \\\*/.*" \
    "verify that the updated source code change is not seen"