1 # Copyright 2012-2019 Free Software Foundation, Inc.
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.
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.
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/>.
16 # Contributed by Mentor Graphics, written by Maciej W. Rozycki.
18 # Test MIPS16 thunk support.
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.
28 if { ![istarget "mips*-*-*"] } then {
29 verbose "Skipping MIPS16 thunk support tests."
33 # A helper to set caller's SRCFILE and OBJFILE based on FILENAME and SUFFIX.
34 proc set_src_and_obj { filename { suffix "" } } {
40 if ![string equal "$suffix" ""] then {
43 set srcfile ${srcdir}/${subdir}/${filename}.c
44 set objfile [standard_output_file ${filename}${suffix}.o]
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.
50 set testname mips16-thunks-main
52 set_src_and_obj mips16-thunks-inmain
53 set options [list debug nowarnings additional_flags=-mips16]
54 set objfiles ${objfile}
55 gdb_compile ${srcfile} ${objfile} object ${options}
57 set_src_and_obj mips16-thunks-main
58 set options [list debug nowarnings additional_flags=-mips16]
59 lappend objfiles ${objfile}
60 gdb_compile ${srcfile} ${objfile} object ${options}
62 set binfile [standard_output_file ${testname}]
63 set options [list debug nowarnings]
64 if { [gdb_compile ${objfiles} ${binfile} executable ${options}] != "" } then {
65 unsupported "no MIPS16 support in the toolchain."
68 clean_restart ${testname}
71 gdb_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."
79 unsupported "no MIPS16 support in the processor."
83 unsupported "no MIPS16 support in the processor."
89 unsupported "no MIPS16 support in the processor."
93 unsupported "no MIPS16 support in the processor."
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.
102 set testname mips16-thunks-pic
105 set_src_and_obj mips16-thunks-inmain pic
107 debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
108 set objfiles ${objfile}
109 gdb_compile ${srcfile} ${objfile} object ${options}
111 set_src_and_obj mips16-thunks-main pic
113 debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
114 lappend objfiles ${objfile}
115 gdb_compile ${srcfile} ${objfile} object ${options}
117 set binfile [standard_output_file ${testname}]
118 set options [list debug nowarnings additional_flags=-fPIC]
119 if { [gdb_compile ${objfiles} ${binfile} executable ${options}] == "" } then {
120 clean_restart ${testname}
121 gdb_breakpoint inmain
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
128 -re "$gdb_prompt $" {
129 note "No PIC support, skipping additional PIC thunk checks."
132 note "No PIC support, skipping additional PIC thunk checks."
136 note "No PIC support, skipping additional PIC thunk checks."
139 # OK, build the twisted executable. This program contains the following
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,
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,
159 set testname mips16-thunks-sin
161 set_src_and_obj mips16-thunks-sinmain
162 set options [list debug nowarnings additional_flags=-mips16]
163 set objfiles ${objfile}
164 gdb_compile ${srcfile} ${objfile} object ${options}
166 set_src_and_obj mips16-thunks-sin
167 set options [list debug nowarnings additional_flags=-mno-mips16]
168 lappend objfiles ${objfile}
169 gdb_compile ${srcfile} ${objfile} object ${options}
171 set_src_and_obj mips16-thunks-sinmips16
172 set options [list debug nowarnings additional_flags=-mips16]
173 lappend objfiles ${objfile}
174 gdb_compile ${srcfile} ${objfile} object ${options}
176 set_src_and_obj mips16-thunks-sinfrob
178 debug nowarnings additional_flags=-mno-mips16 ${picflag}]
179 lappend objfiles ${objfile}
180 gdb_compile ${srcfile} ${objfile} object ${options}
182 set_src_and_obj mips16-thunks-sinfrob16
184 debug nowarnings additional_flags=-mips16 ${picflag}]
185 lappend objfiles ${objfile}
186 gdb_compile ${srcfile} ${objfile} object ${options}
188 set binfile [standard_output_file ${testname}]
189 set options [list debug nowarnings]
190 gdb_compile ${objfiles} ${binfile} executable ${options}
191 clean_restart ${testname}
192 if ![runto_main] then {
193 fail "running test program, MIPS16 thunk tests aborted"
197 # Build some useful regular expressions out of a list of functions FUNCS
198 # to be used to match against backtraces.
199 proc build_frames_re { funcs } {
200 upvar anyframe anyframe
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}"
211 foreach f [lrange $funcs 1 end] {
213 append frames "#${fid} +${addrin}${f}${argsandsource}"
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.
222 proc step_through { id funcs } {
225 set func [lindex $funcs 0]
226 build_frames_re "$funcs"
228 set msg "single-stepping through \"${func}\" ($id)"
230 # Arbitrarily limit the maximium number of steps made to avoid looping
231 # indefinitely in the case something goes wrong, increase as (if)
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 $" {
242 -re "${anyframe}.*$gdb_prompt $" {
244 return $expect_out(1,string)
259 fail "$msg (too many steps)"
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.
268 proc finish_through { id funcs } {
271 set func [lindex $funcs 0]
272 build_frames_re "$funcs"
274 set msg "finishing \"${func}\" ($id)"
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 $" {
283 return $expect_out(1,string)
293 # Report PASS if VAL is equal to EXP, otherwise report FAIL, using MSG.
294 proc pass_if_eq { val exp msg } {
295 if [string equal "$val" "$exp"] then {
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.
307 proc finish_if_ne { id func want funcs } {
308 if ![string equal "$func" "$want"] then {
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]
318 # Now single-step through the program, making sure all thunks are correctly
319 # stepped over and omitted from backtraces.
322 set func [step_through $id [list main]]
323 pass_if_eq "$func" sinfrob16 "stepping from \"main\" into \"sinfrob16\" ($id)"
326 set func [step_through $id [list sinfrob16 main]]
327 set func [finish_if_ne $id "$func" main [list sinfrob16 main]]
328 pass_if_eq "$func" main "stepping from \"sinfrob16\" back to \"main\" ($id)"
331 set func [step_through $id [list main]]
332 pass_if_eq "$func" sinfrob "stepping from \"main\" into \"sinfrob\" ($id)"
335 set func [step_through $id [list sinfrob main]]
336 set func [finish_if_ne $id "$func" main [list sinfrob main]]
337 pass_if_eq "$func" main "stepping from \"sinfrob\" back to \"main\" ($id)"
341 set func [step_through $id [list main]]
342 pass_if_eq "$func" sinhelper "stepping from \"main\" into \"sinhelper\" ($id)"
345 set func [step_through $id [list sinhelper main]]
346 set func [finish_if_ne $id "$func" sinfrob16 [list sinhelper main]]
347 pass_if_eq "$func" sinfrob16 \
348 "stepping from \"sinhelper\" into \"sinfrob16\" ($id)"
351 set func [step_through $id [list sinfrob16 sinhelper main]]
352 set func [finish_if_ne $id "$func" sinhelper [list sinfrob16 sinhelper main]]
353 pass_if_eq "$func" sinhelper \
354 "stepping from \"sinfrob16\" back to \"sinhelper\" ($id)"
357 set func [step_through $id [list sinhelper main]]
358 pass_if_eq "$func" sinfrob "stepping from \"sinhelper\" into \"sinfrob\" ($id)"
361 set func [step_through $id [list sinfrob sinhelper main]]
362 set func [finish_if_ne $id "$func" sinhelper [list sinfrob sinhelper main]]
363 pass_if_eq "$func" sinhelper \
364 "stepping from \"sinfrob\" back to \"sinhelper\" ($id)"
368 set func [step_through $id [list sinhelper main]]
369 pass_if_eq "$func" sinmips16 \
370 "stepping from \"sinhelper\" into \"sinmips16\" ($id)"
373 set func [step_through $id [list sinmips16 sinhelper main]]
374 set func [finish_if_ne $id "$func" sinfrob16 [list sinmips16 sinhelper main]]
375 pass_if_eq "$func" sinfrob16 \
376 "stepping from \"sinmips16\" into \"sinfrob16\" ($id)"
379 set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
380 set func [finish_if_ne $id "$func" sinmips16 \
381 [list sinfrob16 sinmips16 sinhelper main]]
382 pass_if_eq "$func" sinmips16 \
383 "stepping from \"sinfrob16\" back to \"sinmips16\" ($id)"
386 set func [step_through $id [list sinmips16 sinhelper main]]
387 pass_if_eq "$func" sinfrob "stepping from \"sinmips16\" into \"sinfrob\" ($id)"
390 set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
391 set func [finish_if_ne $id "$func" sinhelper \
392 [list sinfrob sinmips16 sinhelper main]]
393 pass_if_eq "$func" sinmips16 \
394 "stepping from \"sinfrob\" back to \"sinmips16\" ($id)"
398 set func [step_through $id [list sinmips16 sinhelper main]]
399 pass_if_eq "$func" sinfrob16 \
400 "stepping from \"sinmips16\" into \"sinfrob16\" (indirectly) ($id)"
403 set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
404 set func [finish_if_ne $id "$func" sinmips16 \
405 [list sinfrob16 sinmips16 sinhelper main]]
406 pass_if_eq "$func" sinmips16 \
407 "stepping from \"sinfrob16\" back to \"sinmips16\" (indirectly) ($id)"
410 set func [step_through $id [list sinmips16 sinhelper main]]
411 pass_if_eq "$func" sinfrob \
412 "stepping from \"sinmips16\" into \"sinfrob\" (indirectly) ($id)"
415 set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
416 set func [finish_if_ne $id "$func" sinhelper \
417 [list sinfrob sinmips16 sinhelper main]]
418 pass_if_eq "$func" sinmips16 \
419 "stepping from \"sinfrob\" back to \"sinmips16\" (indirectly) ($id)"
422 set func [step_through $id [list sinmips16 sinhelper main]]
423 pass_if_eq "$func" sinhelper \
424 "stepping from \"sinmips16\" back to \"sinhelper\" ($id)"
428 set func [step_through $id [list sinhelper main]]
429 pass_if_eq "$func" main "stepping from \"sinhelper\" back to \"main\" ($id)"
432 set func [step_through $id [list main]]
433 pass_if_eq "$func" sinblah "stepping from \"main\" into \"sinblah\" ($id)"
436 set func [step_through $id [list sinblah main]]
437 set func [finish_if_ne $id "$func" main [list sinblah main]]
438 pass_if_eq "$func" main "stepping from \"sinblah\" back to \"main\" ($id)"
441 set func [step_through $id [list main]]
442 pass_if_eq "$func" sinblah16 "stepping from \"main\" into \"sinblah16\" ($id)"
445 set func [step_through $id [list sinblah16 main]]
446 set func [finish_if_ne $id "$func" main [list sinblah16 main]]
447 pass_if_eq "$func" main "stepping from \"sinblah16\" back to \"main\" ($id)"
451 set func [step_through $id [list main]]
452 pass_if_eq "$func" lsinhelper \
453 "stepping from \"main\" into \"lsinhelper\" ($id)"
456 set func [step_through $id [list lsinhelper main]]
457 set func [finish_if_ne $id "$func" sinblah [list lsinhelper main]]
458 pass_if_eq "$func" sinblah \
459 "stepping from \"lsinhelper\" into \"sinblah\" ($id)"
462 set func [step_through $id [list sinblah lsinhelper main]]
463 set func [finish_if_ne $id "$func" lsinhelper [list sinblah lsinhelper main]]
464 pass_if_eq "$func" lsinhelper \
465 "stepping from \"sinblah\" back to \"lsinhelper\" ($id)"
468 set func [step_through $id [list lsinhelper main]]
469 pass_if_eq "$func" sinblah16 \
470 "stepping from \"lsinhelper\" into \"sinblah16\" ($id)"
473 set func [step_through $id [list sinblah16 lsinhelper main]]
474 set func [finish_if_ne $id "$func" lsinhelper [list sinblah16 lsinhelper main]]
475 pass_if_eq "$func" lsinhelper \
476 "stepping from \"sinblah16\" back to \"lsinhelper\" ($id)"
480 set func [step_through $id [list lsinhelper main]]
481 pass_if_eq "$func" lsinmips16 \
482 "stepping from \"lsinhelper\" into \"lsinmips16\" ($id)"
485 set func [step_through $id [list lsinmips16 lsinhelper main]]
486 set func [finish_if_ne $id "$func" sinblah [list lsinmips16 lsinhelper main]]
487 pass_if_eq "$func" sinblah \
488 "stepping from \"lsinmips16\" into \"sinblah\" ($id)"
491 set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
492 set func [finish_if_ne $id "$func" lsinmips16 \
493 [list sinblah lsinmips16 lsinhelper main]]
494 pass_if_eq "$func" lsinmips16 \
495 "stepping from \"sinblah\" back to \"lsinmips16\" ($id)"
498 set func [step_through $id [list lsinmips16 lsinhelper main]]
499 pass_if_eq "$func" sinblah16 \
500 "stepping from \"lsinmips16\" into \"sinblah16\" ($id)"
503 set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
504 set func [finish_if_ne $id "$func" lsinhelper \
505 [list sinblah16 lsinmips16 lsinhelper main]]
506 pass_if_eq "$func" lsinmips16 \
507 "stepping from \"sinblah16\" back to \"lsinmips16\" ($id)"
511 set func [step_through $id [list lsinmips16 lsinhelper main]]
512 pass_if_eq "$func" sinblah \
513 "stepping from \"lsinmips16\" into \"sinblah\" (indirectly) ($id)"
516 set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
517 set func [finish_if_ne $id "$func" lsinmips16 \
518 [list sinblah lsinmips16 lsinhelper main]]
519 pass_if_eq "$func" lsinmips16 \
520 "stepping from \"sinblah\" back to \"lsinmips16\" (indirectly) ($id)"
523 set func [step_through $id [list lsinmips16 lsinhelper main]]
524 pass_if_eq "$func" sinblah16 \
525 "stepping from \"lsinmips16\" into \"sinblah16\" (indirectly) ($id)"
528 set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
529 set func [finish_if_ne $id "$func" lsinhelper \
530 [list sinblah16 lsinmips16 lsinhelper main]]
531 pass_if_eq "$func" lsinmips16 \
532 "stepping from \"sinblah16\" back to \"lsinmips16\" (indirectly) ($id)"
535 set func [step_through $id [list lsinmips16 lsinhelper main]]
536 pass_if_eq "$func" lsinhelper \
537 "stepping from \"lsinmips16\" back to \"lsinhelper\" ($id)"
541 set func [step_through $id [list lsinhelper main]]
542 pass_if_eq "$func" main "stepping from \"lsinhelper\" back to \"main\" ($id)"