1#!/bin/bash 2 3# Copyright (c) 2020-2022 Arm Limited 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17function skip_instruction { 18 19 local SKIP_ADDRESS=$1 20 local SKIP_SIZE=$2 21 22 # Parse the ASM instruction from the address using gdb 23 INSTR=$($GDB $AXF_FILE --batch -ex "disassemble $SKIP_ADDRESS" | grep "^ *$SKIP_ADDRESS" | sed "s/.*:[ \t]*\(.*\)$/\1/g") 24 # Parse the C line from the address using gdb 25 LINE=$($GDB $AXF_FILE --batch -ex "info line *$SKIP_ADDRESS" | sed "s/Line \([0-9]*\).*\"\(.*\)\".*/\2:\1/g") 26 27 # Sometimes an address is in the middle of a 4 byte instruction. In that case 28 # don't run the test 29 if test "$INSTR" == ""; then 30 return 31 fi 32 33 # Print out the meta-info about the test, in YAML 34 echo "- skip_test:" 35 echo " addr: $SKIP_ADDRESS" 36 echo " asm: \"$INSTR\"" 37 echo " line: \"$LINE\"" 38 echo " skip: $SKIP_SIZE" 39 # echo -ne "$SKIP_ADDRESS | $INSTR...\t" 40 41 cat >commands.gdb <<EOF 42target remote localhost: 1234 43file $IMAGE_DIR/bl2.axf 44b boot_go_for_image_id if image_id == 0 45continue 46delete breakpoints 1 47b *$SKIP_ADDRESS 48continue& 49eval "shell sleep 0.5" 50interrupt 51if \$pc == $SKIP_ADDRESS 52 echo "Stopped at breakpoint" 53else 54 echo "Failed to stop at breakpoint" 55end 56echo "PC before increase:" 57print \$pc 58set \$pc += $SKIP_SIZE 59echo "PC after increase:" 60print \$pc 61detach 62eval "shell sleep 0.5" 63EOF 64 65 echo -n '.' 1>&2 66 67 # start qemu, dump the serial output to $QEMU_LOG_FILE 68 QEMU_LOG_FILE=qemu.log 69 QEMU_PID_FILE=qemu_pid.txt 70 rm -f $QEMU_PID_FILE $QEMU_LOG_FILE 71 /usr/bin/qemu-system-arm \ 72 -M mps2-an521 \ 73 -s -S \ 74 -kernel $IMAGE_DIR/bl2.axf \ 75 -device loader,file=$IMAGE_DIR/tfm_s_ns_signed.bin,addr=0x10080000 \ 76 -chardev file,id=char0,path=$QEMU_LOG_FILE \ 77 -serial chardev:char0 \ 78 -display none \ 79 -pidfile $QEMU_PID_FILE \ 80 -daemonize 81 82 # start qemu, skip the instruction, and continue execution 83 $GDB < ./commands.gdb &>gdb_out.txt 84 85 # kill qemu 86 kill -9 `cat $QEMU_PID_FILE` 87 88 # If "Secure image initializing" is seen the TFM booted, which means that a skip 89 # managed to defeat the signature check. Write out whether the image booted or 90 # not to the log in YAML 91 if cat $QEMU_LOG_FILE | grep -i "Starting bootloader" &>/dev/null; then 92 # bootloader started successfully 93 if cat gdb_out.txt | grep -i "Stopped at breakpoint" &>/dev/null; then 94 # The target was stopped at the desired address 95 if cat $QEMU_LOG_FILE | grep -i "Secure image initializing" &>/dev/null; then 96 echo " test_exec_ok: True" 97 echo " skipped: True" 98 echo " boot: True" 99 100 #print the address that was skipped, and some context to the console 101 echo "" 1>&2 102 echo "Boot success: address: $SKIP_ADDRESS skipped: $SKIP_SIZE" 1>&2 103 arm-none-eabi-objdump -d $IMAGE_DIR/bl2.axf --start-address=$SKIP_ADDRESS -S | tail -n +7 | head -n 14 1>&2 104 echo "" 1>&2 105 echo "" 1>&2 106 else 107 LAST_LINE=`tail -n 1 $QEMU_LOG_FILE | tr -dc '[:print:]'` 108 echo " test_exec_ok: True" 109 echo " skipped: True" 110 echo " boot: False" 111 echo " last_line: \"$LAST_LINE\" " 112 fi 113 else 114 # The target was not stopped at the desired address. 115 # The most probable reason is that the instruction for that address is 116 # on a call path that is not taken in this run (e.g. error handling) 117 if cat $QEMU_LOG_FILE | grep -i "Secure image initializing" &>/dev/null; then 118 # The image booted, although it shouldn't happen as the test is to 119 # be run with a corrupt image. 120 echo " test_exec_ok: False" 121 echo " test_exec_fail_reason: \"No instructions were skipped (e.g. branch was not executed), but booted successfully\"" 122 else 123 # the execution didn't stop at the address (e.g. the instruction 124 # is on a branch that is not taken) 125 echo " test_exec_ok: True" 126 echo " skipped: False" 127 fi 128 fi 129 else 130 # failed before the first printout 131 echo " test_exec_ok: True" 132 echo " skipped: True" 133 echo " boot: False" 134 echo " last_line: 'N/A' " 135 fi 136} 137 138# Inform how the script is used 139usage() { 140 echo "$0 <image_dir> <start_addr> [<end_addr>] [(-s | --skip) <skip_len>]" 141} 142 143#defaults 144SKIP=2 145BIN_DIR=$(pwd)/install/outputs 146AXF_FILE=$BIN_DIR/bl2.axf 147GDB=gdb-multiarch 148BOOTLOADER=true 149 150# Parse arguments 151while [[ $# -gt 0 ]]; do 152 case $1 in 153 -s|--skip) 154 SKIP="$2" 155 shift 156 shift 157 ;; 158 -h|--help) 159 usage 160 exit 0 161 ;; 162 *) 163 if test -z "$IMAGE_DIR"; then 164 IMAGE_DIR=$1 165 elif test -z "$START"; then 166 START=$1 167 elif test -z "$END"; then 168 END=$1 169 else 170 usage 171 exit 1 172 fi 173 shift 174 ;; 175 esac 176done 177 178# Check that image directory, start and end address have been supplied 179if test -z "$IMAGE_DIR"; then 180 usage 181 exit 2 182fi 183 184if test -z "$START"; then 185 usage 186 exit 2 187fi 188 189if test -z "$END"; then 190 END=$START 191fi 192 193if test -z "$SKIP"; then 194 SKIP='2' 195fi 196 197# Create the start-end address range (step 2) 198ADDRS=$(printf '0x%x\n' $(seq "$START" 2 "$END")) 199 200# For each address run the skip_instruction function on it 201for ADDR in $ADDRS; do 202 skip_instruction $ADDR $SKIP 203done 204