1# Copyright 2002-2020 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 file was written by Michael Snyder (msnyder@redhat.com)
17# This is a test for the gdb command "dump".
18
19
20standard_testfile
21
22set options  {debug}
23
24set is64bitonly "no"
25set endian "auto"
26
27if [istarget "alpha*-*-*"] then {
28    # SREC etc cannot handle 64-bit addresses.  Force the test
29    # program into the low 31 bits of the address space.
30    lappend options "additional_flags=-Wl,-taso"
31}
32
33# Runs the command 'print zero_all ()'.  Uses the PRINT_ZERO_ALL_COUNT
34# global to ensure the test names are unique.
35set print_zero_all_count 0
36proc print_zero_all { } {
37    global print_zero_all_count
38
39    incr print_zero_all_count
40    gdb_test "print zero_all ()" " = void" \
41	"call ${print_zero_all_count} to zero_all function"
42}
43
44# Debian9/Ubuntu16.10 onwards default to PIE enabled. Ensure it is disabled as
45# this causes addresses to be out of range for IHEX.
46lappend options {nopie}
47
48if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable ${options}] != "" } {
49     untested "failed to compile"
50     return -1
51}
52
53# Start with a fresh gdb.
54
55gdb_exit
56gdb_start
57gdb_reinitialize_dir $srcdir/$subdir
58
59gdb_test "dump mem /dev/null 0x10 0x20" "Cannot access memory at address 0x10" \
60	 "inaccessible memory is reported"
61
62gdb_load ${binfile}
63
64# Check the address of a variable.  If it is bigger than 32-bit,
65# assume our target has 64-bit addresses that are not supported by SREC,
66# IHEX and TEKHEX.  We skip those tests then.
67set max_32bit_address "0xffffffff"
68set data_address [get_hexadecimal_valueof "&intarray" 0x100000000]
69if {${data_address} > ${max_32bit_address}} then {
70    set is64bitonly "yes"
71}
72
73# Clean up any stale output files from previous test runs
74
75set filenames {}
76set all_files {
77    intarr1.bin intarr1b.bin intarr1.ihex
78    intarr1.srec intarr1.tekhex intarr1.verilog
79    intarr2.bin intarr2b.bin intarr2.ihex
80    intarr2.srec intarr2.tekhex intarr2.verilog
81    intstr1.bin intstr1b.bin intstr1.ihex
82    intstr1.srec intstr1.tekhex intstr1.verilog
83    intstr2.bin intstr2b.bin intstr2.ihex
84    intstr2.srec intstr2.tekhex intstr2.verilog
85    intarr3.srec
86}
87
88# This loop sets variables dynamically -- each name listed in
89# $ALL_FILES is both a file name and a variable name.
90foreach file $all_files {
91    if {[is_remote host]} {
92	set this_name $file
93    } else {
94	set this_name [standard_output_file $file]
95    }
96
97    lappend filenames [set ${file} $this_name]
98}
99
100remote_exec host "rm -f $filenames"
101
102# Test help (FIXME:)
103
104# Run target program until data structs are initialized.
105
106if { ! [ runto checkpoint1 ] } then {
107    untested "couldn't run to checkpoint"
108    return -1
109}
110
111# Get the endianness for the later use with endianless formats.
112
113set endian [get_endianness]
114
115# Now generate some dump files.
116
117proc make_dump_file { command msg } {
118  global gdb_prompt
119
120    gdb_test_multiple "${command}" "$msg" {
121	-re ".*\[Ee\]rror.*$gdb_prompt $"      { fail $msg }
122	-re ".*\[Ww\]arning.*$gdb_prompt $"    { fail $msg }
123	-re ".*\[Uu\]ndefined .*$gdb_prompt $" { fail $msg }
124	-re ".*$gdb_prompt $"                  { pass $msg }
125    }
126}
127
128make_dump_file "dump val [set intarr1.bin] intarray" \
129	"dump array as value, default"
130
131make_dump_file "dump val [set intstr1.bin] intstruct" \
132	"dump struct as value, default"
133
134make_dump_file "dump bin val [set intarr1b.bin] intarray" \
135	"dump array as value, binary"
136
137make_dump_file "dump bin val [set intstr1b.bin] intstruct" \
138	"dump struct as value, binary"
139
140make_dump_file "dump srec val [set intarr1.srec] intarray" \
141	"dump array as value, srec"
142
143make_dump_file "dump srec val [set intstr1.srec] intstruct" \
144	"dump struct as value, srec"
145
146make_dump_file "dump ihex val [set intarr1.ihex] intarray" \
147	"dump array as value, intel hex"
148
149make_dump_file "dump ihex val [set intstr1.ihex] intstruct" \
150	"dump struct as value, intel hex"
151
152make_dump_file "dump tekhex val [set intarr1.tekhex] intarray" \
153	"dump array as value, tekhex"
154
155make_dump_file "dump tekhex val [set intstr1.tekhex] intstruct" \
156	"dump struct as value, tekhex"
157
158make_dump_file "dump verilog val [set intarr1.verilog] intarray" \
159	"dump array as value, verilog"
160
161make_dump_file "dump verilog val [set intstr1.verilog] intstruct" \
162	"dump struct as value, verilog"
163
164proc capture_value { expression args } {
165    global gdb_prompt
166    global expect_out
167
168    set output_string ""
169    if {[llength $args] > 0} {
170	# Convert $args into a simple string and don't use EXPRESSION
171	# in the test name.
172	set test "[join $args]; capture"
173    } {
174	set test "capture $expression"
175    }
176    gdb_test_multiple "print ${expression}" "$test" {
177	-re "\\$\[0-9\]+ = (\[^\r\n\]+).*$gdb_prompt $" {
178	    set output_string "$expect_out(1,string)"
179	    pass "$test"
180	}
181	-re "(Cannot access memory at address \[^\r\n\]+).*$gdb_prompt $" {
182	    # Even a failed value is valid
183	    set output_string "$expect_out(1,string)"
184	    pass "$test"
185	}
186    }
187    return $output_string
188}
189
190# POINTER is a pointer and this proc captures the value of POINTER along
191# with POINTER's type.  For example, POINTER is "&intarray", this proc will
192# call "p &intarray", capture "(int (*)[32]) 0x804a0e0", and return this
193# string.
194
195proc capture_pointer_with_type { pointer } {
196    global gdb_prompt
197    global expect_out
198
199    set test "capture type of pointer $pointer"
200    set output_string ""
201    gdb_test_multiple "p ${pointer}" $test {
202	-re "\\$\[0-9\]+ = .*$gdb_prompt $" {
203	    # Expected output of "p ${pointer}" is like "$7 = (int (*)[32]) 0x804a0e0",
204	    # and we want to extract "(int (*)[32]) 0x804a0e0" from it via
205	    # following regexp.
206	    if [regexp " \\(.*\\).* 0x\[0-9a-fA-F\]+" $expect_out(0,string) output_string] {
207		# OUTPUT_STRING is expected to be like "(int (*)[32]) 0x804a0e0".
208		pass "$test"
209	    } else {
210		fail "$test"
211	    }
212	}
213    }
214
215    return $output_string
216}
217
218set array_start  [capture_value "/x &intarray\[0\]"]
219set array_end    [capture_value "/x &intarray\[32\]"]
220set struct_start [capture_value "/x &intstruct"]
221set struct_end   [capture_value "/x &intstruct + 1"]
222
223set array_val    [capture_value "intarray"]
224set struct_val   [capture_value "intstruct"]
225
226set array_ptr_type [capture_pointer_with_type "&intarray"]
227set struct_ptr_type [capture_pointer_with_type "&intstruct"]
228
229make_dump_file "dump mem [set intarr2.bin] $array_start $array_end" \
230	"dump array as memory, default"
231
232make_dump_file "dump  mem [set intstr2.bin] $struct_start $struct_end" \
233	"dump struct as memory, default"
234
235make_dump_file "dump bin mem [set intarr2b.bin] $array_start $array_end" \
236	"dump array as memory, binary"
237
238make_dump_file "dump bin mem [set intstr2b.bin] $struct_start $struct_end" \
239	"dump struct as memory, binary"
240
241make_dump_file "dump srec mem [set intarr2.srec] $array_start $array_end" \
242	"dump array as memory, srec"
243
244make_dump_file "dump srec mem [set intstr2.srec] $struct_start $struct_end" \
245	"dump struct as memory, srec"
246
247make_dump_file "dump ihex mem [set intarr2.ihex] $array_start $array_end" \
248	"dump array as memory, ihex"
249
250make_dump_file "dump ihex mem [set intstr2.ihex] $struct_start $struct_end" \
251	"dump struct as memory, ihex"
252
253make_dump_file "dump tekhex mem [set intarr2.tekhex] $array_start $array_end" \
254	"dump array as memory, tekhex"
255
256make_dump_file "dump tekhex mem [set intstr2.tekhex] $struct_start $struct_end" \
257	"dump struct as memory, tekhex"
258
259make_dump_file "dump verilog mem [set intarr2.verilog] $array_start $array_end" \
260	"dump array as memory, verilog"
261
262make_dump_file "dump verilog mem [set intstr2.verilog] $struct_start $struct_end" \
263	"dump struct as memory, verilog"
264
265# test complex expressions
266make_dump_file \
267    "dump srec mem [set intarr3.srec] &intarray \(char *\) &intarray + sizeof intarray" \
268	"dump array as mem, srec, expressions"
269
270proc test_restore_saved_value { restore_args msg oldval newval } {
271    global gdb_prompt
272
273    gdb_test "restore $restore_args" \
274	"Restoring .*" \
275	"$msg; file restored ok"
276    if { ![string compare $oldval \
277	       [capture_value $newval "$msg"]] } then {
278	pass "$msg; value restored ok"
279    } else {
280	fail "$msg; value restored ok"
281    }
282}
283
284if ![string compare $is64bitonly "no"] then {
285
286
287  test_restore_saved_value "[set intarr1.srec]" "array as value, srec" \
288	$array_val "intarray"
289
290  test_restore_saved_value "[set intstr1.srec]" "struct as value, srec" \
291	$struct_val "intstruct"
292
293  print_zero_all
294
295  test_restore_saved_value "[set intarr2.srec]" "array as memory, srec" \
296	$array_val "intarray"
297
298  test_restore_saved_value "[set intstr2.srec]" "struct as memory, srec" \
299	$struct_val "intstruct"
300
301  print_zero_all
302
303  test_restore_saved_value "[set intarr1.ihex]" "array as value, ihex" \
304	$array_val "intarray"
305
306  test_restore_saved_value "[set intstr1.ihex]" "struct as value, ihex" \
307	$struct_val "intstruct"
308
309  print_zero_all
310
311  test_restore_saved_value "[set intarr2.ihex]" "array as memory, ihex" \
312	$array_val "intarray"
313
314  test_restore_saved_value "[set intstr2.ihex]" "struct as memory, ihex" \
315	$struct_val "intstruct"
316
317  print_zero_all
318
319  test_restore_saved_value "[set intarr1.tekhex]" "array as value, tekhex" \
320	$array_val "intarray"
321
322  test_restore_saved_value "[set intstr1.tekhex]" "struct as value, tekhex" \
323	$struct_val "intstruct"
324
325  print_zero_all
326
327  test_restore_saved_value "[set intarr2.tekhex]" "array as memory, tekhex" \
328	$array_val "intarray"
329
330  test_restore_saved_value "[set intstr2.tekhex]" "struct as memory, tekhex" \
331	$struct_val "intstruct"
332}
333
334print_zero_all
335
336test_restore_saved_value "[set intarr1.bin] binary $array_start" \
337	"array as value, binary" \
338	$array_val "intarray"
339
340test_restore_saved_value "[set intstr1.bin] binary $struct_start" \
341	"struct as value, binary" \
342	$struct_val "intstruct"
343
344print_zero_all
345
346test_restore_saved_value "[set intarr2.bin] binary $array_start" \
347	"array as memory, binary" \
348	$array_val "intarray"
349
350test_restore_saved_value "[set intstr2.bin] binary $struct_start" \
351	"struct as memory, binary" \
352	$struct_val "intstruct"
353
354# test restore with offset.
355
356set array2_start   [capture_value "/x &intarray2\[0\]"]
357set struct2_start  [capture_value "/x &intstruct2"]
358set array2_offset  \
359	[capture_value "(char *) &intarray2 - (char *) &intarray"]
360set struct2_offset \
361	[capture_value "(char *) &intstruct2 - (char *) &intstruct"]
362
363print_zero_all
364
365
366if ![string compare $is64bitonly "no"] then {
367  test_restore_saved_value "[set intarr1.srec] $array2_offset" \
368	"array copy, srec" \
369	$array_val "intarray2"
370
371  test_restore_saved_value "[set intstr1.srec] $struct2_offset" \
372	"struct copy, srec" \
373	$struct_val "intstruct2"
374
375  print_zero_all
376
377  test_restore_saved_value "[set intarr1.ihex] $array2_offset" \
378	"array copy, ihex" \
379	$array_val "intarray2"
380
381  test_restore_saved_value "[set intstr1.ihex] $struct2_offset" \
382	"struct copy, ihex" \
383	$struct_val "intstruct2"
384
385  print_zero_all
386
387  test_restore_saved_value "[set intarr1.tekhex] $array2_offset" \
388	"array copy, tekhex" \
389	$array_val "intarray2"
390
391  test_restore_saved_value "[set intstr1.tekhex] $struct2_offset" \
392	"struct copy, tekhex" \
393	$struct_val "intstruct2"
394}
395
396print_zero_all
397
398test_restore_saved_value "[set intarr1.bin] binary $array2_start" \
399	"array copy, binary" \
400	$array_val "intarray2"
401
402test_restore_saved_value "[set intstr1.bin] binary $struct2_start" \
403	"struct copy, binary" \
404	$struct_val "intstruct2"
405
406#
407# test restore with start/stop addresses.
408#
409# For this purpose, we will restore just the third element of the array,
410# and check to see that adjacent elements are not modified.
411#
412# We will need the address and offset of the third and fourth elements.
413#
414
415set element3_start  [capture_value "/x &intarray\[3\]"]
416set element4_start  [capture_value "/x &intarray\[4\]"]
417set element3_offset \
418	[capture_value "/x (char *) &intarray\[3\] - (char *) &intarray\[0\]"]
419set element4_offset \
420	[capture_value "/x (char *) &intarray\[4\] - (char *) &intarray\[0\]"]
421
422if ![string compare $is64bitonly "no"] then {
423  print_zero_all
424
425  test_restore_saved_value "[set intarr1.srec] 0 $element3_start $element4_start" \
426	"array partial, srec" 4 "intarray\[3\]"
427
428  gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 1"
429  gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 1"
430
431  print_zero_all
432
433  test_restore_saved_value "[set intarr1.ihex] 0 $element3_start $element4_start" \
434	"array partial, ihex" 4 "intarray\[3\]"
435
436  gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 2"
437  gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 2"
438
439  print_zero_all
440
441  test_restore_saved_value "[set intarr1.tekhex] 0 $element3_start $element4_start" \
442	"array partial, tekhex" 4 "intarray\[3\]"
443
444  gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 3"
445  gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 3"
446}
447
448print_zero_all
449
450test_restore_saved_value \
451    "[set intarr1.bin] binary $array_start $element3_offset $element4_offset" \
452    "array partial, binary" 4 "intarray\[3\]"
453
454gdb_test "print intarray\[2\] == 0" " = 1" "element 2 not changed - 4"
455gdb_test "print intarray\[4\] == 0" " = 1" "element 4 not changed - 4"
456
457if ![string compare $is64bitonly "no"] then {
458  print_zero_all
459
460  # restore with expressions
461  test_restore_saved_value \
462	"[set intarr3.srec] (char*)${array2_start}-(char*)${array_start} &intarray\[3\] &intarray\[4\]" \
463	"array partial with expressions" 4 "intarray2\[3\]"
464
465  gdb_test "print intarray2\[2\] == 0" " = 1" "element 2 not changed, == 4"
466  gdb_test "print intarray2\[4\] == 0" " = 1" "element 4 not changed, == 4"
467}
468
469
470# Now start a fresh gdb session, and reload the saved value files.
471
472gdb_exit
473gdb_start
474gdb_file_cmd ${binfile}
475
476# Now fix the endianness at the correct state.
477
478gdb_test_multiple "set endian $endian" "set endianness" {
479    -re ".* (big|little) endian.*$gdb_prompt $" {
480	pass "setting $endian endianness"
481    }
482}
483
484# Reload saved values one by one, and compare.
485
486if { ![string compare $array_val \
487	   [capture_value "intarray" "file binfile; intarray"]] } then {
488    fail "start with intarray un-initialized"
489} else {
490    pass "start with intarray un-initialized"
491}
492
493if { ![string compare $struct_val \
494	   [capture_value "intstruct" "file binfile; intstruct"]] } then {
495    fail "start with intstruct un-initialized"
496} else {
497    pass "start with intstruct un-initialized"
498}
499
500proc test_reload_saved_value { filename msg oldval newval } {
501    global gdb_prompt
502
503    gdb_file_cmd $filename
504    if { ![string compare $oldval \
505	       [capture_value $newval "$msg"]] } then {
506	pass "$msg; value restored ok"
507    } else {
508	fail "$msg; value restored ok"
509    }
510}
511
512# srec format can not be loaded for 64-bit-only platforms
513if ![string compare $is64bitonly "no"] then {
514  test_reload_saved_value "[set intarr1.srec]" "reload array as value, srec" \
515	$array_val "\*$array_ptr_type"
516  test_reload_saved_value "[set intstr1.srec]" "reload struct as value, srec" \
517	$struct_val "\*$struct_ptr_type"
518  test_reload_saved_value "[set intarr2.srec]" "reload array as memory, srec" \
519	$array_val "\*$array_ptr_type"
520  test_reload_saved_value "[set intstr2.srec]" "reload struct as memory, srec" \
521	$struct_val "\*$struct_ptr_type"
522}
523
524# ihex format can not be loaded for 64-bit-only platforms
525if ![string compare $is64bitonly "no"] then {
526
527  test_reload_saved_value "[set intarr1.ihex]" \
528      "reload array as value, intel hex" \
529	$array_val "\*$array_ptr_type"
530  test_reload_saved_value "[set intstr1.ihex]" \
531      "reload struct as value, intel hex" \
532	$struct_val "\*$struct_ptr_type"
533  test_reload_saved_value "[set intarr2.ihex]" \
534      "reload array as memory, intel hex" \
535	$array_val "\*$array_ptr_type"
536  test_reload_saved_value "[set intstr2.ihex]" \
537      "reload struct as memory, intel hex" \
538	$struct_val "\*$struct_ptr_type"
539}
540
541# tekhex format can not be loaded for 64-bit-only platforms
542if ![string compare $is64bitonly "no"] then {
543  test_reload_saved_value "[set intarr1.tekhex]" \
544      "reload array as value, tekhex" \
545	$array_val "\*$array_ptr_type"
546  test_reload_saved_value "[set intstr1.tekhex]" \
547      "reload struct as value, tekhex" \
548	$struct_val "\*$struct_ptr_type"
549  test_reload_saved_value "[set intarr2.tekhex]" \
550      "reload array as memory, tekhex" \
551	$array_val "\*$array_ptr_type"
552  test_reload_saved_value "[set intstr2.tekhex]" \
553      "reload struct as memory, tekhex" \
554	$struct_val "\*$struct_ptr_type"
555}
556
557# clean up files
558
559remote_exec host "rm -f $filenames"
560