# Copyright 2010, 2011 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # This file is part of the gdb testsuite. # Test arm displaced stepping. if $tracelevel { strace $tracelevel } if {![istarget "arm*-*-*"]} then { verbose "Skipping arm displaced stepping tests." return } set testfile "arm-disp-step" set srcfile ${testfile}.S set binfile ${objdir}/${subdir}/${testfile} set additional_flags "-Wa,-g" if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable [list debug $additional_flags]] != "" } { untested arm-disp-step.exp return -1 } ######################################### # Test ldm/stm related to PC. proc test_ldm_stm_pc {} { global srcfile # Try to set breakpoint on test_ldm_stm_pc. If symbol 'test_ldm_stm_pc' # can't be resolved, test case is compiled in Thumb mode, skip it. gdb_test_multiple "break *test_ldm_stm_pc" "break test_ldm_stm_pc" { -re "Breakpoint.*at.* file .*$srcfile, line.*" { pass "break test_ldm_stm_pc" } -re "Function \"test_ldm_stm_pc\" not defined\..*Make breakpoint pending on future shared library load.*y or .n.. $" { gdb_test "n" "" "Test case is compiled in Thumb mode" return } } gdb_test "break *test_ldm_pc" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ldm_pc" gdb_test "break *test_ldm_stm_pc_ret" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ldm_stm_pc_ret" gdb_continue_to_breakpoint "continue to test_ldm_stm_pc" \ ".*stmdb.*sp\!\,.*\{lr\, pc\}.*" gdb_continue_to_breakpoint "continue to test_ldm_pc" \ ".*ldmia.*sp\!\,.*\{pc\}.*" gdb_continue_to_breakpoint "continue to test_ldm_stm_pc_ret" \ ".*bx lr.*" } ######################################### # Test ldrX literal proc test_ldr_literal {} { global srcfile global gdb_prompt gdb_test_multiple "break *test_ldr_literal" "break test_ldr_literal" { -re "Breakpoint.*at.* file .*$srcfile, line.*\r\n$gdb_prompt $" { pass "break test_ldr_literal" } -re "No symbol.*\r\n$gdb_prompt $" { return 0 } } gdb_test "break *test_ldrsb_literal" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ldrsb_literal" gdb_test "break *test_ldrsh_literal" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ldrsh_literal" gdb_test "break *test_ldr_literal_end" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_test_ldr_literal_end" gdb_continue_to_breakpoint "continue to test_ldr_literal" \ ".*ldrh.*r0\,.*\[pc\].*" gdb_continue_to_breakpoint "continue to test_ldrsb_literal" \ ".*ldrsb.*r0\,.*\[pc\].*" gdb_continue_to_breakpoint "continue to test_ldrsh_literal" \ ".*ldrsh.*r0\,.*\[pc\].*" gdb_continue_to_breakpoint "continue to test_ldr_literal_ret" \ ".*bx lr.*" } ########################################## # Test call/ret. proc test_call_ret {} { global srcfile gdb_test "break *test_call_end" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_call_end" gdb_test "break *test_ret" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ret" gdb_test "break *test_ret_end" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ret_end" gdb_continue_to_breakpoint "continue to test_call_end" \ ".*@ Location test_call_end.*" gdb_continue_to_breakpoint "continue to test_ret" \ ".*bx lr.*" gdb_continue_to_breakpoint "continue to test_ret_end" \ ".*@ Location test_ret_end.*" } ######################################### # Test branch proc test_branch {} { global srcfile gdb_test "break *test_branch" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_branch" gdb_test "break *L_branch" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break Lbranch" gdb_continue_to_breakpoint "continue to test_branch" \ ".*b.*L_branch.*" gdb_continue_to_breakpoint "continue to Lbranch" \ ".*bx lr.*" } ######################################### # Test ldr from pc proc test_ldr_from_pc {} { global srcfile gdb_test "break *test_ldr_pc" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ldr_pc" gdb_test "break test_ldr_pc_ret" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_ldr_pc_ret" gdb_continue_to_breakpoint "continue to test_ldr_pc" \ ".*ldr.*r1\,.*\[pc, #0\].*" gdb_continue_to_breakpoint "continue to Lbranch" \ ".*bx lr.*" } proc test_adr_32bit {} { global srcfile global gdb_prompt gdb_test_multiple "break *test_adr_32bit" "break test_adr_32bit" { -re "Breakpoint.*at.* file .*$srcfile, line.*\r\n$gdb_prompt $" { pass "break test_adr" } -re "No symbol.*\r\n$gdb_prompt $" { return 0 } } gdb_test "break *test_adr_32bit_after" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_adr_32bit_after" gdb_test "break *test_adr_32bit_end" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_adr_32bit_end" gdb_continue_to_breakpoint "test_adr_32bit" \ ".*adr.*r0\,.*\.L6.*" gdb_continue_to_breakpoint "test_adr_32bit_after" \ ".*adr.*r0\,.*\.L6.*" gdb_continue_to_breakpoint "test_adr_32bit_end" \ ".*bx lr.*" } ######################################### # Test pop to PC proc test_pop_pc {} { global srcfile gdb_test "break *test_pop_pc_1" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_pop_pc" gdb_test "break *test_pop_pc_ret" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_pop_pc_ret" gdb_continue_to_breakpoint "continue to test_pop_pc" \ ".*b.*\{r1\, pc\}.*" gdb_continue_to_breakpoint "continue to test_pop_pc_ret" \ ".*bx lr.*" } ########################################### proc test_str_pc {} { global srcfile gdb_test_multiple "break *test_str_pc" "break test_str_pc" { -re "Breakpoint.*at.* file .*$srcfile, line.*" { pass "break test_str_pc" } -re "No symbol.*" { pass "break test_str_pc" return } } gdb_test "break *test_str_pc_end" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_str_pc_end" # Set breakpoint on both lables pc_offset_right and pc_offset_wrong gdb_test "break *pc_offset_right" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break pc_offset_right" gdb_test "break *pc_offset_wrong" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break pc_offset_wrong" gdb_continue_to_breakpoint "continue to test_str_pc" \ ".*str.*pc\,.*\[sp, #-4\].*" # If breakpoint on lable pc_offset_wrong is hit, that means the offset # computed in displaced stepping is different from offset computed # without displaced stepping. Report a failure. gdb_continue_to_breakpoint "continue to pc_offset_right" \ ".*b.*test_str_pc_end.*" gdb_continue_to_breakpoint "continue to test_str_pc_end" \ ".*bx lr.*" } # Get things started. clean_restart ${testfile} # Turn displaced stepping off before runto main. When displaced stepping # is on, and we type 'run', GDB will first try to single step on _dl_debug_state, # which is in library might be compiled in Thumb. gdb_test_no_output "set displaced-stepping off" if ![runto_main] then { fail "Can't run to main" return 0 } gdb_test_no_output "set displaced-stepping on" gdb_test "show displaced-stepping" ".* displaced stepping .* is on.*" gdb_test "break *test_call" \ "Breakpoint.*at.* file .*$srcfile, line.*" \ "break test_call" gdb_test_multiple "continue" "continue to test_call" { -re ".*bl test_call_subr.*" { pass "continue to test_call" } -re "Displaced stepping is only supported in" { kfail "gdb/NNNN" $testfile return } } test_call_ret test_branch test_ldr_from_pc test_ldm_stm_pc test_ldr_literal test_adr_32bit test_pop_pc test_str_pc ########################################## # Done, run program to exit. gdb_continue_to_end "arm-disp-step"