boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

disasm-elf.sh (4704B)


      1 #!/bin/sh
      2 ## disasm-elf.sh — disassemble a hex2pp-emitted ELF with llvm-objdump.
      3 ##
      4 ## Our seed ELF.hex2 sets ph_memsz to 512 MB (so the BSS region past
      5 ## ELF_end is mappable), but ph_filesz is just the on-disk size.
      6 ## llvm-objdump trusts memsz when laying out the segment for
      7 ## disassembly and runs off the end of the file with
      8 ## "The end of the file was unexpectedly encountered". The seed ELF
      9 ## also lacks section headers, so --start-address/--stop-address
     10 ## doesn't help on its own.
     11 ##
     12 ## Workaround: copy the ELF, patch ph_memsz down to ph_filesz, then
     13 ## disassemble. Output goes to stdout.
     14 ##
     15 ## We also auto-default --start-address to e_entry so the ELF header +
     16 ## program header bytes at the top of PT_LOAD aren't decoded as bogus
     17 ## instructions. Pass an explicit --start-address (e.g. 0x600000) to
     18 ## override and see the header bytes.
     19 ##
     20 ## boot-build-p1*.sh writes a one-line sidecar at <elf>.workdir pointing
     21 ## at build/$ARCH/.work/<src-without-ext>/. P1pp builds store
     22 ## expanded.hex2pp there; legacy raw-P1 seed builds store prog.hex2.
     23 ## When that sidecar is present we extract a label map via
     24 ## tools/m1-symbols.py and:
     25 ##   - default --stop-address to :_text_end if that sentinel label is
     26 ##     present, so trailing rodata doesn't decode as bogus instructions
     27 ##   - inject "<label>:" headers and rewrite "<PT_LOAD#0+0xNNN>" xrefs
     28 ##     in the disasm output
     29 ## Pass NO_LABELS=1 to disable both behaviors.
     30 ##
     31 ## Usage: disasm-elf.sh <elf> [llvm-objdump args...]
     32 ##   defaults to `-d` (text only). For data + text, pass `-D`.
     33 
     34 set -eu
     35 
     36 [ "$#" -ge 1 ] || { echo "usage: $0 <elf> [llvm-objdump args...]" >&2; exit 2; }
     37 
     38 ELF=$1; shift
     39 [ -e "$ELF" ] || { echo "missing $ELF" >&2; exit 1; }
     40 
     41 OBJDUMP=${LLVM_OBJDUMP:-llvm-objdump}
     42 TRIPLE=${TRIPLE:-aarch64-linux-gnu}
     43 
     44 # ELF fields we read (little-endian 8-byte):
     45 #   e_entry    at file offset 0x18
     46 #   ph_filesz  at file offset 0x60 (e_phoff 0x40 + 0x20)
     47 #   ph_memsz   at file offset 0x68 (e_phoff 0x40 + 0x28)
     48 # Single-program-header layout, per our seed ELF.
     49 read_le8() {
     50     od -An -tu8 -N8 -j"$2" "$1" | tr -d ' \n'
     51 }
     52 write_le8() {
     53     # $1 file, $2 offset, $3 value
     54     printf '%016x' "$3" \
     55         | sed 's/\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)\(..\)/\8\7\6\5\4\3\2\1/' \
     56         | xxd -r -p \
     57         | dd of="$1" bs=1 seek="$2" count=8 conv=notrunc status=none
     58 }
     59 
     60 ENTRY=$(read_le8 "$ELF" 24)
     61 FILESZ=$(read_le8 "$ELF" 96)
     62 MEMSZ=$(read_le8 "$ELF" 104)
     63 
     64 TMP=$(mktemp -t disasm-elf.XXXXXX)
     65 trap 'rm -f "$TMP"' EXIT
     66 cp "$ELF" "$TMP"
     67 chmod u+w "$TMP"
     68 
     69 if [ "$MEMSZ" != "$FILESZ" ]; then
     70     write_le8 "$TMP" 104 "$FILESZ"
     71 fi
     72 
     73 # Default to -d if no objdump flags given.
     74 [ "$#" -eq 0 ] && set -- -d
     75 
     76 # Auto-skip the ELF header + program header by defaulting
     77 # --start-address to e_entry, unless the user supplied their own.
     78 have_start=0
     79 have_stop=0
     80 for arg in "$@"; do
     81     case "$arg" in
     82         --start-address=*|--start-address) have_start=1;;
     83         --stop-address=*|--stop-address)   have_stop=1;;
     84     esac
     85 done
     86 if [ "$have_start" -eq 0 ]; then
     87     set -- "--start-address=0x$(printf '%x' "$ENTRY")" "$@"
     88 fi
     89 
     90 # Locate expanded.hex2pp (new P1pp path) or prog.hex2 (legacy raw-P1
     91 # path) via the <elf>.workdir sidecar produced by boot-build-p1*.sh.
     92 # The sidecar holds a repo-relative path (build/$ARCH/.work/<src>/), so
     93 # resolve it against the repo root inferred from this script's location.
     94 HERE=$(dirname "$0")
     95 REPO_ROOT=$(cd "$HERE/.." && pwd)
     96 HEX2=""
     97 if [ -e "$ELF.workdir" ]; then
     98     workdir=$(cat "$ELF.workdir")
     99     case "$workdir" in
    100         /*) ;;                          # absolute, leave alone
    101          *) workdir="$REPO_ROOT/$workdir" ;;
    102     esac
    103     if [ -e "$workdir/expanded.hex2pp" ]; then
    104         HEX2="$workdir/expanded.hex2pp"
    105     elif [ -e "$workdir/prog.hex2" ]; then
    106         HEX2="$workdir/prog.hex2"
    107     else
    108         echo "disasm-elf: $ELF.workdir -> $workdir, but no expanded.hex2pp or prog.hex2 there" >&2
    109     fi
    110 elif [ "${NO_LABELS:-0}" != "1" ]; then
    111     echo "disasm-elf: no $ELF.workdir sidecar; rebuild for label annotation" >&2
    112 fi
    113 MAP=""
    114 if [ "${NO_LABELS:-0}" != "1" ] && [ -n "$HEX2" ]; then
    115     MAP=$(mktemp -t disasm-elf-map.XXXXXX)
    116     trap 'rm -f "$TMP" "$MAP"' EXIT
    117     "$HERE/m1-symbols.py" map "$HEX2" > "$MAP"
    118     # Default --stop-address to :_text_end if no user value and the
    119     # sentinel exists in the map.
    120     if [ "$have_stop" -eq 0 ]; then
    121         text_end=$(awk '$2 == "_text_end" {print $1; exit}' "$MAP")
    122         [ -n "$text_end" ] && set -- "--stop-address=$text_end" "$@"
    123     fi
    124 fi
    125 
    126 if [ -n "$MAP" ]; then
    127     "$OBJDUMP" --triple="$TRIPLE" "$@" "$TMP" \
    128         | "$HERE/m1-symbols.py" annotate "$MAP"
    129 else
    130     exec "$OBJDUMP" --triple="$TRIPLE" "$@" "$TMP"
    131 fi