xref: /netbsd-src/external/gpl3/gdb.old/dist/gdb/testsuite/gdb.arch/mips16-thunks.exp (revision 6db267571823ee3b0a1d61478df085a087f2e990)
1# Copyright 2012-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# Contributed by Mentor Graphics, written by Maciej W. Rozycki.
17
18# Test MIPS16 thunk support.
19
20# This should work on any targets that support MIPS16 execution, including
21# Linux and bare-iron ones, but not all of them do, for example MIPS16
22# support has been added to Linux relatively late in the game.  Also besides
23# environment support, the target processor has to support the MIPS16 ASE.
24# Finally as of this writing MIPS16 support has only been implemented in the
25# toolchain for a subset of ABIs, so we need to check that a MIPS16
26# executable can be built and run at all before we attempt the actual test.
27
28if { ![istarget "mips*-*-*"] } then {
29    verbose "Skipping MIPS16 thunk support tests."
30    return
31}
32
33# A helper to set caller's SRCFILE and OBJFILE based on FILENAME and SUFFIX.
34proc set_src_and_obj { filename { suffix "" } } {
35    upvar srcfile srcfile
36    upvar objfile objfile
37    global srcdir
38    global subdir
39
40    if ![string equal "$suffix" ""] then {
41	set suffix "-$suffix"
42    }
43    set srcfile ${srcdir}/${subdir}/${filename}.c
44    set objfile [standard_output_file ${filename}${suffix}.o]
45}
46
47# First check if a trivial MIPS16 program can be built and debugged.  This
48# verifies environment and processor support, any failure here must be
49# classed as the lack of support.
50set testname mips16-thunks-main
51
52set_src_and_obj mips16-thunks-inmain
53set options [list debug nowarnings additional_flags=-mips16]
54set objfiles ${objfile}
55gdb_compile ${srcfile} ${objfile} object ${options}
56
57set_src_and_obj mips16-thunks-main
58set options [list debug nowarnings additional_flags=-mips16]
59lappend objfiles ${objfile}
60gdb_compile ${srcfile} ${objfile} object ${options}
61
62set binfile [standard_output_file ${testname}]
63set options [list debug nowarnings]
64if { [gdb_compile ${objfiles} ${binfile} executable ${options}] != "" } then {
65    unsupported "no MIPS16 support in the toolchain."
66    return
67}
68clean_restart ${testname}
69gdb_breakpoint inmain
70gdb_run_cmd
71gdb_test_multiple "" "check for MIPS16 support in the processor" {
72    -re "Breakpoint 1.*inmain .*$gdb_prompt $" {
73	gdb_test_multiple "finish" \
74	    "check for MIPS16 support in the processor" {
75	    -re "Value returned is \\\$\[0-9\]+ = 0\[^0-9\].*$gdb_prompt $" {
76		verbose "MIPS16 support check successful."
77	    }
78	    -re "$gdb_prompt $" {
79		unsupported "no MIPS16 support in the processor."
80		return
81	    }
82	    default {
83		unsupported "no MIPS16 support in the processor."
84		return
85	    }
86	}
87    }
88    -re "$gdb_prompt $" {
89	unsupported "no MIPS16 support in the processor."
90	return
91    }
92    default {
93	unsupported "no MIPS16 support in the processor."
94	return
95    }
96}
97
98# Check if MIPS16 PIC code can be built and debugged.  We want to check
99# PIC and MIPS16 thunks are handled correctly together if possible, but
100# on targets that do not support PIC code, e.g. bare iron, we still want
101# to test the rest of functionality.
102set testname mips16-thunks-pic
103set picflag ""
104
105set_src_and_obj mips16-thunks-inmain pic
106set options [list \
107    debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
108set objfiles ${objfile}
109gdb_compile ${srcfile} ${objfile} object ${options}
110
111set_src_and_obj mips16-thunks-main pic
112set options [list \
113    debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
114lappend objfiles ${objfile}
115gdb_compile ${srcfile} ${objfile} object ${options}
116
117set binfile [standard_output_file ${testname}]
118set options [list debug nowarnings additional_flags=-fPIC]
119if { [gdb_compile ${objfiles} ${binfile} executable ${options}] == "" } then {
120    clean_restart ${testname}
121    gdb_breakpoint inmain
122    gdb_run_cmd
123    gdb_test_multiple "" "check for PIC support" {
124	-re "Breakpoint 1.*inmain .*$gdb_prompt $" {
125	    note "PIC support present, will make additional PIC thunk checks."
126	    set picflag additional_flags=-fPIC
127	}
128	-re "$gdb_prompt $" {
129	    note "No PIC support, skipping additional PIC thunk checks."
130	}
131	default {
132	    note "No PIC support, skipping additional PIC thunk checks."
133	}
134    }
135} else {
136    note "No PIC support, skipping additional PIC thunk checks."
137}
138
139# OK, build the twisted executable.  This program contains the following
140# MIPS16 thunks:
141# - __call_stub_fp_sin,
142# - __call_stub_fp_sinblah,
143# - __call_stub_fp_sinfrob,
144# - __call_stub_fp_sinhelper,
145# - __call_stub_lsinhelper,
146# - __fn_stub_lsinmips16,
147# - __fn_stub_sinblah16,
148# - __fn_stub_sinfrob16,
149# - __fn_stub_sinmips16,
150# - __mips16_call_stub_df_2,
151# - __mips16_ret_df.
152# Additionally, if PIC code is supported, it contains the following PIC thunks:
153# - .pic.__mips16_call_stub_df_2,
154# - .pic.__mips16_ret_df,
155# - .pic.sinblah,
156# - .pic.sinblah16,
157# - .pic.sinfrob,
158# - .pic.sinfrob16.
159set testname mips16-thunks-sin
160
161set_src_and_obj mips16-thunks-sinmain
162set options [list debug nowarnings additional_flags=-mips16]
163set objfiles ${objfile}
164gdb_compile ${srcfile} ${objfile} object ${options}
165
166set_src_and_obj mips16-thunks-sin
167set options [list debug nowarnings additional_flags=-mno-mips16]
168lappend objfiles ${objfile}
169gdb_compile ${srcfile} ${objfile} object ${options}
170
171set_src_and_obj mips16-thunks-sinmips16
172set options [list debug nowarnings additional_flags=-mips16]
173lappend objfiles ${objfile}
174gdb_compile ${srcfile} ${objfile} object ${options}
175
176set_src_and_obj mips16-thunks-sinfrob
177set options [list \
178    debug nowarnings additional_flags=-mno-mips16 ${picflag}]
179lappend objfiles ${objfile}
180gdb_compile ${srcfile} ${objfile} object ${options}
181
182set_src_and_obj mips16-thunks-sinfrob16
183set options [list \
184    debug nowarnings additional_flags=-mips16 ${picflag}]
185lappend objfiles ${objfile}
186gdb_compile ${srcfile} ${objfile} object ${options}
187
188set binfile [standard_output_file ${testname}]
189set options [list debug nowarnings]
190gdb_compile ${objfiles} ${binfile} executable ${options}
191clean_restart ${testname}
192if ![runto_main] then {
193    fail "running test program, MIPS16 thunk tests aborted"
194    return
195}
196
197# Build some useful regular expressions out of a list of functions FUNCS
198# to be used to match against backtraces.
199proc build_frames_re { funcs } {
200    upvar anyframe anyframe
201    upvar frames frames
202    upvar frame frame
203    upvar func func
204
205    set fid 0
206    set argsandsource " +\\\(.*\\\) +at +\[^\r\n\]+\r\n"
207    set addrin "(?:\[^ \]+ +in +)?"
208    set anyframe "#${fid} +${addrin}(\[^ \]+)${argsandsource}"
209    set frame "#${fid} +${addrin}${func}${argsandsource}"
210    set frames "$frame"
211    foreach f [lrange $funcs 1 end] {
212	incr fid
213	append frames "#${fid} +${addrin}${f}${argsandsource}"
214    }
215}
216
217# Single-step through the function that is at the head of function list
218# FUNCS until a different function (frame) is reached.  Before each step
219# check the backtrace against FUNCS.  ID is used for reporting, to tell
220# apart different calls to this procedure for the same function.  If
221# successful, then return the name of the function we have stopped in.
222proc step_through { id funcs } {
223    global gdb_prompt
224
225    set func [lindex $funcs 0]
226    build_frames_re "$funcs"
227
228    set msg "single-stepping through \"${func}\" ($id)"
229
230    # Arbitrarily limit the maximium number of steps made to avoid looping
231    # indefinitely in the case something goes wrong, increase as (if)
232    # necessary.
233    set count 8
234    while { $count > 0 } {
235	if { [gdb_test_multiple "backtrace" "$msg (backtrace)" {
236	    -re "${frames}$gdb_prompt $" {
237		if { [gdb_test_multiple "step" "$msg (step)" {
238		    -re "$gdb_prompt $" {
239			if { [gdb_test_multiple "frame" "$msg (frame)" {
240			    -re "${frame}.*$gdb_prompt $" {
241			    }
242			    -re "${anyframe}.*$gdb_prompt $" {
243				pass "$msg"
244				return $expect_out(1,string)
245			    }
246			}] != 0 } then {
247			    return ""
248			}
249		    }
250		}] != 0 } then {
251		    return ""
252		}
253	    }
254	}] != 0 } then {
255	    return ""
256	}
257	incr count -1
258    }
259    fail "$msg (too many steps)"
260    return ""
261}
262
263# Finish the current function that must be one that is at the head of
264# function list FUNCS.  Before that check the backtrace against FUNCS.
265# ID is used for reporting, to tell apart different calls to this
266# procedure for the same function.  If successful, then return the name
267# of the function we have stopped in.
268proc finish_through { id funcs } {
269    global gdb_prompt
270
271    set func [lindex $funcs 0]
272    build_frames_re "$funcs"
273
274    set msg "finishing \"${func}\" ($id)"
275
276    gdb_test_multiple "backtrace" "$msg (backtrace)" {
277	-re "${frames}$gdb_prompt $" {
278	    gdb_test_multiple "finish" "$msg (finish)" {
279		-re "Run till exit from ${frame}.*$gdb_prompt $" {
280		    gdb_test_multiple "frame" "$msg (frame)" {
281			-re "${anyframe}.*$gdb_prompt $" {
282			    pass "$msg"
283			    return $expect_out(1,string)
284			}
285		    }
286		}
287	    }
288	}
289    }
290    return ""
291}
292
293# Report PASS if VAL is equal to EXP, otherwise report FAIL, using MSG.
294proc pass_if_eq { val exp msg } {
295    if [string equal "$val" "$exp"] then {
296	pass "$msg"
297    } else {
298	fail "$msg"
299    }
300}
301
302# Check if FUNC is equal to WANT.  If not, then assume that we have stepped
303# into a library call.  In this case finish it, then step out of the caller.
304# ID is used for reporting, to tell apart different calls to this procedure
305# for the same function.  If successful, then return the name of the
306# function we have stopped in.
307proc finish_if_ne { id func want funcs } {
308    if ![string equal "$func" "$want"] then {
309	set call "$func"
310	set want [lindex $funcs 0]
311	set func [finish_through "$id" [linsert $funcs 0 "$func"]]
312	pass_if_eq "$func" "$want" "\"${call}\" finishing to \"${want}\" ($id)"
313	set func [step_through "$id" $funcs]
314    }
315    return "$func"
316}
317
318# Now single-step through the program, making sure all thunks are correctly
319# stepped over and omitted from backtraces.
320
321set id 1
322set func [step_through $id [list main]]
323pass_if_eq "$func" sinfrob16 "stepping from \"main\" into \"sinfrob16\" ($id)"
324
325incr id
326set func [step_through $id [list sinfrob16 main]]
327set func [finish_if_ne $id "$func" main [list sinfrob16 main]]
328pass_if_eq "$func" main "stepping from \"sinfrob16\" back to \"main\" ($id)"
329
330incr id
331set func [step_through $id [list main]]
332pass_if_eq "$func" sinfrob "stepping from \"main\" into \"sinfrob\" ($id)"
333
334incr id
335set func [step_through $id [list sinfrob main]]
336set func [finish_if_ne $id "$func" main [list sinfrob main]]
337pass_if_eq "$func" main "stepping from \"sinfrob\" back to \"main\" ($id)"
338
339# 5
340incr id
341set func [step_through $id [list main]]
342pass_if_eq "$func" sinhelper "stepping from \"main\" into \"sinhelper\" ($id)"
343
344incr id
345set func [step_through $id [list sinhelper main]]
346set func [finish_if_ne $id "$func" sinfrob16 [list sinhelper main]]
347pass_if_eq "$func" sinfrob16 \
348    "stepping from \"sinhelper\" into \"sinfrob16\" ($id)"
349
350incr id
351set func [step_through $id [list sinfrob16 sinhelper main]]
352set func [finish_if_ne $id "$func" sinhelper [list sinfrob16 sinhelper main]]
353pass_if_eq "$func" sinhelper \
354    "stepping from \"sinfrob16\" back to \"sinhelper\" ($id)"
355
356incr id
357set func [step_through $id [list sinhelper main]]
358pass_if_eq "$func" sinfrob "stepping from \"sinhelper\" into \"sinfrob\" ($id)"
359
360incr id
361set func [step_through $id [list sinfrob sinhelper main]]
362set func [finish_if_ne $id "$func" sinhelper [list sinfrob sinhelper main]]
363pass_if_eq "$func" sinhelper \
364    "stepping from \"sinfrob\" back to \"sinhelper\" ($id)"
365
366# 10
367incr id
368set func [step_through $id [list sinhelper main]]
369pass_if_eq "$func" sinmips16 \
370    "stepping from \"sinhelper\" into \"sinmips16\" ($id)"
371
372incr id
373set func [step_through $id [list sinmips16 sinhelper main]]
374set func [finish_if_ne $id "$func" sinfrob16 [list sinmips16 sinhelper main]]
375pass_if_eq "$func" sinfrob16 \
376    "stepping from \"sinmips16\" into \"sinfrob16\" ($id)"
377
378incr id
379set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
380set func [finish_if_ne $id "$func" sinmips16 \
381	      [list sinfrob16 sinmips16 sinhelper main]]
382pass_if_eq "$func" sinmips16 \
383    "stepping from \"sinfrob16\" back to \"sinmips16\" ($id)"
384
385incr id
386set func [step_through $id [list sinmips16 sinhelper main]]
387pass_if_eq "$func" sinfrob "stepping from \"sinmips16\" into \"sinfrob\" ($id)"
388
389incr id
390set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
391set func [finish_if_ne $id "$func" sinhelper \
392	      [list sinfrob sinmips16 sinhelper main]]
393pass_if_eq "$func" sinmips16 \
394    "stepping from \"sinfrob\" back to \"sinmips16\" ($id)"
395
396# 15
397incr id
398set func [step_through $id [list sinmips16 sinhelper main]]
399pass_if_eq "$func" sinfrob16 \
400    "stepping from \"sinmips16\" into \"sinfrob16\" (indirectly) ($id)"
401
402incr id
403set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
404set func [finish_if_ne $id "$func" sinmips16 \
405	      [list sinfrob16 sinmips16 sinhelper main]]
406pass_if_eq "$func" sinmips16 \
407    "stepping from \"sinfrob16\" back to \"sinmips16\" (indirectly) ($id)"
408
409incr id
410set func [step_through $id [list sinmips16 sinhelper main]]
411pass_if_eq "$func" sinfrob \
412    "stepping from \"sinmips16\" into \"sinfrob\" (indirectly) ($id)"
413
414incr id
415set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
416set func [finish_if_ne $id "$func" sinhelper \
417	      [list sinfrob sinmips16 sinhelper main]]
418pass_if_eq "$func" sinmips16 \
419    "stepping from \"sinfrob\" back to \"sinmips16\" (indirectly) ($id)"
420
421incr id
422set func [step_through $id [list sinmips16 sinhelper main]]
423pass_if_eq "$func" sinhelper \
424    "stepping from \"sinmips16\" back to \"sinhelper\" ($id)"
425
426# 20
427incr id
428set func [step_through $id [list sinhelper main]]
429pass_if_eq "$func" main "stepping from \"sinhelper\" back to \"main\" ($id)"
430
431incr id
432set func [step_through $id [list main]]
433pass_if_eq "$func" sinblah "stepping from \"main\" into \"sinblah\" ($id)"
434
435incr id
436set func [step_through $id [list sinblah main]]
437set func [finish_if_ne $id "$func" main [list sinblah main]]
438pass_if_eq "$func" main "stepping from \"sinblah\" back to \"main\" ($id)"
439
440incr id
441set func [step_through $id [list main]]
442pass_if_eq "$func" sinblah16 "stepping from \"main\" into \"sinblah16\" ($id)"
443
444incr id
445set func [step_through $id [list sinblah16 main]]
446set func [finish_if_ne $id "$func" main [list sinblah16 main]]
447pass_if_eq "$func" main "stepping from \"sinblah16\" back to \"main\" ($id)"
448
449# 25
450incr id
451set func [step_through $id [list main]]
452pass_if_eq "$func" lsinhelper \
453    "stepping from \"main\" into \"lsinhelper\" ($id)"
454
455incr id
456set func [step_through $id [list lsinhelper main]]
457set func [finish_if_ne $id "$func" sinblah [list lsinhelper main]]
458pass_if_eq "$func" sinblah \
459    "stepping from \"lsinhelper\" into \"sinblah\" ($id)"
460
461incr id
462set func [step_through $id [list sinblah lsinhelper main]]
463set func [finish_if_ne $id "$func" lsinhelper [list sinblah lsinhelper main]]
464pass_if_eq "$func" lsinhelper \
465    "stepping from \"sinblah\" back to \"lsinhelper\" ($id)"
466
467incr id
468set func [step_through $id [list lsinhelper main]]
469pass_if_eq "$func" sinblah16 \
470    "stepping from \"lsinhelper\" into \"sinblah16\" ($id)"
471
472incr id
473set func [step_through $id [list sinblah16 lsinhelper main]]
474set func [finish_if_ne $id "$func" lsinhelper [list sinblah16 lsinhelper main]]
475pass_if_eq "$func" lsinhelper \
476    "stepping from \"sinblah16\" back to \"lsinhelper\" ($id)"
477
478# 30
479incr id
480set func [step_through $id [list lsinhelper main]]
481pass_if_eq "$func" lsinmips16 \
482    "stepping from \"lsinhelper\" into \"lsinmips16\" ($id)"
483
484incr id
485set func [step_through $id [list lsinmips16 lsinhelper main]]
486set func [finish_if_ne $id "$func" sinblah [list lsinmips16 lsinhelper main]]
487pass_if_eq "$func" sinblah \
488    "stepping from \"lsinmips16\" into \"sinblah\" ($id)"
489
490incr id
491set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
492set func [finish_if_ne $id "$func" lsinmips16 \
493	      [list sinblah lsinmips16 lsinhelper main]]
494pass_if_eq "$func" lsinmips16 \
495    "stepping from \"sinblah\" back to \"lsinmips16\" ($id)"
496
497incr id
498set func [step_through $id [list lsinmips16 lsinhelper main]]
499pass_if_eq "$func" sinblah16 \
500    "stepping from \"lsinmips16\" into \"sinblah16\" ($id)"
501
502incr id
503set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
504set func [finish_if_ne $id "$func" lsinhelper \
505	      [list sinblah16 lsinmips16 lsinhelper main]]
506pass_if_eq "$func" lsinmips16 \
507    "stepping from \"sinblah16\" back to \"lsinmips16\" ($id)"
508
509# 35
510incr id
511set func [step_through $id [list lsinmips16 lsinhelper main]]
512pass_if_eq "$func" sinblah \
513    "stepping from \"lsinmips16\" into \"sinblah\" (indirectly) ($id)"
514
515incr id
516set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
517set func [finish_if_ne $id "$func" lsinmips16 \
518	      [list sinblah lsinmips16 lsinhelper main]]
519pass_if_eq "$func" lsinmips16 \
520    "stepping from \"sinblah\" back to \"lsinmips16\" (indirectly) ($id)"
521
522incr id
523set func [step_through $id [list lsinmips16 lsinhelper main]]
524pass_if_eq "$func" sinblah16 \
525    "stepping from \"lsinmips16\" into \"sinblah16\" (indirectly) ($id)"
526
527incr id
528set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
529set func [finish_if_ne $id "$func" lsinhelper \
530	      [list sinblah16 lsinmips16 lsinhelper main]]
531pass_if_eq "$func" lsinmips16 \
532    "stepping from \"sinblah16\" back to \"lsinmips16\" (indirectly) ($id)"
533
534incr id
535set func [step_through $id [list lsinmips16 lsinhelper main]]
536pass_if_eq "$func" lsinhelper \
537    "stepping from \"lsinmips16\" back to \"lsinhelper\" ($id)"
538
539# 40
540incr id
541set func [step_through $id [list lsinhelper main]]
542pass_if_eq "$func" main "stepping from \"lsinhelper\" back to \"main\" ($id)"
543