1 # Copyright 2012-2024 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 require {istarget "mips*-*-*"}
30 # A helper to set caller's SRCFILE and OBJFILE based on FILENAME and SUFFIX.
31 proc set_src_and_obj { filename { suffix "" } } {
37 if {![string equal "$suffix" ""]} {
40 set srcfile ${srcdir}/${subdir}/${filename}.c
41 set objfile [standard_output_file ${filename}${suffix}.o]
44 # First check if a trivial MIPS16 program can be built and debugged. This
45 # verifies environment and processor support, any failure here must be
46 # classed as the lack of support.
47 set testname mips16-thunks-main
49 set_src_and_obj mips16-thunks-inmain
50 set options [list debug nowarnings additional_flags=-mips16]
51 set objfiles ${objfile}
52 gdb_compile ${srcfile} ${objfile} object ${options}
54 set_src_and_obj mips16-thunks-main
55 set options [list debug nowarnings additional_flags=-mips16]
56 lappend objfiles ${objfile}
57 gdb_compile ${srcfile} ${objfile} object ${options}
59 set binfile [standard_output_file ${testname}]
60 set options [list debug nowarnings]
61 if {[gdb_compile ${objfiles} ${binfile} executable ${options}] != ""} {
62 unsupported "no MIPS16 support in the toolchain."
65 clean_restart ${testname}
68 gdb_test_multiple "" "check for MIPS16 support in the processor" {
69 -re "Breakpoint 1.*inmain .*$gdb_prompt $" {
70 gdb_test_multiple "finish" \
71 "check for MIPS16 support in the processor" {
72 -re "Value returned is \\\$\[0-9\]+ = 0\[^0-9\].*$gdb_prompt $" {
73 verbose "MIPS16 support check successful."
76 unsupported "no MIPS16 support in the processor."
80 unsupported "no MIPS16 support in the processor."
86 unsupported "no MIPS16 support in the processor."
90 unsupported "no MIPS16 support in the processor."
95 # Check if MIPS16 PIC code can be built and debugged. We want to check
96 # PIC and MIPS16 thunks are handled correctly together if possible, but
97 # on targets that do not support PIC code, e.g. bare iron, we still want
98 # to test the rest of functionality.
99 set testname mips16-thunks-pic
102 set_src_and_obj mips16-thunks-inmain pic
104 debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
105 set objfiles ${objfile}
106 gdb_compile ${srcfile} ${objfile} object ${options}
108 set_src_and_obj mips16-thunks-main pic
110 debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
111 lappend objfiles ${objfile}
112 gdb_compile ${srcfile} ${objfile} object ${options}
114 set binfile [standard_output_file ${testname}]
115 set options [list debug nowarnings additional_flags=-fPIC]
116 if {[gdb_compile ${objfiles} ${binfile} executable ${options}] == ""} {
117 clean_restart ${testname}
118 gdb_breakpoint inmain
120 gdb_test_multiple "" "check for PIC support" {
121 -re "Breakpoint 1.*inmain .*$gdb_prompt $" {
122 note "PIC support present, will make additional PIC thunk checks."
123 set picflag additional_flags=-fPIC
125 -re "$gdb_prompt $" {
126 note "No PIC support, skipping additional PIC thunk checks."
129 note "No PIC support, skipping additional PIC thunk checks."
133 note "No PIC support, skipping additional PIC thunk checks."
136 # OK, build the twisted executable. This program contains the following
138 # - __call_stub_fp_sin,
139 # - __call_stub_fp_sinblah,
140 # - __call_stub_fp_sinfrob,
141 # - __call_stub_fp_sinhelper,
142 # - __call_stub_lsinhelper,
143 # - __fn_stub_lsinmips16,
144 # - __fn_stub_sinblah16,
145 # - __fn_stub_sinfrob16,
146 # - __fn_stub_sinmips16,
147 # - __mips16_call_stub_df_2,
149 # Additionally, if PIC code is supported, it contains the following PIC thunks:
150 # - .pic.__mips16_call_stub_df_2,
151 # - .pic.__mips16_ret_df,
156 set testname mips16-thunks-sin
158 set_src_and_obj mips16-thunks-sinmain
159 set options [list debug nowarnings additional_flags=-mips16]
160 set objfiles ${objfile}
161 gdb_compile ${srcfile} ${objfile} object ${options}
163 set_src_and_obj mips16-thunks-sin
164 set options [list debug nowarnings additional_flags=-mno-mips16]
165 lappend objfiles ${objfile}
166 gdb_compile ${srcfile} ${objfile} object ${options}
168 set_src_and_obj mips16-thunks-sinmips16
169 set options [list debug nowarnings additional_flags=-mips16]
170 lappend objfiles ${objfile}
171 gdb_compile ${srcfile} ${objfile} object ${options}
173 set_src_and_obj mips16-thunks-sinfrob
175 debug nowarnings additional_flags=-mno-mips16 ${picflag}]
176 lappend objfiles ${objfile}
177 gdb_compile ${srcfile} ${objfile} object ${options}
179 set_src_and_obj mips16-thunks-sinfrob16
181 debug nowarnings additional_flags=-mips16 ${picflag}]
182 lappend objfiles ${objfile}
183 gdb_compile ${srcfile} ${objfile} object ${options}
185 set binfile [standard_output_file ${testname}]
186 set options [list debug nowarnings]
187 gdb_compile ${objfiles} ${binfile} executable ${options}
188 clean_restart ${testname}
193 # Build some useful regular expressions out of a list of functions FUNCS
194 # to be used to match against backtraces.
195 proc build_frames_re { funcs } {
196 upvar anyframe anyframe
202 set argsandsource " +\\\(.*\\\) +at +\[^\r\n\]+\r\n"
203 set addrin "(?:\[^ \]+ +in +)?"
204 set anyframe "#${fid} +${addrin}(\[^ \]+)${argsandsource}"
205 set frame "#${fid} +${addrin}${func}${argsandsource}"
207 foreach f [lrange $funcs 1 end] {
209 append frames "#${fid} +${addrin}${f}${argsandsource}"
213 # Single-step through the function that is at the head of function list
214 # FUNCS until a different function (frame) is reached. Before each step
215 # check the backtrace against FUNCS. ID is used for reporting, to tell
216 # apart different calls to this procedure for the same function. If
217 # successful, then return the name of the function we have stopped in.
218 proc step_through { id funcs } {
221 set func [lindex $funcs 0]
222 build_frames_re "$funcs"
224 set msg "single-stepping through \"${func}\" ($id)"
226 # Arbitrarily limit the maximium number of steps made to avoid looping
227 # indefinitely in the case something goes wrong, increase as (if)
230 while { $count > 0 } {
231 if { [gdb_test_multiple "backtrace" "$msg (backtrace)" {
232 -re "${frames}$gdb_prompt $" {
233 if { [gdb_test_multiple "step" "$msg (step)" {
234 -re "$gdb_prompt $" {
235 if { [gdb_test_multiple "frame" "$msg (frame)" {
236 -re "${frame}.*$gdb_prompt $" {
238 -re "${anyframe}.*$gdb_prompt $" {
240 return $expect_out(1,string)
255 fail "$msg (too many steps)"
259 # Finish the current function that must be one that is at the head of
260 # function list FUNCS. Before that check the backtrace against FUNCS.
261 # ID is used for reporting, to tell apart different calls to this
262 # procedure for the same function. If successful, then return the name
263 # of the function we have stopped in.
264 proc finish_through { id funcs } {
267 set func [lindex $funcs 0]
268 build_frames_re "$funcs"
270 set msg "finishing \"${func}\" ($id)"
272 gdb_test_multiple "backtrace" "$msg (backtrace)" {
273 -re "${frames}$gdb_prompt $" {
274 gdb_test_multiple "finish" "$msg (finish)" {
275 -re "Run till exit from ${frame}.*$gdb_prompt $" {
276 gdb_test_multiple "frame" "$msg (frame)" {
277 -re "${anyframe}.*$gdb_prompt $" {
279 return $expect_out(1,string)
289 # Report PASS if VAL is equal to EXP, otherwise report FAIL, using MSG.
290 proc pass_if_eq { val exp msg } {
291 if {[string equal "$val" "$exp"]} {
298 # Check if FUNC is equal to WANT. If not, then assume that we have stepped
299 # into a library call. In this case finish it, then step out of the caller.
300 # ID is used for reporting, to tell apart different calls to this procedure
301 # for the same function. If successful, then return the name of the
302 # function we have stopped in.
303 proc finish_if_ne { id func want funcs } {
304 if {![string equal "$func" "$want"]} {
306 set want [lindex $funcs 0]
307 set func [finish_through "$id" [linsert $funcs 0 "$func"]]
308 pass_if_eq "$func" "$want" "\"${call}\" finishing to \"${want}\" ($id)"
309 set func [step_through "$id" $funcs]
314 # Now single-step through the program, making sure all thunks are correctly
315 # stepped over and omitted from backtraces.
318 set func [step_through $id [list main]]
319 pass_if_eq "$func" sinfrob16 "stepping from \"main\" into \"sinfrob16\" ($id)"
322 set func [step_through $id [list sinfrob16 main]]
323 set func [finish_if_ne $id "$func" main [list sinfrob16 main]]
324 pass_if_eq "$func" main "stepping from \"sinfrob16\" back to \"main\" ($id)"
327 set func [step_through $id [list main]]
328 pass_if_eq "$func" sinfrob "stepping from \"main\" into \"sinfrob\" ($id)"
331 set func [step_through $id [list sinfrob main]]
332 set func [finish_if_ne $id "$func" main [list sinfrob main]]
333 pass_if_eq "$func" main "stepping from \"sinfrob\" back to \"main\" ($id)"
337 set func [step_through $id [list main]]
338 pass_if_eq "$func" sinhelper "stepping from \"main\" into \"sinhelper\" ($id)"
341 set func [step_through $id [list sinhelper main]]
342 set func [finish_if_ne $id "$func" sinfrob16 [list sinhelper main]]
343 pass_if_eq "$func" sinfrob16 \
344 "stepping from \"sinhelper\" into \"sinfrob16\" ($id)"
347 set func [step_through $id [list sinfrob16 sinhelper main]]
348 set func [finish_if_ne $id "$func" sinhelper [list sinfrob16 sinhelper main]]
349 pass_if_eq "$func" sinhelper \
350 "stepping from \"sinfrob16\" back to \"sinhelper\" ($id)"
353 set func [step_through $id [list sinhelper main]]
354 pass_if_eq "$func" sinfrob "stepping from \"sinhelper\" into \"sinfrob\" ($id)"
357 set func [step_through $id [list sinfrob sinhelper main]]
358 set func [finish_if_ne $id "$func" sinhelper [list sinfrob sinhelper main]]
359 pass_if_eq "$func" sinhelper \
360 "stepping from \"sinfrob\" back to \"sinhelper\" ($id)"
364 set func [step_through $id [list sinhelper main]]
365 pass_if_eq "$func" sinmips16 \
366 "stepping from \"sinhelper\" into \"sinmips16\" ($id)"
369 set func [step_through $id [list sinmips16 sinhelper main]]
370 set func [finish_if_ne $id "$func" sinfrob16 [list sinmips16 sinhelper main]]
371 pass_if_eq "$func" sinfrob16 \
372 "stepping from \"sinmips16\" into \"sinfrob16\" ($id)"
375 set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
376 set func [finish_if_ne $id "$func" sinmips16 \
377 [list sinfrob16 sinmips16 sinhelper main]]
378 pass_if_eq "$func" sinmips16 \
379 "stepping from \"sinfrob16\" back to \"sinmips16\" ($id)"
382 set func [step_through $id [list sinmips16 sinhelper main]]
383 pass_if_eq "$func" sinfrob "stepping from \"sinmips16\" into \"sinfrob\" ($id)"
386 set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
387 set func [finish_if_ne $id "$func" sinhelper \
388 [list sinfrob sinmips16 sinhelper main]]
389 pass_if_eq "$func" sinmips16 \
390 "stepping from \"sinfrob\" back to \"sinmips16\" ($id)"
394 set func [step_through $id [list sinmips16 sinhelper main]]
395 pass_if_eq "$func" sinfrob16 \
396 "stepping from \"sinmips16\" into \"sinfrob16\" (indirectly) ($id)"
399 set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
400 set func [finish_if_ne $id "$func" sinmips16 \
401 [list sinfrob16 sinmips16 sinhelper main]]
402 pass_if_eq "$func" sinmips16 \
403 "stepping from \"sinfrob16\" back to \"sinmips16\" (indirectly) ($id)"
406 set func [step_through $id [list sinmips16 sinhelper main]]
407 pass_if_eq "$func" sinfrob \
408 "stepping from \"sinmips16\" into \"sinfrob\" (indirectly) ($id)"
411 set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
412 set func [finish_if_ne $id "$func" sinhelper \
413 [list sinfrob sinmips16 sinhelper main]]
414 pass_if_eq "$func" sinmips16 \
415 "stepping from \"sinfrob\" back to \"sinmips16\" (indirectly) ($id)"
418 set func [step_through $id [list sinmips16 sinhelper main]]
419 pass_if_eq "$func" sinhelper \
420 "stepping from \"sinmips16\" back to \"sinhelper\" ($id)"
424 set func [step_through $id [list sinhelper main]]
425 pass_if_eq "$func" main "stepping from \"sinhelper\" back to \"main\" ($id)"
428 set func [step_through $id [list main]]
429 pass_if_eq "$func" sinblah "stepping from \"main\" into \"sinblah\" ($id)"
432 set func [step_through $id [list sinblah main]]
433 set func [finish_if_ne $id "$func" main [list sinblah main]]
434 pass_if_eq "$func" main "stepping from \"sinblah\" back to \"main\" ($id)"
437 set func [step_through $id [list main]]
438 pass_if_eq "$func" sinblah16 "stepping from \"main\" into \"sinblah16\" ($id)"
441 set func [step_through $id [list sinblah16 main]]
442 set func [finish_if_ne $id "$func" main [list sinblah16 main]]
443 pass_if_eq "$func" main "stepping from \"sinblah16\" back to \"main\" ($id)"
447 set func [step_through $id [list main]]
448 pass_if_eq "$func" lsinhelper \
449 "stepping from \"main\" into \"lsinhelper\" ($id)"
452 set func [step_through $id [list lsinhelper main]]
453 set func [finish_if_ne $id "$func" sinblah [list lsinhelper main]]
454 pass_if_eq "$func" sinblah \
455 "stepping from \"lsinhelper\" into \"sinblah\" ($id)"
458 set func [step_through $id [list sinblah lsinhelper main]]
459 set func [finish_if_ne $id "$func" lsinhelper [list sinblah lsinhelper main]]
460 pass_if_eq "$func" lsinhelper \
461 "stepping from \"sinblah\" back to \"lsinhelper\" ($id)"
464 set func [step_through $id [list lsinhelper main]]
465 pass_if_eq "$func" sinblah16 \
466 "stepping from \"lsinhelper\" into \"sinblah16\" ($id)"
469 set func [step_through $id [list sinblah16 lsinhelper main]]
470 set func [finish_if_ne $id "$func" lsinhelper [list sinblah16 lsinhelper main]]
471 pass_if_eq "$func" lsinhelper \
472 "stepping from \"sinblah16\" back to \"lsinhelper\" ($id)"
476 set func [step_through $id [list lsinhelper main]]
477 pass_if_eq "$func" lsinmips16 \
478 "stepping from \"lsinhelper\" into \"lsinmips16\" ($id)"
481 set func [step_through $id [list lsinmips16 lsinhelper main]]
482 set func [finish_if_ne $id "$func" sinblah [list lsinmips16 lsinhelper main]]
483 pass_if_eq "$func" sinblah \
484 "stepping from \"lsinmips16\" into \"sinblah\" ($id)"
487 set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
488 set func [finish_if_ne $id "$func" lsinmips16 \
489 [list sinblah lsinmips16 lsinhelper main]]
490 pass_if_eq "$func" lsinmips16 \
491 "stepping from \"sinblah\" back to \"lsinmips16\" ($id)"
494 set func [step_through $id [list lsinmips16 lsinhelper main]]
495 pass_if_eq "$func" sinblah16 \
496 "stepping from \"lsinmips16\" into \"sinblah16\" ($id)"
499 set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
500 set func [finish_if_ne $id "$func" lsinhelper \
501 [list sinblah16 lsinmips16 lsinhelper main]]
502 pass_if_eq "$func" lsinmips16 \
503 "stepping from \"sinblah16\" back to \"lsinmips16\" ($id)"
507 set func [step_through $id [list lsinmips16 lsinhelper main]]
508 pass_if_eq "$func" sinblah \
509 "stepping from \"lsinmips16\" into \"sinblah\" (indirectly) ($id)"
512 set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
513 set func [finish_if_ne $id "$func" lsinmips16 \
514 [list sinblah lsinmips16 lsinhelper main]]
515 pass_if_eq "$func" lsinmips16 \
516 "stepping from \"sinblah\" back to \"lsinmips16\" (indirectly) ($id)"
519 set func [step_through $id [list lsinmips16 lsinhelper main]]
520 pass_if_eq "$func" sinblah16 \
521 "stepping from \"lsinmips16\" into \"sinblah16\" (indirectly) ($id)"
524 set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
525 set func [finish_if_ne $id "$func" lsinhelper \
526 [list sinblah16 lsinmips16 lsinhelper main]]
527 pass_if_eq "$func" lsinmips16 \
528 "stepping from \"sinblah16\" back to \"lsinmips16\" (indirectly) ($id)"
531 set func [step_through $id [list lsinmips16 lsinhelper main]]
532 pass_if_eq "$func" lsinhelper \
533 "stepping from \"lsinmips16\" back to \"lsinhelper\" ($id)"
537 set func [step_through $id [list lsinhelper main]]
538 pass_if_eq "$func" main "stepping from \"lsinhelper\" back to \"main\" ($id)"