dw2-unexpected-entry-pc.exp revision 1.1.1.1 1 1.1 christos # Copyright 2024 Free Software Foundation, Inc.
2 1.1 christos
3 1.1 christos # This program is free software; you can redistribute it and/or modify
4 1.1 christos # it under the terms of the GNU General Public License as published by
5 1.1 christos # the Free Software Foundation; either version 3 of the License, or
6 1.1 christos # (at your option) any later version.
7 1.1 christos #
8 1.1 christos # This program is distributed in the hope that it will be useful,
9 1.1 christos # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 1.1 christos # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 1.1 christos # GNU General Public License for more details.
12 1.1 christos #
13 1.1 christos # You should have received a copy of the GNU General Public License
14 1.1 christos # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 1.1 christos
16 1.1 christos # Create an inline function which uses DW_AT_ranges and which has a
17 1.1 christos # DW_AT_entry_pc.
18 1.1 christos #
19 1.1 christos # Within the function's ranges, create an empty sub-range, many
20 1.1 christos # versions of gcc (8.x to at least 14.x) do this, and point the
21 1.1 christos # DW_AT_entry_pc at this empty sub-range (at last 8.x to 9.x did
22 1.1 christos # this).
23 1.1 christos #
24 1.1 christos # Now place a breakpoint on the inline function and run to the
25 1.1 christos # breakpoint, check that GDB reports we are inside the inline
26 1.1 christos # function.
27 1.1 christos #
28 1.1 christos # At one point GDB would use the entry-pc value as the breakpoint
29 1.1 christos # location even though that address is not actually associated with
30 1.1 christos # the inline function. Now GDB will reject the entry-pc value and
31 1.1 christos # select a suitable default entry-pc value instead, one which is
32 1.1 christos # associated with the inline function.
33 1.1 christos
34 1.1 christos load_lib dwarf.exp
35 1.1 christos
36 1.1 christos require dwarf2_support
37 1.1 christos
38 1.1 christos standard_testfile
39 1.1 christos
40 1.1 christos # This compiles the source file and starts and stops GDB, so run it
41 1.1 christos # before calling prepare_for_testing otherwise GDB will have exited.
42 1.1 christos get_func_info foo
43 1.1 christos
44 1.1 christos if { [prepare_for_testing "failed to prepare" ${testfile} \
45 1.1 christos [list ${srcfile}]] } {
46 1.1 christos return
47 1.1 christos }
48 1.1 christos
49 1.1 christos if ![runto_main] {
50 1.1 christos return
51 1.1 christos }
52 1.1 christos
53 1.1 christos # Some label addresses, needed to match against the output later.
54 1.1 christos foreach foo {foo_1 foo_2 foo_3 foo_4 foo_5 foo_6} {
55 1.1 christos set $foo [get_hexadecimal_valueof "&$foo" "UNKNOWN" \
56 1.1 christos "get address for $foo label"]
57 1.1 christos }
58 1.1 christos
59 1.1 christos # Some line numbers needed in the generated DWARF.
60 1.1 christos set foo_decl_line [gdb_get_line_number "foo decl line"]
61 1.1 christos set bar_call_line [gdb_get_line_number "bar call line"]
62 1.1 christos
63 1.1 christos if [is_ilp32_target] {
64 1.1 christos set ptr_type "data4"
65 1.1 christos } else {
66 1.1 christos set ptr_type "data8"
67 1.1 christos }
68 1.1 christos
69 1.1 christos # Setup the fake DWARF (see comment at top of this file for more
70 1.1 christos # details). Use DWARF_VERSION (either 4 or 5) to select which type of
71 1.1 christos # ranges are created. Compile the source and generated DWARF and run
72 1.1 christos # the test.
73 1.1 christos #
74 1.1 christos # The ENTRY_LABEL is the label to use as the entry-pc value. The
75 1.1 christos # useful choices are 'foo_3', this label is for an empty sub-range,
76 1.1 christos # 'foo_4', this label is within the blocks low/high addresses, but is
77 1.1 christos # not in any sub-range for the block at all, or 'foo_6', this label is
78 1.1 christos # the end address of a non-empty sub-range, and is also the end
79 1.1 christos # address for the whole block.
80 1.1 christos #
81 1.1 christos # The 'foo_4' case is not something that has been seen generated by
82 1.1 christos # any compiler, but it doesn't hurt to test.
83 1.1 christos #
84 1.1 christos # When WITH_LINE_TABLE is true a small snippet of line table will be
85 1.1 christos # generated which covers some parts of the inlined function. This
86 1.1 christos # makes most sense when being tested with the 'foo_6' label, as that
87 1.1 christos # label is all about handling the end of the inline function case.
88 1.1 christos
89 1.1 christos proc run_test { entry_label dwarf_version with_line_table } {
90 1.1 christos set dw_testname "${::testfile}-${dwarf_version}-${entry_label}"
91 1.1 christos
92 1.1 christos if { $with_line_table } {
93 1.1 christos set dw_testname ${dw_testname}-lt
94 1.1 christos }
95 1.1 christos
96 1.1 christos set asm_file [standard_output_file "${dw_testname}.S"]
97 1.1 christos Dwarf::assemble $asm_file {
98 1.1 christos upvar dwarf_version dwarf_version
99 1.1 christos upvar entry_label entry_label
100 1.1 christos
101 1.1 christos declare_labels lines_table inline_func ranges_label
102 1.1 christos
103 1.1 christos cu { version $dwarf_version } {
104 1.1 christos compile_unit {
105 1.1 christos {producer "gcc"}
106 1.1 christos {language @DW_LANG_C}
107 1.1 christos {name $::srcfile}
108 1.1 christos {comp_dir /tmp}
109 1.1 christos {stmt_list $lines_table DW_FORM_sec_offset}
110 1.1 christos {low_pc 0 addr}
111 1.1 christos } {
112 1.1 christos inline_func: subprogram {
113 1.1 christos {name bar}
114 1.1 christos {inline @DW_INL_declared_inlined}
115 1.1 christos }
116 1.1 christos subprogram {
117 1.1 christos {name foo}
118 1.1 christos {decl_file 1 data1}
119 1.1 christos {decl_line $::foo_decl_line data1}
120 1.1 christos {decl_column 1 data1}
121 1.1 christos {low_pc $::foo_start addr}
122 1.1 christos {high_pc $::foo_len $::ptr_type}
123 1.1 christos {external 1 flag}
124 1.1 christos } {
125 1.1 christos inlined_subroutine {
126 1.1 christos {abstract_origin %$inline_func}
127 1.1 christos {call_file 1 data1}
128 1.1 christos {call_line $::bar_call_line data1}
129 1.1 christos {entry_pc $entry_label addr}
130 1.1 christos {ranges ${ranges_label} DW_FORM_sec_offset}
131 1.1 christos }
132 1.1 christos }
133 1.1 christos }
134 1.1 christos }
135 1.1 christos
136 1.1 christos lines {version 2} lines_table {
137 1.1 christos include_dir "$::srcdir/$::subdir"
138 1.1 christos file_name "$::srcfile" 1
139 1.1 christos
140 1.1 christos upvar with_line_table with_line_table
141 1.1 christos
142 1.1 christos if {$with_line_table} {
143 1.1 christos program {
144 1.1 christos DW_LNE_set_address foo_label
145 1.1 christos line [expr $::bar_call_line - 2]
146 1.1 christos DW_LNS_copy
147 1.1 christos
148 1.1 christos DW_LNE_set_address foo_0
149 1.1 christos line [expr $::bar_call_line - 1]
150 1.1 christos DW_LNS_copy
151 1.1 christos
152 1.1 christos DW_LNE_set_address foo_1
153 1.1 christos line 1
154 1.1 christos DW_LNS_copy
155 1.1 christos
156 1.1 christos DW_LNE_set_address foo_2
157 1.1 christos line 2
158 1.1 christos DW_LNS_copy
159 1.1 christos
160 1.1 christos DW_LNE_set_address foo_6
161 1.1 christos line 10
162 1.1 christos DW_LNS_copy
163 1.1 christos
164 1.1 christos DW_LNE_set_address foo_6
165 1.1 christos line 10
166 1.1 christos DW_LNS_negate_stmt
167 1.1 christos DW_LNS_copy
168 1.1 christos
169 1.1 christos DW_LNE_set_address foo_6
170 1.1 christos line $::bar_call_line
171 1.1 christos DW_LNS_copy
172 1.1 christos
173 1.1 christos DW_LNE_set_address "$::foo_start + $::foo_len"
174 1.1 christos DW_LNE_end_sequence
175 1.1 christos }
176 1.1 christos }
177 1.1 christos }
178 1.1 christos
179 1.1 christos if { $dwarf_version == 5 } {
180 1.1 christos rnglists {} {
181 1.1 christos table {} {
182 1.1 christos ranges_label: list_ {
183 1.1 christos start_end foo_3 foo_3
184 1.1 christos start_end foo_1 foo_2
185 1.1 christos start_end foo_5 foo_6
186 1.1 christos }
187 1.1 christos }
188 1.1 christos }
189 1.1 christos } else {
190 1.1 christos ranges { } {
191 1.1 christos ranges_label: sequence {
192 1.1 christos range foo_3 foo_3
193 1.1 christos range foo_1 foo_2
194 1.1 christos range foo_5 foo_6
195 1.1 christos }
196 1.1 christos }
197 1.1 christos }
198 1.1 christos }
199 1.1 christos
200 1.1 christos if {[prepare_for_testing "failed to prepare" "${dw_testname}" \
201 1.1 christos [list $::srcfile $asm_file] {nodebug}]} {
202 1.1 christos return false
203 1.1 christos }
204 1.1 christos
205 1.1 christos if ![runto_main] {
206 1.1 christos return false
207 1.1 christos }
208 1.1 christos
209 1.1 christos # Place a breakpoint on `bar` and run to the breakpoint. Use
210 1.1 christos # gdb_test as we want full pattern matching against the stop
211 1.1 christos # location.
212 1.1 christos #
213 1.1 christos # When we have a line table GDB will find a line for the
214 1.1 christos # breakpoint location, so the output will be different.
215 1.1 christos if { $with_line_table } {
216 1.1 christos set re \
217 1.1 christos [multi_line \
218 1.1 christos "Breakpoint $::decimal, bar \\(\\) at \[^\r\n\]+/$::srcfile:1" \
219 1.1 christos "1\\s+\[^\r\n\]+"]
220 1.1 christos } else {
221 1.1 christos set re "Breakpoint $::decimal, $::hex in bar \\(\\)"
222 1.1 christos }
223 1.1 christos gdb_breakpoint bar
224 1.1 christos gdb_test "continue" $re
225 1.1 christos
226 1.1 christos # Inspect the block structure of `bar` at this location. We are
227 1.1 christos # expecting that the empty range (that contained the entry-pc) has
228 1.1 christos # been removed from the block, and that the entry-pc has its
229 1.1 christos # default value.
230 1.1 christos gdb_test "maint info blocks" \
231 1.1 christos [multi_line \
232 1.1 christos "\\\[\\(block \\*\\) $::hex\\\] $::foo_1\\.\\.$::foo_6" \
233 1.1 christos " entry pc: $::foo_1" \
234 1.1 christos " inline function: bar" \
235 1.1 christos " symbol count: $::decimal" \
236 1.1 christos " address ranges:" \
237 1.1 christos " $::foo_1\\.\\.$::foo_2" \
238 1.1 christos " $::foo_5\\.\\.$::foo_6"]
239 1.1 christos }
240 1.1 christos
241 1.1 christos foreach_with_prefix dwarf_version { 4 5 } {
242 1.1 christos # Test various labels without any line table present.
243 1.1 christos foreach_with_prefix entry_label { foo_3 foo_4 foo_2 foo_6 } {
244 1.1 christos run_test $entry_label $dwarf_version false
245 1.1 christos }
246 1.1 christos
247 1.1 christos # Now test what happens if we use the end address of the block,
248 1.1 christos # but also supply a line table. Does GDB do anything different?
249 1.1 christos run_test foo_6 $dwarf_version true
250 1.1 christos }
251