459 lines
13 KiB
Plaintext
459 lines
13 KiB
Plaintext
# Copyright 2010-2016 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 <http://www.gnu.org/licenses/>.
|
|
|
|
# This file is part of the gdb testsuite.
|
|
|
|
# Test arm displaced stepping.
|
|
|
|
if {![is_aarch32_target]} 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
|
|
global gdb_prompt
|
|
|
|
# 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.*\r\n$gdb_prompt $" {
|
|
pass "break test_ldm_stm_pc"
|
|
}
|
|
-re "No symbol.*\r\n$gdb_prompt $" {
|
|
pass "break test_ldm_stm_pc"
|
|
return 0
|
|
}
|
|
}
|
|
|
|
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.*"
|
|
}
|
|
|
|
proc test_ldr_literal_16 {} {
|
|
global srcfile
|
|
global gdb_prompt
|
|
|
|
gdb_test_multiple "break *test_ldr_literal_16" "break test_ldr_literal_16" {
|
|
-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_ldr_literal_16_end" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_ldr_literal_16_end"
|
|
|
|
gdb_continue_to_breakpoint "continue to test_ldr_literal_16" \
|
|
".*ldr.*r0\,.*L2.*"
|
|
gdb_continue_to_breakpoint "continue to test_ldr_literal_16_end" \
|
|
".*bx lr.*"
|
|
}
|
|
|
|
##########################################
|
|
# Test call/ret.
|
|
proc test_call_ret {} {
|
|
global srcfile
|
|
global testfile
|
|
|
|
gdb_test "break *test_call" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_call"
|
|
|
|
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 "test_call" ".*bl test_call_subr.*"
|
|
gdb_continue_to_breakpoint "test_call_end" \
|
|
".*@ Location test_call_end.*"
|
|
gdb_continue_to_breakpoint "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 test_ldr_pc_ret" \
|
|
".*bx lr.*"
|
|
}
|
|
|
|
#########################################
|
|
|
|
# Test cbz and cbnz
|
|
proc test_cbz_cbnz {} {
|
|
global srcfile
|
|
global gdb_prompt
|
|
|
|
gdb_test_multiple "break *test_zero_cbnz" "break test_zero_cbnz" {
|
|
-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_zero_cbz" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_zero_cbz"
|
|
gdb_test "break *test_non_zero_cbnz" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_non_zero_cbnz"
|
|
gdb_test "break *test_non_zero_cbz" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_non_zero_cbz"
|
|
|
|
gdb_continue_to_breakpoint "continue to test_zero_cbnz" \
|
|
".*cbnz.*r0\,.*\.L3.*"
|
|
gdb_continue_to_breakpoint "continue to test_zero_cbz" \
|
|
".*cbz.*r0\,.*\.L3.*"
|
|
gdb_continue_to_breakpoint "continue to test_non_zero_cbz" \
|
|
".*cbz.*r0\,.*\.L4.*"
|
|
gdb_continue_to_breakpoint "continue to test_non_zero_cbnz" \
|
|
".*cbnz.*r0\,.*\.L4.*"
|
|
}
|
|
|
|
# Test adr
|
|
|
|
proc test_adr {} {
|
|
global srcfile
|
|
global gdb_prompt
|
|
|
|
gdb_test_multiple "break *test_adr" "break test_adr" {
|
|
-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_end" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_adr_end"
|
|
|
|
gdb_continue_to_breakpoint "test_adr" \
|
|
".*adr.*r0\,.*\.L8.*"
|
|
gdb_continue_to_breakpoint "test_adr_end" \
|
|
".*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_1"
|
|
gdb_test "break *test_pop_pc_2" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_2"
|
|
gdb_test "break *test_pop_pc_3" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_3"
|
|
|
|
gdb_test "break *test_pop_pc_ret" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_ret"
|
|
|
|
gdb_test "break *test_pop_pc_1_right" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_1_right"
|
|
gdb_test "break *test_pop_pc_1_wrong" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_1_wrong"
|
|
gdb_test "break *test_pop_pc_2_right" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_2_right"
|
|
gdb_test "break *test_pop_pc_2_wrong" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_2_wrong"
|
|
gdb_test "break *test_pop_pc_3_right" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_3_right"
|
|
gdb_test "break *test_pop_pc_3_wrong" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_pop_pc_1_wrong"
|
|
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_1" \
|
|
".*b.*\{r1\, pc\}.*"
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_1_check" \
|
|
".*b.*right.*"
|
|
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_2" \
|
|
".*\{pc\}.*"
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_2_check" \
|
|
".*b.*right.*"
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_3" \
|
|
".*\{r0\,r1\,r2\,r3\,r4\,r5\,r6\,r7\,pc\}.*"
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_3_check" \
|
|
".*b.*right.*"
|
|
gdb_continue_to_breakpoint "continue to test_pop_pc_ret" \
|
|
".*r7.*"
|
|
}
|
|
|
|
###########################################
|
|
|
|
proc test_str_pc {} {
|
|
global srcfile
|
|
global gdb_prompt
|
|
|
|
gdb_test_multiple "break *test_str_pc" "break test_str_pc" {
|
|
-re "Breakpoint.*at.* file .*$srcfile, line.*\r\n$gdb_prompt $" {
|
|
pass "break test_str_pc"
|
|
}
|
|
-re "No symbol.*\r\n$gdb_prompt $" {
|
|
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.*"
|
|
}
|
|
|
|
# Test 16 bit thumb instruction 'add rd, pc'.
|
|
|
|
proc test_add_rn_pc {} {
|
|
global srcfile gdb_prompt
|
|
|
|
set test "break test_add_rn_pc"
|
|
gdb_test_multiple "break *test_add_rn_pc" $test {
|
|
-re "Breakpoint.*at.* file .*$srcfile, line.*\r\n$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
-re "No symbol.*\r\n$gdb_prompt $" {
|
|
return
|
|
}
|
|
}
|
|
|
|
gdb_continue_to_breakpoint "continue to test_add_rn_pc" \
|
|
".*mov.*r3, 4.*"
|
|
|
|
gdb_test "break *test_add_rn_pc_start" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_add_rn_pc_start"
|
|
|
|
gdb_continue_to_breakpoint "continue to test_add_rn_pc_start" \
|
|
".*add.*r3,.*pc.*"
|
|
|
|
set pc_val [get_integer_valueof "\$pc" 0]
|
|
|
|
gdb_test "break *test_add_rn_pc_end" \
|
|
"Breakpoint.*at.* file .*$srcfile, line.*" \
|
|
"break test_add_rn_pc_end"
|
|
|
|
gdb_continue_to_breakpoint "continue to test_add_rn_pc_end" \
|
|
".*bx lr.*"
|
|
|
|
set r3_val [get_integer_valueof "\$r3" 0]
|
|
# Test the value in r3 is correct.
|
|
gdb_assert { [expr {$pc_val + 4 + 4} == $r3_val] }
|
|
}
|
|
|
|
# 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.*"
|
|
|
|
test_call_ret
|
|
|
|
test_branch
|
|
|
|
test_ldr_from_pc
|
|
|
|
test_ldm_stm_pc
|
|
|
|
test_ldr_literal
|
|
|
|
test_ldr_literal_16
|
|
|
|
test_cbz_cbnz
|
|
|
|
test_adr
|
|
|
|
test_adr_32bit
|
|
|
|
test_pop_pc
|
|
|
|
test_str_pc
|
|
|
|
test_add_rn_pc
|
|
|
|
##########################################
|
|
|
|
# Done, run program to exit.
|
|
|
|
gdb_continue_to_end "arm-disp-step"
|