1 # Copyright 2012-2016 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 "" } } {
41 if ![string equal "$suffix" ""] then {
44 set srcfile ${srcdir}/${subdir}/${filename}.c
45 set objfile ${objdir}/${subdir}/${filename}${suffix}.o
48 # First check if a trivial MIPS16 program can be built and debugged. This
49 # verifies environment and processor support, any failure here must be
50 # classed as the lack of support.
51 set testname mips16-thunks-main
53 set_src_and_obj mips16-thunks-inmain
54 set options [list debug nowarnings additional_flags=-mips16]
55 set objfiles ${objfile}
56 gdb_compile ${srcfile} ${objfile} object ${options}
58 set_src_and_obj mips16-thunks-main
59 set options [list debug nowarnings additional_flags=-mips16]
60 lappend objfiles ${objfile}
61 gdb_compile ${srcfile} ${objfile} object ${options}
63 set binfile ${objdir}/${subdir}/${testname}
64 set options [list debug nowarnings]
65 if { [gdb_compile ${objfiles} ${binfile} executable ${options}] != "" } then {
66 unsupported "No MIPS16 support in the toolchain."
69 clean_restart ${testname}
72 gdb_test_multiple "" "check for MIPS16 support in the processor" {
73 -re "Breakpoint 1.*inmain .*$gdb_prompt $" {
74 gdb_test_multiple "finish" \
75 "check for MIPS16 support in the processor" {
76 -re "Value returned is \\\$\[0-9\]+ = 0\[^0-9\].*$gdb_prompt $" {
77 verbose "MIPS16 support check successful."
80 unsupported "No MIPS16 support in the processor."
84 unsupported "No MIPS16 support in the processor."
90 unsupported "No MIPS16 support in the processor."
94 unsupported "No MIPS16 support in the processor."
99 # Check if MIPS16 PIC code can be built and debugged. We want to check
100 # PIC and MIPS16 thunks are handled correctly together if possible, but
101 # on targets that do not support PIC code, e.g. bare iron, we still want
102 # to test the rest of functionality.
103 set testname mips16-thunks-pic
106 set_src_and_obj mips16-thunks-inmain pic
108 debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
109 set objfiles ${objfile}
110 gdb_compile ${srcfile} ${objfile} object ${options}
112 set_src_and_obj mips16-thunks-main pic
114 debug nowarnings additional_flags=-mips16 additional_flags=-fPIC]
115 lappend objfiles ${objfile}
116 gdb_compile ${srcfile} ${objfile} object ${options}
118 set binfile ${objdir}/${subdir}/${testname}
119 set options [list debug nowarnings additional_flags=-fPIC]
120 if { [gdb_compile ${objfiles} ${binfile} executable ${options}] == "" } then {
121 clean_restart ${testname}
122 gdb_breakpoint inmain
124 gdb_test_multiple "" "check for PIC support" {
125 -re "Breakpoint 1.*inmain .*$gdb_prompt $" {
126 note "PIC support present, will make additional PIC thunk checks."
127 set picflag additional_flags=-fPIC
129 -re "$gdb_prompt $" {
130 note "No PIC support, skipping additional PIC thunk checks."
133 note "No PIC support, skipping additional PIC thunk checks."
137 note "No PIC support, skipping additional PIC thunk checks."
140 # OK, build the twisted executable. This program contains the following
142 # - __call_stub_fp_sin,
143 # - __call_stub_fp_sinblah,
144 # - __call_stub_fp_sinfrob,
145 # - __call_stub_fp_sinhelper,
146 # - __call_stub_lsinhelper,
147 # - __fn_stub_lsinmips16,
148 # - __fn_stub_sinblah16,
149 # - __fn_stub_sinfrob16,
150 # - __fn_stub_sinmips16,
151 # - __mips16_call_stub_df_2,
153 # Additionally, if PIC code is supported, it contains the following PIC thunks:
154 # - .pic.__mips16_call_stub_df_2,
155 # - .pic.__mips16_ret_df,
160 set testname mips16-thunks-sin
162 set_src_and_obj mips16-thunks-sinmain
163 set options [list debug nowarnings additional_flags=-mips16]
164 set objfiles ${objfile}
165 gdb_compile ${srcfile} ${objfile} object ${options}
167 set_src_and_obj mips16-thunks-sin
168 set options [list debug nowarnings additional_flags=-mno-mips16]
169 lappend objfiles ${objfile}
170 gdb_compile ${srcfile} ${objfile} object ${options}
172 set_src_and_obj mips16-thunks-sinmips16
173 set options [list debug nowarnings additional_flags=-mips16]
174 lappend objfiles ${objfile}
175 gdb_compile ${srcfile} ${objfile} object ${options}
177 set_src_and_obj mips16-thunks-sinfrob
179 debug nowarnings additional_flags=-mno-mips16 ${picflag}]
180 lappend objfiles ${objfile}
181 gdb_compile ${srcfile} ${objfile} object ${options}
183 set_src_and_obj mips16-thunks-sinfrob16
185 debug nowarnings additional_flags=-mips16 ${picflag}]
186 lappend objfiles ${objfile}
187 gdb_compile ${srcfile} ${objfile} object ${options}
189 set binfile ${objdir}/${subdir}/${testname}
190 set options [list debug nowarnings]
191 gdb_compile ${objfiles} ${binfile} executable ${options}
192 clean_restart ${testname}
193 if ![runto_main] then {
194 fail "running test program, MIPS16 thunk tests aborted"
198 # Build some useful regular expressions out of a list of functions FUNCS
199 # to be used to match against backtraces.
200 proc build_frames_re { funcs } {
201 upvar anyframe anyframe
207 set argsandsource " +\\\(.*\\\) +at +\[^\r\n\]+\r\n"
208 set addrin "(?:\[^ \]+ +in +)?"
209 set anyframe "#${fid} +${addrin}(\[^ \]+)${argsandsource}"
210 set frame "#${fid} +${addrin}${func}${argsandsource}"
212 foreach f [lrange $funcs 1 end] {
214 append frames "#${fid} +${addrin}${f}${argsandsource}"
218 # Single-step through the function that is at the head of function list
219 # FUNCS until a different function (frame) is reached. Before each step
220 # check the backtrace against FUNCS. ID is used for reporting, to tell
221 # apart different calls to this procedure for the same function. If
222 # successful, then return the name of the function we have stopped in.
223 proc step_through { id funcs } {
226 set func [lindex $funcs 0]
227 build_frames_re "$funcs"
229 set msg "single-stepping through \"${func}\" ($id)"
231 # Arbitrarily limit the maximium number of steps made to avoid looping
232 # indefinitely in the case something goes wrong, increase as (if)
235 while { $count > 0 } {
236 if { [gdb_test_multiple "backtrace" "$msg (backtrace)" {
237 -re "${frames}$gdb_prompt $" {
238 if { [gdb_test_multiple "step" "$msg (step)" {
239 -re "$gdb_prompt $" {
240 if { [gdb_test_multiple "frame" "$msg (frame)" {
241 -re "${frame}.*$gdb_prompt $" {
243 -re "${anyframe}.*$gdb_prompt $" {
245 return $expect_out(1,string)
260 fail "$msg (too many steps)"
264 # Finish the current function that must be one that is at the head of
265 # function list FUNCS. Before that check the backtrace against FUNCS.
266 # ID is used for reporting, to tell apart different calls to this
267 # procedure for the same function. If successful, then return the name
268 # of the function we have stopped in.
269 proc finish_through { id funcs } {
272 set func [lindex $funcs 0]
273 build_frames_re "$funcs"
275 set msg "finishing \"${func}\" ($id)"
277 gdb_test_multiple "backtrace" "$msg (backtrace)" {
278 -re "${frames}$gdb_prompt $" {
279 gdb_test_multiple "finish" "$msg (finish)" {
280 -re "Run till exit from ${frame}.*$gdb_prompt $" {
281 gdb_test_multiple "frame" "$msg (frame)" {
282 -re "${anyframe}.*$gdb_prompt $" {
284 return $expect_out(1,string)
294 # Report PASS if VAL is equal to EXP, otherwise report FAIL, using MSG.
295 proc pass_if_eq { val exp msg } {
296 if [string equal "$val" "$exp"] then {
303 # Check if FUNC is equal to WANT. If not, then assume that we have stepped
304 # into a library call. In this case finish it, then step out of the caller.
305 # ID is used for reporting, to tell apart different calls to this procedure
306 # for the same function. If successful, then return the name of the
307 # function we have stopped in.
308 proc finish_if_ne { id func want funcs } {
309 if ![string equal "$func" "$want"] then {
311 set want [lindex $funcs 0]
312 set func [finish_through "$id" [linsert $funcs 0 "$func"]]
313 pass_if_eq "$func" "$want" "\"${call}\" finishing to \"${want}\" ($id)"
314 set func [step_through "$id" $funcs]
319 # Now single-step through the program, making sure all thunks are correctly
320 # stepped over and omitted from backtraces.
323 set func [step_through $id [list main]]
324 pass_if_eq "$func" sinfrob16 "stepping from \"main\" into \"sinfrob16\" ($id)"
327 set func [step_through $id [list sinfrob16 main]]
328 set func [finish_if_ne $id "$func" main [list sinfrob16 main]]
329 pass_if_eq "$func" main "stepping from \"sinfrob16\" back to \"main\" ($id)"
332 set func [step_through $id [list main]]
333 pass_if_eq "$func" sinfrob "stepping from \"main\" into \"sinfrob\" ($id)"
336 set func [step_through $id [list sinfrob main]]
337 set func [finish_if_ne $id "$func" main [list sinfrob main]]
338 pass_if_eq "$func" main "stepping from \"sinfrob\" back to \"main\" ($id)"
342 set func [step_through $id [list main]]
343 pass_if_eq "$func" sinhelper "stepping from \"main\" into \"sinhelper\" ($id)"
346 set func [step_through $id [list sinhelper main]]
347 set func [finish_if_ne $id "$func" sinfrob16 [list sinhelper main]]
348 pass_if_eq "$func" sinfrob16 \
349 "stepping from \"sinhelper\" into \"sinfrob16\" ($id)"
352 set func [step_through $id [list sinfrob16 sinhelper main]]
353 set func [finish_if_ne $id "$func" sinhelper [list sinfrob16 sinhelper main]]
354 pass_if_eq "$func" sinhelper \
355 "stepping from \"sinfrob16\" back to \"sinhelper\" ($id)"
358 set func [step_through $id [list sinhelper main]]
359 pass_if_eq "$func" sinfrob "stepping from \"sinhelper\" into \"sinfrob\" ($id)"
362 set func [step_through $id [list sinfrob sinhelper main]]
363 set func [finish_if_ne $id "$func" sinhelper [list sinfrob sinhelper main]]
364 pass_if_eq "$func" sinhelper \
365 "stepping from \"sinfrob\" back to \"sinhelper\" ($id)"
369 set func [step_through $id [list sinhelper main]]
370 pass_if_eq "$func" sinmips16 \
371 "stepping from \"sinhelper\" into \"sinmips16\" ($id)"
374 set func [step_through $id [list sinmips16 sinhelper main]]
375 set func [finish_if_ne $id "$func" sinfrob16 [list sinmips16 sinhelper main]]
376 pass_if_eq "$func" sinfrob16 \
377 "stepping from \"sinmips16\" into \"sinfrob16\" ($id)"
380 set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
381 set func [finish_if_ne $id "$func" sinmips16 \
382 [list sinfrob16 sinmips16 sinhelper main]]
383 pass_if_eq "$func" sinmips16 \
384 "stepping from \"sinfrob16\" back to \"sinmips16\" ($id)"
387 set func [step_through $id [list sinmips16 sinhelper main]]
388 pass_if_eq "$func" sinfrob "stepping from \"sinmips16\" into \"sinfrob\" ($id)"
391 set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
392 set func [finish_if_ne $id "$func" sinhelper \
393 [list sinfrob sinmips16 sinhelper main]]
394 pass_if_eq "$func" sinmips16 \
395 "stepping from \"sinfrob\" back to \"sinmips16\" ($id)"
399 set func [step_through $id [list sinmips16 sinhelper main]]
400 pass_if_eq "$func" sinfrob16 \
401 "stepping from \"sinmips16\" into \"sinfrob16\" (indirectly) ($id)"
404 set func [step_through $id [list sinfrob16 sinmips16 sinhelper main]]
405 set func [finish_if_ne $id "$func" sinmips16 \
406 [list sinfrob16 sinmips16 sinhelper main]]
407 pass_if_eq "$func" sinmips16 \
408 "stepping from \"sinfrob16\" back to \"sinmips16\" (indirectly) ($id)"
411 set func [step_through $id [list sinmips16 sinhelper main]]
412 pass_if_eq "$func" sinfrob \
413 "stepping from \"sinmips16\" into \"sinfrob\" (indirectly) ($id)"
416 set func [step_through $id [list sinfrob sinmips16 sinhelper main]]
417 set func [finish_if_ne $id "$func" sinhelper \
418 [list sinfrob sinmips16 sinhelper main]]
419 pass_if_eq "$func" sinmips16 \
420 "stepping from \"sinfrob\" back to \"sinmips16\" (indirectly) ($id)"
423 set func [step_through $id [list sinmips16 sinhelper main]]
424 pass_if_eq "$func" sinhelper \
425 "stepping from \"sinmips16\" back to \"sinhelper\" ($id)"
429 set func [step_through $id [list sinhelper main]]
430 pass_if_eq "$func" main "stepping from \"sinhelper\" back to \"main\" ($id)"
433 set func [step_through $id [list main]]
434 pass_if_eq "$func" sinblah "stepping from \"main\" into \"sinblah\" ($id)"
437 set func [step_through $id [list sinblah main]]
438 set func [finish_if_ne $id "$func" main [list sinblah main]]
439 pass_if_eq "$func" main "stepping from \"sinblah\" back to \"main\" ($id)"
442 set func [step_through $id [list main]]
443 pass_if_eq "$func" sinblah16 "stepping from \"main\" into \"sinblah16\" ($id)"
446 set func [step_through $id [list sinblah16 main]]
447 set func [finish_if_ne $id "$func" main [list sinblah16 main]]
448 pass_if_eq "$func" main "stepping from \"sinblah16\" back to \"main\" ($id)"
452 set func [step_through $id [list main]]
453 pass_if_eq "$func" lsinhelper \
454 "stepping from \"main\" into \"lsinhelper\" ($id)"
457 set func [step_through $id [list lsinhelper main]]
458 set func [finish_if_ne $id "$func" sinblah [list lsinhelper main]]
459 pass_if_eq "$func" sinblah \
460 "stepping from \"lsinhelper\" into \"sinblah\" ($id)"
463 set func [step_through $id [list sinblah lsinhelper main]]
464 set func [finish_if_ne $id "$func" lsinhelper [list sinblah lsinhelper main]]
465 pass_if_eq "$func" lsinhelper \
466 "stepping from \"sinblah\" back to \"lsinhelper\" ($id)"
469 set func [step_through $id [list lsinhelper main]]
470 pass_if_eq "$func" sinblah16 \
471 "stepping from \"lsinhelper\" into \"sinblah16\" ($id)"
474 set func [step_through $id [list sinblah16 lsinhelper main]]
475 set func [finish_if_ne $id "$func" lsinhelper [list sinblah16 lsinhelper main]]
476 pass_if_eq "$func" lsinhelper \
477 "stepping from \"sinblah16\" back to \"lsinhelper\" ($id)"
481 set func [step_through $id [list lsinhelper main]]
482 pass_if_eq "$func" lsinmips16 \
483 "stepping from \"lsinhelper\" into \"lsinmips16\" ($id)"
486 set func [step_through $id [list lsinmips16 lsinhelper main]]
487 set func [finish_if_ne $id "$func" sinblah [list lsinmips16 lsinhelper main]]
488 pass_if_eq "$func" sinblah \
489 "stepping from \"lsinmips16\" into \"sinblah\" ($id)"
492 set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
493 set func [finish_if_ne $id "$func" lsinmips16 \
494 [list sinblah lsinmips16 lsinhelper main]]
495 pass_if_eq "$func" lsinmips16 \
496 "stepping from \"sinblah\" back to \"lsinmips16\" ($id)"
499 set func [step_through $id [list lsinmips16 lsinhelper main]]
500 pass_if_eq "$func" sinblah16 \
501 "stepping from \"lsinmips16\" into \"sinblah16\" ($id)"
504 set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
505 set func [finish_if_ne $id "$func" lsinhelper \
506 [list sinblah16 lsinmips16 lsinhelper main]]
507 pass_if_eq "$func" lsinmips16 \
508 "stepping from \"sinblah16\" back to \"lsinmips16\" ($id)"
512 set func [step_through $id [list lsinmips16 lsinhelper main]]
513 pass_if_eq "$func" sinblah \
514 "stepping from \"lsinmips16\" into \"sinblah\" (indirectly) ($id)"
517 set func [step_through $id [list sinblah lsinmips16 lsinhelper main]]
518 set func [finish_if_ne $id "$func" lsinmips16 \
519 [list sinblah lsinmips16 lsinhelper main]]
520 pass_if_eq "$func" lsinmips16 \
521 "stepping from \"sinblah\" back to \"lsinmips16\" (indirectly) ($id)"
524 set func [step_through $id [list lsinmips16 lsinhelper main]]
525 pass_if_eq "$func" sinblah16 \
526 "stepping from \"lsinmips16\" into \"sinblah16\" (indirectly) ($id)"
529 set func [step_through $id [list sinblah16 lsinmips16 lsinhelper main]]
530 set func [finish_if_ne $id "$func" lsinhelper \
531 [list sinblah16 lsinmips16 lsinhelper main]]
532 pass_if_eq "$func" lsinmips16 \
533 "stepping from \"sinblah16\" back to \"lsinmips16\" (indirectly) ($id)"
536 set func [step_through $id [list lsinmips16 lsinhelper main]]
537 pass_if_eq "$func" lsinhelper \
538 "stepping from \"lsinmips16\" back to \"lsinhelper\" ($id)"
542 set func [step_through $id [list lsinhelper main]]
543 pass_if_eq "$func" main "stepping from \"lsinhelper\" back to \"main\" ($id)"