regen.sh (5393B)
1 #!/usr/bin/env bash 2 # test/asm/regen.sh — regenerate the smoke goldens from the host 3 # `as` / `objdump` (via clang as the cross driver). Maintainer aid: NOT 4 # run by CI. Commit the refreshed goldens alongside the case changes. 5 # 6 # Usage: 7 # ./regen.sh regenerate every case 8 # ./regen.sh <name> regenerate just one case (substring match) 9 # 10 # Requires: 11 # clang --target=aarch64-linux-gnu or --target=x86_64-linux-gnu 12 # llvm-objdump or a target objdump 13 # xxd (for hex dumps) 14 15 set -eu 16 17 ROOT="$(cd "$(dirname "$0")/../.." && pwd)" 18 TEST_DIR="$ROOT/test/asm" 19 FILTER="${1:-}" 20 KIT_TEST_ARCH="${KIT_TEST_ARCH:-aa64}" 21 ASM_RUNNER="$ROOT/build/test/asm-runner" 22 23 case "$KIT_TEST_ARCH" in 24 aa64|aarch64|arm64) 25 TEST_ARCH=aa64 26 CLANG_TARGET="--target=aarch64-linux-gnu" 27 OBJDUMP_MACHINE="aarch64" 28 TARGET_OBJDUMP="aarch64-linux-gnu-objdump" 29 ;; 30 x64|x86_64|amd64) 31 TEST_ARCH=x64 32 CLANG_TARGET="--target=x86_64-linux-gnu" 33 OBJDUMP_MACHINE="i386:x86-64" 34 TARGET_OBJDUMP="x86_64-linux-gnu-objdump" 35 ;; 36 *) 37 printf 'regen.sh: unknown KIT_TEST_ARCH=%s (want aa64|x64)\n' "$KIT_TEST_ARCH" >&2 38 exit 2 39 ;; 40 esac 41 42 OBJDUMP="$(command -v llvm-objdump 2>/dev/null || command -v "$TARGET_OBJDUMP" 2>/dev/null || true)" 43 if [ -z "$OBJDUMP" ]; then 44 printf 'regen.sh: no llvm-objdump / %s on PATH\n' "$TARGET_OBJDUMP" >&2 45 exit 1 46 fi 47 48 tmp="$(mktemp -d)" 49 trap 'rm -rf "$tmp"' EXIT 50 51 case_applies() { 52 local dir="$1" name="$2" targets tuple 53 targets="$dir/$name.targets" 54 [ -f "$targets" ] || return 0 55 for tuple in $(cat "$targets"); do 56 case "$tuple:$TEST_ARCH" in 57 aa64:aa64|aarch64:aa64|arm64:aa64) return 0 ;; 58 x64:x64|x86_64:x64|amd64:x64) return 0 ;; 59 esac 60 done 61 return 1 62 } 63 64 regen_encode() { 65 local src="$1" name out_obj out_hex 66 name="$(basename "$src" .s)" 67 [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]] && return 0 68 case_applies "$TEST_DIR/encode" "$name" || return 0 69 out_obj="$tmp/$name.o" 70 out_hex="$TEST_DIR/encode/$name.expected.hex" 71 clang $CLANG_TARGET -c "$src" -o "$out_obj" 72 # Dump every executable section (smoke only inspects .text; this is 73 # tight enough for now). For multi-section cases we'll pivot to a 74 # per-section dump alongside phase 3. 75 "$OBJDUMP" -h -j .text "$out_obj" >/dev/null 2>&1 76 "$OBJDUMP" --full-contents -j .text "$out_obj" \ 77 | awk '/^Contents of section/ {next} /^$/ {next} 78 { for (i=2; i<=5; i++) if ($i ~ /^[0-9a-f]+$/) printf "%s", $i; printf "\n" }' \ 79 | tr -d '\n' \ 80 | { cat; printf '\n'; } >"$out_hex" 81 printf ' regen encode/%s\n' "$name" 82 } 83 84 regen_decode() { 85 local hexfile="$1" name out_txt 86 name="$(basename "$hexfile" .hex)" 87 [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]] && return 0 88 case_applies "$TEST_DIR/decode" "$name" || return 0 89 out_txt="$TEST_DIR/decode/$name.expected.txt" 90 # Mirror asm-runner --decode output exactly: vaddr:\tmnemonic\toperands. 91 # objdump's listing format differs (it interleaves addresses + raw hex); 92 # rebuild a minimal line per insn via awk so the goldens match the 93 # runner's exact-match expectation. 94 local raw="$tmp/$name.bin" bytes_s="$tmp/$name.bytes.s" bytes_o="$tmp/$name.bytes.o" 95 xxd -r -p "$hexfile" "$raw" 96 { 97 printf '.text\n' 98 od -An -tx1 -v "$raw" \ 99 | awk '{ for (i=1; i<=NF; i++) printf ".byte 0x%s\n", $i }' 100 } >"$bytes_s" 101 clang $CLANG_TARGET -c "$bytes_s" -o "$bytes_o" 102 "$OBJDUMP" -d --no-show-raw-insn "$bytes_o" \ 103 | awk '/^[ ]*[0-9a-f]+:/ { 104 sub(/:/, "", $1); 105 addr = $1; 106 # fields: addr mnemonic operands... 107 mnem = $2; 108 ops = ""; 109 for (i=3; i<=NF; i++) ops = (ops=="" ? $i : ops " " $i); 110 if (mnem == "lock") { 111 lock_addr = addr; 112 pending_lock = 1; 113 next; 114 } 115 if (pending_lock) { 116 addr = lock_addr; 117 mnem = "lock " mnem; 118 pending_lock = 0; 119 } 120 if (ops == "") 121 printf "%s:\t%s\n", addr, mnem; 122 else 123 printf "%s:\t%s\t%s\n", addr, mnem, ops; 124 }' >"$out_txt" 125 printf ' regen decode/%s\n' "$name" 126 } 127 128 regen_listing() { 129 local bin="$1" name out_lst 130 name="$(basename "$bin" .in.bin)" 131 [ -n "$FILTER" ] && [[ "$name" != *"$FILTER"* ]] && return 0 132 case_applies "$TEST_DIR/listing" "$name" || return 0 133 out_lst="$TEST_DIR/listing/$name.expected.lst" 134 if [ -x "$ASM_RUNNER" ]; then 135 KIT_TEST_ARCH="$TEST_ARCH" "$ASM_RUNNER" --listing "$bin" "$out_lst" 136 else 137 "$OBJDUMP" -d "$bin" \ 138 | awk '/^Disassembly of section/ || /^[0-9a-f]+ </ || /^[ ]+[0-9a-f]+:/ || /^$/' \ 139 >"$out_lst" 140 fi 141 printf ' regen listing/%s\n' "$name" 142 } 143 144 printf 'Regenerating goldens...\n' 145 for src in "$TEST_DIR"/encode/*.s; do [ -e "$src" ] && regen_encode "$src"; done 146 for src in "$TEST_DIR"/decode/*.hex; do [ -e "$src" ] && regen_decode "$src"; done 147 for src in "$TEST_DIR"/listing/*.in.bin; do [ -e "$src" ] && regen_listing "$src"; done 148 printf 'Done.\n'