]>
Commit | Line | Data |
---|---|---|
4a94e368 | 1 | # Copyright 2021-2022 Free Software Foundation, Inc. |
a640adf7 KB |
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 case uses the DWARF assembler to reproduce the problem | |
17 | # described by PR28030. The bug turned out to be that | |
18 | # FIELD_LOC_KIND_DWARF_BLOCK was not handled when recursively copying | |
19 | # a value's type when preserving the value history during the freeing | |
20 | # up of objfiles associated with a shared object. (Yes, figuring out | |
21 | # how to make this happen in a concise test case turned out to be | |
22 | # challenging.) | |
23 | # | |
24 | # The following elements proved to be necessary for reproducing the | |
25 | # problem: | |
26 | # | |
27 | # 1) A location expression needed to be used with | |
28 | # DW_AT_data_member_location rather than a simple offset. | |
29 | # Moreover, this location expression needed to use opcodes | |
30 | # which GDB's DWARF reader could not convert to a simple | |
31 | # offset. (Note, however, that GDB could probably be improved | |
32 | # to handle the opcodes chosen for this test; if decode_locdesc() | |
33 | # in dwarf2/read.c is ever updated to handle both DW_OP_pick and | |
34 | # DW_OP_drop, then this test could end up passing even if | |
35 | # the bug it's intended to test has not been fixed.) | |
36 | # | |
37 | # 2) The debug info containing the above DWARF info needed | |
38 | # to be associated with a shared object since the problem | |
39 | # occurred while GDB was preserving values during the | |
40 | # purging of shared objects. | |
41 | # | |
42 | # 3) After performing some simple gdb commands, the program is | |
43 | # run again. In the course of running the objfile destructor | |
44 | # associated with the shared object, values are preserved | |
45 | # along with their types. As noted earlier, it was during | |
46 | # the recursive type copy that the bug was observed. | |
47 | # | |
48 | # Therefore, due to #2 above, this test case creates debug info | |
49 | # which is then used by a shared object. | |
50 | ||
51 | # This test can't be run on targets lacking shared library support. | |
52 | if [skip_shlib_tests] { | |
53 | return 0 | |
54 | } | |
55 | ||
56 | load_lib dwarf.exp | |
57 | ||
58 | # This test can only be run on targets which support DWARF-2 and use gas. | |
59 | if ![dwarf2_support] { | |
60 | return 0 | |
61 | } | |
62 | ||
63 | # gdb_test_file_name is the name of this file without the .exp | |
64 | # extension. Use it to form basenames for the main program | |
65 | # and shared object. | |
66 | set main_basename ${::gdb_test_file_name}-main | |
67 | set lib_basename ${::gdb_test_file_name}-lib | |
68 | ||
2899c914 | 69 | # We're generating DWARF assembly for the shared object; |
a640adf7 KB |
70 | # The output of Dwarf::assemble will be placed in $lib_basename.S |
71 | # which will be ${srcfile3} after the execution of standard_testfile. | |
72 | ||
2899c914 | 73 | standard_testfile $main_basename.c $lib_basename.c $lib_basename.S |
a640adf7 | 74 | |
2899c914 | 75 | set libsrc "${::srcdir}/${::subdir}/${::srcfile2}" |
a640adf7 KB |
76 | set lib_so [standard_output_file ${lib_basename}.so] |
77 | set asm_file [standard_output_file ${::srcfile3}] | |
78 | ||
2899c914 TV |
79 | # Compile the shared library for the first GDB session. Note that debugging |
80 | # symbols will be present for this compilation, because we want to print some | |
81 | # type information. | |
a640adf7 | 82 | if {[gdb_compile_shlib $libsrc $lib_so \ |
2899c914 | 83 | {debug}] != ""} { |
a640adf7 KB |
84 | untested "failed to compile shared library" |
85 | return | |
86 | } | |
87 | ||
2899c914 TV |
88 | # Compile the main program for use with the shared object. Note we're using |
89 | # debug, such that "finish out of foo" prints: | |
90 | # Value returned is $1 = (class B *) $hex <g_> | |
91 | # instead of: | |
92 | # Value returned is $1 = (B *) $hex <g_> | |
93 | # Note that this compilation is used for all GDB sessions. | |
94 | set exec_options [list debug shlib=$lib_so] | |
95 | if [prepare_for_testing "failed to prepare" ${testfile} \ | |
96 | ${::srcfile} $exec_options] { | |
97 | return -1 | |
98 | } | |
99 | ||
100 | # Do whatever is necessary to make sure that the shared library is | |
101 | # loaded for remote targets. | |
102 | gdb_load_shlib ${lib_so} | |
103 | ||
a640adf7 | 104 | |
2899c914 | 105 | ### First GDB session. |
a640adf7 | 106 | |
2899c914 TV |
107 | # Run to foo to make sure foo refers to the function, and not foo@PLT. |
108 | if ![runto foo qualified] then { | |
a640adf7 KB |
109 | return |
110 | } | |
111 | ||
2899c914 TV |
112 | with_shared_gdb { |
113 | ||
114 | set session_options $exec_options | |
115 | ||
116 | # Rather than start a new session, declare the current session the | |
117 | # shared one. Otherwise, get_func_info would compile an executable | |
118 | # in a temp dir, which means -Wl,-rpath,\\\$ORIGIN no longer finds | |
119 | # the shared lib. | |
120 | share_gdb ${srcdir}/${subdir}/$srcfile $session_options | |
121 | ||
122 | get_func_info foo $session_options | |
123 | get_func_info bar $session_options | |
124 | ||
125 | # Using our running GDB session, determine sizes of several types. | |
126 | set long_size [get_sizeof "long" -1] | |
127 | set addr_size [get_sizeof "void *" -1] | |
128 | set struct_A_size [get_sizeof "g_A" -1] | |
129 | set struct_B_size [get_sizeof "g_B" -1] | |
130 | ||
131 | # Retrieve struct offset of MBR in struct TP | |
132 | proc get_offsetof { tp mbr } { | |
133 | return [get_integer_valueof "&((${tp} *) 0)->${mbr}" -1] | |
134 | } | |
135 | ||
136 | # Use running GDB session to get struct offsets | |
137 | set A_a [get_offsetof A a] | |
138 | set A_x [get_offsetof A x] | |
139 | set B_a [get_offsetof B a] | |
140 | set B_b [get_offsetof B b] | |
141 | set B_x2 [get_offsetof B x2] | |
a640adf7 KB |
142 | } |
143 | ||
2899c914 TV |
144 | if { $long_size == -1 || $addr_size == -1 \ |
145 | || $struct_A_size == -1 || $struct_B_size == -1} { | |
146 | perror "Can't determine type sizes" | |
147 | return | |
148 | } | |
a640adf7 KB |
149 | |
150 | # Create the DWARF. | |
151 | Dwarf::assemble ${asm_file} { | |
152 | declare_labels L | |
2899c914 TV |
153 | global foo_start foo_end |
154 | global bar_start bar_end | |
155 | global libsrc | |
a640adf7 | 156 | |
3859e65e | 157 | cu { label cu_label } { |
a640adf7 KB |
158 | DW_TAG_compile_unit { |
159 | {DW_AT_language @DW_LANG_C_plus_plus} | |
160 | {name ${::srcfile}} | |
161 | {stmt_list $L DW_FORM_sec_offset} | |
162 | } { | |
163 | declare_labels int_label class_A_label class_B_label \ | |
164 | B_ptr_label | |
165 | ||
166 | int_label: DW_TAG_base_type { | |
167 | {DW_AT_byte_size ${::long_size} DW_FORM_udata} | |
168 | {DW_AT_encoding @DW_ATE_signed} | |
169 | {DW_AT_name "int"} | |
170 | } | |
171 | ||
172 | class_A_label: DW_TAG_class_type { | |
173 | {DW_AT_name "A"} | |
174 | {DW_AT_byte_size ${::struct_A_size} DW_FORM_sdata} | |
175 | } { | |
176 | DW_TAG_member { | |
177 | {DW_AT_name "a"} | |
178 | {DW_AT_type :$int_label} | |
179 | {DW_AT_data_member_location ${::A_a} DW_FORM_udata} | |
180 | } | |
181 | DW_TAG_member { | |
182 | {DW_AT_name "x"} | |
183 | {DW_AT_type :$int_label} | |
184 | {DW_AT_data_member_location ${::A_x} DW_FORM_udata} | |
185 | } | |
186 | } | |
187 | ||
188 | class_B_label: DW_TAG_class_type { | |
189 | {DW_AT_name "B"} | |
190 | {DW_AT_byte_size ${::struct_B_size} DW_FORM_sdata} | |
191 | } { | |
192 | # While there are easier / better ways to specify an | |
193 | # offset used by DW_AT_data_member_location than that | |
194 | # used below, we need a location expression here in | |
195 | # order to reproduce the bug. Moreover, this location | |
196 | # expression needs to use opcodes that aren't handled | |
197 | # by decode_locdesc() in dwarf2/read.c; if we use | |
198 | # opcodes that _are_ handled by that function, the | |
199 | # location expression will be converted into a simple | |
200 | # offset - which will then (again) not reproduce the | |
201 | # bug. At the time that this test was written, | |
202 | # neither DW_OP_pick nor DW_OP_drop were being handled | |
203 | # by decode_locdesc(); this is why those opcodes were | |
204 | # chosen. | |
205 | DW_TAG_inheritance { | |
206 | {DW_AT_type :$class_A_label} | |
207 | {DW_AT_data_member_location { | |
208 | DW_OP_constu ${::B_a} | |
209 | DW_OP_plus | |
210 | DW_OP_pick 0 | |
211 | DW_OP_drop} SPECIAL_expr} | |
212 | {DW_AT_accessibility 1 DW_FORM_data1} | |
213 | } | |
214 | DW_TAG_member { | |
215 | {DW_AT_name "b"} | |
216 | {DW_AT_type :$int_label} | |
217 | {DW_AT_data_member_location ${::B_b} DW_FORM_udata} | |
218 | } | |
219 | DW_TAG_member { | |
220 | {DW_AT_name "x2"} | |
221 | {DW_AT_type :$int_label} | |
222 | {DW_AT_data_member_location ${::B_x2} DW_FORM_udata} | |
223 | } | |
224 | } | |
225 | ||
226 | B_ptr_label: DW_TAG_pointer_type { | |
227 | {DW_AT_type :$class_B_label} | |
228 | {DW_AT_byte_size ${::addr_size} DW_FORM_sdata} | |
229 | } | |
230 | ||
231 | DW_TAG_variable { | |
232 | {DW_AT_name "g_A"} | |
233 | {DW_AT_type :$class_A_label} | |
234 | {DW_AT_external 1 flag} | |
235 | {DW_AT_location {DW_OP_addr [gdb_target_symbol "g_A"]} \ | |
236 | SPECIAL_expr} | |
237 | } | |
238 | ||
239 | DW_TAG_variable { | |
240 | {DW_AT_name "g_B"} | |
241 | {DW_AT_type :$class_B_label} | |
242 | {DW_AT_external 1 flag} | |
243 | {DW_AT_location {DW_OP_addr [gdb_target_symbol "g_B"]} \ | |
244 | SPECIAL_expr} | |
245 | } | |
246 | ||
247 | # We can't use MACRO_AT for the definitions of foo and bar | |
248 | # because it doesn't provide a way to pass the appropriate | |
249 | # flags. Therefore, we list the name, low_pc, and high_pc | |
250 | # explicitly. | |
251 | DW_TAG_subprogram { | |
252 | {DW_AT_name foo} | |
253 | {DW_AT_low_pc $foo_start DW_FORM_addr} | |
254 | {DW_AT_high_pc $foo_end DW_FORM_addr} | |
255 | {DW_AT_type :${B_ptr_label}} | |
256 | {DW_AT_external 1 flag} | |
257 | } | |
258 | ||
259 | DW_TAG_subprogram { | |
260 | {DW_AT_name bar} | |
261 | {DW_AT_low_pc $bar_start DW_FORM_addr} | |
262 | {DW_AT_high_pc $bar_end DW_FORM_addr} | |
263 | {DW_AT_type :${B_ptr_label}} | |
264 | {DW_AT_external 1 flag} | |
265 | } { | |
266 | DW_TAG_formal_parameter { | |
267 | {DW_AT_name v} | |
268 | {DW_AT_type :${B_ptr_label}} | |
269 | } | |
270 | } | |
271 | } | |
272 | } | |
273 | ||
274 | lines {version 2} L { | |
275 | include_dir "${::srcdir}/${::subdir}" | |
2899c914 | 276 | file_name "${::srcfile2}" 1 |
a640adf7 KB |
277 | |
278 | # Generate a line table program. | |
279 | program { | |
d4c4a229 | 280 | DW_LNE_set_address $foo_start |
2899c914 | 281 | line [gdb_get_line_number "foo prologue" $libsrc] |
d4c4a229 SM |
282 | DW_LNS_copy |
283 | DW_LNE_set_address foo_label | |
2899c914 | 284 | line [gdb_get_line_number "foo return" $libsrc] |
d4c4a229 | 285 | DW_LNS_copy |
2899c914 | 286 | line [gdb_get_line_number "foo end" $libsrc] |
d4c4a229 SM |
287 | DW_LNS_copy |
288 | DW_LNE_set_address $foo_end | |
289 | DW_LNS_advance_line 1 | |
290 | DW_LNS_copy | |
291 | DW_LNE_end_sequence | |
a640adf7 | 292 | |
d4c4a229 | 293 | DW_LNE_set_address $bar_start |
2899c914 | 294 | line [gdb_get_line_number "bar prologue" $libsrc] |
d4c4a229 SM |
295 | DW_LNS_copy |
296 | DW_LNE_set_address bar_label | |
2899c914 | 297 | line [gdb_get_line_number "bar return" $libsrc] |
d4c4a229 | 298 | DW_LNS_copy |
2899c914 | 299 | line [gdb_get_line_number "bar end" $libsrc] |
d4c4a229 SM |
300 | DW_LNS_copy |
301 | DW_LNE_set_address $bar_end | |
302 | DW_LNS_advance_line 1 | |
303 | DW_LNS_copy | |
304 | DW_LNE_end_sequence | |
a640adf7 KB |
305 | } |
306 | } | |
3859e65e TV |
307 | |
308 | aranges {} cu_label { | |
1a7c41d5 TT |
309 | # This 0,0 entry tests that the .debug_aranges reader can |
310 | # handle an apparent terminator before the end of the ranges. | |
311 | arange {} 0 0 | |
3859e65e TV |
312 | arange {} $foo_start $foo_end |
313 | arange {} $bar_start $bar_end | |
314 | } | |
a640adf7 KB |
315 | } |
316 | ||
317 | # Compile the shared object again, but this time include / use the | |
2899c914 TV |
318 | # DWARF info that we've created above. Note the use of the "nodebug" option. |
319 | # Any debugging information that we need will be provided by the DWARF info | |
320 | # created above. | |
a640adf7 | 321 | if {[gdb_compile_shlib [list $libsrc $asm_file] $lib_so \ |
2899c914 | 322 | {nodebug}] != ""} { |
a640adf7 KB |
323 | untested "failed to compile shared library" |
324 | return | |
325 | } | |
326 | ||
2899c914 | 327 | ### Second GDB session. |
a640adf7 | 328 | |
2899c914 TV |
329 | clean_restart $binfile |
330 | ||
331 | # Again, do whatever is necessary to make sure that the shared library is | |
a640adf7 KB |
332 | # loaded for remote targets. |
333 | gdb_load_shlib ${lib_so} | |
334 | ||
335 | if ![runto_main] then { | |
a640adf7 KB |
336 | return |
337 | } | |
338 | ||
339 | # Step into foo so that we can finish out of it. | |
340 | gdb_test "step" "foo .. at .* foo end.*" "step into foo" | |
341 | ||
342 | # Finishing out of foo will create a value that will later need to | |
343 | # be preserved when restarting the program. | |
344 | gdb_test "finish" "= \\(class B \\*\\) ${::hex} .*" "finish out of foo" | |
345 | ||
346 | # Dereferencing and printing the return value isn't necessary | |
347 | # for reproducing the bug, but we should make sure that the | |
348 | # return value is what we expect it to be. | |
349 | gdb_test "p *$" { = {<A> = {a = 8, x = 9}, b = 10, x2 = 11}} \ | |
350 | "dereference return value" | |
351 | ||
352 | # The original PR28030 reproducer stepped back into the shared object, | |
353 | # so we'll do the same here: | |
354 | gdb_test "step" "bar \\(.*" "step into bar" | |
355 | ||
2899c914 TV |
356 | |
357 | ### Third GDB session. | |
358 | ||
a640adf7 KB |
359 | # We don't want a clean restart here since that will be too clean. |
360 | # The original reproducer for PR28030 set a breakpoint in the shared | |
361 | # library and then restarted via "run". The command below does roughly | |
362 | # the same thing. It's at this step that an internal error would | |
363 | # occur for PR28030. The "message" argument tells runto to turn on | |
364 | # the printing of PASSes while runto is doing its job. | |
365 | runto "bar" message |