]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/testsuite/gdb.base/until-trailing-insns.exp
Update copyright year range in header of all files managed by GDB
[thirdparty/binutils-gdb.git] / gdb / testsuite / gdb.base / until-trailing-insns.exp
1 # Copyright 2022-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
16 # This test sets up debug information for a loop as we see in some cases
17 # from clang-13. In this situation, instructions at both the start and end
18 # of the loop are associated (in the line table), with the header line of
19 # the loop (line 10 in the example below).
20 #
21 # At the end of the loop we see some instructions marked as not a statement,
22 # but still associated with the same loop header line. For example,
23 # consider the following C code:
24 #
25 # 10: for (i = 0; i < 10; ++i)
26 # 11: loop_body ();
27 # 12: other_stuff ();
28 #
29 # Transformed into the following pseudo-assembler, with associated line table:
30 #
31 # Address | Pseudo-Assembler | Line | Is-Statement?
32 #
33 # 0x100 | i = 0 | 10 | Yes
34 # 0x104 | loop_body () | 11 | Yes
35 # 0x108 | i = i + 1 | 10 | Yes
36 # 0x10c | if (i < 10): | 10 | No
37 # 0x110 | goto 0x104 | 10 | No
38 # 0x114 | other_stuff () | 12 | Yes
39 #
40 # Notice the two non-statement instructions at the end of the loop.
41 #
42 # The problem here is that when we reach address 0x108 and use 'until',
43 # hoping to leave the loop, GDB sets up a stepping range that runs from the
44 # start of the function (0x100 in our example) to the end of the current
45 # line table entry, that is 0x10c in our example. GDB then starts stepping
46 # forward.
47 #
48 # When 0x10c is reached GDB spots that we have left the stepping range, that
49 # the new location is not a statement, and that the new location is
50 # associated with the same source line number as the previous stepping
51 # range. GDB then sets up a new stepping range that runs from 0x10c to
52 # 0x114, and continues stepping forward.
53 #
54 # Within that stepping range the inferior hits the goto and loops back to
55 # address 0x104.
56 #
57 # At 0x104 GDB spots that we have left the previous stepping range, that the
58 # new address is marked as a statement, and that the new address is for a
59 # different source line. As a result, GDB stops and returns control to the
60 # user. This is not what the user was expecting, they expected GDB not to
61 # stop until they were outside of the loop.
62 #
63 # The fix is that, when the user issues the 'until' command, and GDB sets up
64 # the initial stepping range, GDB will check subsequent SALs to see if they
65 # are non-statements associated with the same line number. If they are then
66 # the end of the initial stepping range is pushed out to the end of the
67 # non-statement SALs.
68 #
69 # In our example above, the user is at 0x108 and uses 'until'. GDB now sets
70 # up a stepping range from the start of the function 0x100 to 0x114, the
71 # first address associated with a different line.
72 #
73 # Now as GDB steps around the loop it never leaves the initial stepping
74 # range. It is only when GDB exits the loop that we leave the stepping
75 # range, and the stepping finishes at address 0x114.
76 #
77 # This test checks this behaviour using the DWARF assembler.
78
79 load_lib dwarf.exp
80
81 # This test can only be run on targets which support DWARF-2 and use gas.
82 require dwarf2_support
83
84 standard_testfile .c .S
85
86 if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile}] } {
87 return -1
88 }
89
90 set asm_file [standard_output_file $srcfile2]
91 Dwarf::assemble $asm_file {
92 global srcdir subdir srcfile
93 declare_labels integer_label L
94 set int_size [get_sizeof "int" 4]
95
96 # Find start address and length for our functions.
97 lassign [function_range main [list ${srcdir}/${subdir}/$srcfile]] \
98 main_start main_len
99 set main_end "$main_start + $main_len"
100
101 cu {} {
102 compile_unit {
103 {language @DW_LANG_C}
104 {name until-trailing-isns.c}
105 {stmt_list $L DW_FORM_sec_offset}
106 {low_pc 0 addr}
107 } {
108 subprogram {
109 {external 1 flag}
110 {name main}
111 {low_pc $main_start addr}
112 {high_pc $main_len DW_FORM_data4}
113 }
114 }
115 }
116
117 lines {version 2 default_is_stmt 1} L {
118 include_dir "${srcdir}/${subdir}"
119 file_name "$srcfile" 1
120
121 # Generate a line table program. This mimicks clang-13's behavior
122 # of adding some !is_stmt at the end of a loop line, making until
123 # not work properly.
124 program {
125 DW_LNE_set_address $main_start
126 line [gdb_get_line_number "TAG: main prologue"]
127 DW_LNS_copy
128 DW_LNE_set_address loop_start
129 line [gdb_get_line_number "TAG: loop line"]
130 DW_LNS_copy
131 DW_LNE_set_address loop_condition
132 line [gdb_get_line_number "TAG: loop line"]
133 DW_LNS_negate_stmt
134 DW_LNS_copy
135 DW_LNE_set_address loop_code
136 line [gdb_get_line_number "TAG: loop code"]
137 DW_LNS_negate_stmt
138 DW_LNS_copy
139 DW_LNE_set_address loop_increment
140 line [gdb_get_line_number "TAG: loop line"]
141 DW_LNS_copy
142 DW_LNE_set_address loop_jump
143 line [gdb_get_line_number "TAG: loop line"]
144 DW_LNS_negate_stmt
145 DW_LNS_copy
146 DW_LNE_set_address main_return
147 line [gdb_get_line_number "TAG: main return"]
148 DW_LNS_negate_stmt
149 DW_LNS_copy
150 DW_LNE_set_address $main_end
151 line [expr [gdb_get_line_number "TAG: main return"] + 1]
152 DW_LNS_copy
153 DW_LNE_end_sequence
154 }
155 }
156
157 }
158
159 if { [prepare_for_testing "failed to prepare" ${testfile} \
160 [list $srcfile $asm_file] {nodebug} ] } {
161 return -1
162 }
163
164 if ![runto_main] {
165 return -1
166 }
167
168 gdb_test "next" ".* TAG: loop code .*" "inside the loop"
169 gdb_test "next" ".* TAG: loop line .*" "ending of loop"
170 gdb_test "until" ".* TAG: main return .*" "left loop"