1 # Copyright 2024 Free Software Foundation, Inc. 2 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. 7 # 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. 12 # 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/>. 15 16 # Test instruction record for AArch64 FEAT_MOPS instructions. 17 # Based on gdb.reverse/ppc_record_test_isa_3_1.exp 18 # 19 # The basic flow of the record tests are: 20 # 1) Stop before executing the instructions of interest. Record 21 # the initial value of the registers that the instruction will 22 # change, i.e. the destination register. 23 # 2) Execute the instructions. Record the new value of the 24 # registers that changed. 25 # 3) Reverse the direction of the execution and execute back to 26 # just before the instructions of interest. Record the final 27 # value of the registers of interest. 28 # 4) Check that the initial and new values of the registers are 29 # different, i.e. the instruction changed the registers as expected. 30 # 5) Check that the initial and final values of the registers are 31 # the same, i.e. GDB record restored the registers to their 32 # original values. 33 34 require allow_aarch64_mops_tests 35 36 standard_testfile 37 38 if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} \ 39 [list debug additional_flags=-march=armv9.3-a]] } { 40 return -1 41 } 42 43 if ![runto_main] { 44 return -1 45 } 46 47 gdb_test_no_output "record full" 48 49 foreach_with_prefix insn_prefix {"set" "cpy" "cpyf"} { 50 global decimal hex 51 52 set before_seq [gdb_get_line_number "Before ${insn_prefix}p"] 53 set after_seq [gdb_get_line_number "After ${insn_prefix}e"] 54 55 gdb_test "break $before_seq" \ 56 "Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \ 57 "break before instruction sequence" 58 gdb_continue_to_breakpoint "about to execute instruction sequence" \ 59 [multi_line ".*/aarch64-mops.c:$decimal" \ 60 "$decimal\[ \t\]+__asm__ volatile \\(\"${insn_prefix}p \[^\r\n\]+\""] 61 62 # Depending on the compiler, the line number information may put GDB a few 63 # instructions before the beginning of the asm statement. 64 arrive_at_instruction "${insn_prefix}p" 65 # Add a breakpoint that we're sure is at the prologue instruction. 66 gdb_test "break *\$pc" \ 67 "Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \ 68 "break at prologue instruction" 69 70 # Record the initial memory and register values. 71 set dest_initial [get_valueof "/x" "dest" "unable to read initial" \ 72 "get dest initial value"] 73 set x19_initial [capture_command_output "info register x19" ""] 74 set x21_initial [capture_command_output "info register x21" ""] 75 76 # The set instructions use the ZERO variable, but not Q nor SOURCE, 77 # and the other instructions are the opposite. 78 if {[string compare $insn_prefix "set"] == 0} { 79 set x22_initial [capture_command_output "info register x22" ""] 80 } else { 81 set x20_initial [capture_command_output "info register x20" ""] 82 set source_initial [get_valueof "/x" "source" "unable to read initial" \ 83 "get source initial value"] 84 } 85 86 gdb_test "break $after_seq" \ 87 "Breakpoint $decimal at $hex: file .*/aarch64-mops.c, line $decimal\\." \ 88 "break after instruction sequence" 89 gdb_continue_to_breakpoint "executed instruction sequence" \ 90 [multi_line ".*/aarch64-mops.c:$decimal" "$decimal\[ \t\]+p = dest;"] 91 92 # Record the new memory and register values. 93 set dest_new [get_valueof "/x" "dest" "unable to read new" \ 94 "get dest new value"] 95 set x19_new [capture_command_output "info register x19" ""] 96 set x21_new [capture_command_output "info register x21" ""] 97 98 if {[string compare $insn_prefix "set"] == 0} { 99 set x22_new [capture_command_output "info register x22" ""] 100 } else { 101 set x20_new [capture_command_output "info register x20" ""] 102 set source_new [get_valueof "/x" "source" "unable to read new" \ 103 "get source new value"] 104 } 105 106 # Execute in reverse to before the instruction sequence. 107 gdb_test_no_output "set exec-direction reverse" 108 109 gdb_continue_to_breakpoint "reversed execution of instruction sequence" \ 110 [multi_line ".*/aarch64-mops.c:$decimal" \ 111 "$decimal\[ \t\]+__asm__ volatile \\(\"${insn_prefix}p \[^\r\n\]+\""] 112 113 # Record the final memory and register values. 114 set dest_final [get_valueof "/x" "dest" "unable to read final" \ 115 "get dest final value"] 116 set x19_final [capture_command_output "info register x19" ""] 117 set x21_final [capture_command_output "info register x21" ""] 118 119 if {[string compare $insn_prefix "set"] == 0} { 120 set x22_final [capture_command_output "info register x22" ""] 121 } else { 122 set x20_final [capture_command_output "info register x20" ""] 123 set source_final [get_valueof "/x" "source" "unable to read final" \ 124 "get source final value"] 125 } 126 127 # Check initial and new values of dest are different. 128 gdb_assert [string compare $dest_initial $dest_new] \ 129 "check dest initial value versus dest new value" 130 131 # Check initial and new values of x19 are different. 132 gdb_assert [string compare $x19_initial $x19_new] \ 133 "check x19 initial value versus x19 new value" 134 135 # Check initial and new values of x21 are different. 136 gdb_assert [string compare $x21_initial $x21_new] \ 137 "check x21 initial value versus x21 new value" 138 139 if {[string compare $insn_prefix "set"] == 0} { 140 # Check initial and new values of x22 are the same. 141 # The register with the value to set shouldn't change. 142 gdb_assert ![string compare $x22_initial $x22_new] \ 143 "check x22 initial value versus x22 new value" 144 } else { 145 # Check initial and new values of x20 are different. 146 gdb_assert [string compare $x20_initial $x20_new] \ 147 "check x20 initial value versus x20 new value" 148 # Check initial and new values of source are the same. 149 gdb_assert ![string compare $source_initial $source_new] \ 150 "check source initial value versus source new value" 151 } 152 153 # Check initial and final values of dest are the same. 154 gdb_assert ![string compare $dest_initial $dest_final] \ 155 "check dest initial value versus dest final value" 156 157 # Check initial and final values of x19 are the same. 158 gdb_assert ![string compare $x19_initial $x19_final] \ 159 "check x19 initial value versus x19 final value" 160 161 # Check initial and final values of x21 are the same. 162 gdb_assert ![string compare $x21_initial $x21_final] \ 163 "check x21 initial value versus x21 final value" 164 165 if {[string compare $insn_prefix "set"] == 0} { 166 # Check initial and final values of x22 are the same. 167 gdb_assert ![string compare $x22_initial $x22_final] \ 168 "check x22 initial value versus x22 final value" 169 } else { 170 # Check initial and final values of x20 are the same. 171 gdb_assert ![string compare $x20_initial $x20_final] \ 172 "check x20 initial value versus x20 final value" 173 174 # Check initial and final values of source are the same. 175 gdb_assert ![string compare $source_initial $source_final] \ 176 "check source initial value versus source final value" 177 } 178 179 # Restore forward execution and go to end of recording. 180 gdb_test_no_output "set exec-direction forward" 181 gdb_test "record goto end" \ 182 [multi_line \ 183 "Go forward to insn number $decimal" \ 184 "#0 main \\(\\) at .*/aarch64-mops.c:$decimal" \ 185 "$decimal\[ \t\]+p = dest;"] 186 } 187