| #!/bin/bash | |
| # Copyright 2021 The Fuchsia Authors. All rights reserved. | |
| # Use of this source code is governed by a BSD-style license that can be | |
| # found in the LICENSE file. | |
| #### CATEGORY=Diagnostic | |
| ### Dumps disassembly for binaries from the build. | |
| ## usage: fx dis [-l | -S | -n] BINARY... | |
| ## | |
| ## Dump disassembly for a binary to a file in the build directory. | |
| ## | |
| ## -l list source locations interleaved with assembly | |
| ## -S list source code lines interleaved with assembly | |
| ## -r list relocations interleaved with assembly | |
| ## -n do not demangle symbol names | |
| ## -L use llvm-objdump rather than GNU objdump | |
| ## | |
| ## Each BINARY can be the name of the binary file without directory, e.g. | |
| ## "libzircon.so" or "zircon.elf"; or the name of a GN target, e.g. "zircon"; | |
| ## or a string of (lowercase) hex characters that's an ELF build ID. | |
| ## | |
| ## The disassembly will be written to a file next to the binary file in | |
| ## the build directory, using its name with ".lst" suffix. | |
| set -o errexit | |
| source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $? | |
| fx-config-read | |
| readonly BINARIES_JSON="$FUCHSIA_BUILD_DIR/binaries.json" | |
| DEMANGLE=true | |
| USE_LLVM=false | |
| OBJDUMP_ARGS=() | |
| while getopts lSrLn OPT; do | |
| case $OPT in | |
| [lSr]) OBJDUMP_ARGS+=(-$OPT) ;; | |
| L) USE_LLVM=true ;; | |
| n) DEMANGLE=false ;; | |
| esac | |
| done | |
| shift $((OPTIND-1)) | |
| if $DEMANGLE; then | |
| OBJDUMP_ARGS+=(--demangle) | |
| fi | |
| if [[ $# -eq 0 ]]; then | |
| fx-command-help | |
| exit 1 | |
| fi | |
| run_jq() { | |
| fx-command-run jq --raw-output "$@" | |
| } | |
| run_direct_filter() { | |
| run_jq "$1" "$BINARIES_JSON" | |
| } | |
| normalize_build_ids() { | |
| local query=' | |
| .[] | select(.elf_build_id) | "\(.elf_build_id) \(.cpu) \(.debug) \(.label)"' | |
| run_jq "$query" "$BINARIES_JSON" | normalize_build_ids_filter | |
| } | |
| normalize_build_ids_filter() { | |
| echo '[' | |
| local comma= | |
| while read id cpu debug label; do | |
| echo "$comma{\ | |
| \"build_id\": \"$(<"$FUCHSIA_BUILD_DIR/$id")\",\ | |
| \"cpu\": \"$cpu\",\ | |
| \"debug\": \"$debug\",\ | |
| \"label\": \"$label\"\ | |
| }" | |
| comma=',' | |
| done | |
| echo ']' | |
| } | |
| run_buildid_filter() { | |
| normalize_build_ids | run_jq "$1" | |
| } | |
| is_hex() { | |
| local str="$1" | |
| if [[ -z "$str" ]]; then | |
| return 0 | |
| fi | |
| while [[ -n "$str" ]]; do | |
| case "${str:0:1}" in | |
| [0-9a-f]) ;; | |
| *) return 1 ;; | |
| esac | |
| str="${str:1}" | |
| done | |
| return 0 | |
| } | |
| RUN_FILTER=run_direct_filter | |
| for BINARY in "$@"; do | |
| if is_hex "$BINARY"; then | |
| RUN_FILTER=run_buildid_filter | |
| break | |
| fi | |
| done | |
| FILTER=".[] | select(false" | |
| for BINARY in "$@"; do | |
| if is_hex "$BINARY"; then | |
| FILTER+=" or (.build_id == \"$BINARY\")" | |
| else | |
| DEBUG_RE="(^|/)$BINARY([.]debug)?\$" | |
| LABEL_RE=":$BINARY[(]" | |
| FILTER+=" or (.debug | test(\"$DEBUG_RE\")) or (.label | test(\"$LABEL_RE\"))" | |
| fi | |
| done | |
| FILTER+=') | "\(.cpu) \(.debug) \(.label)"' | |
| PATHS=($($RUN_FILTER "$FILTER")) | |
| if (( ${#PATHS[@]} == 0 )); then | |
| fx-error "No binaries matched any of: $*" | |
| exit 1 | |
| fi | |
| disassemble() { | |
| local BINARY_CPU="$1" BINARY_PATH="$2" BINARY_LABEL="$3" | |
| local -a CMD | |
| if $USE_LLVM; then | |
| CMD=("$PREBUILT_CLANG_DIR/bin/llvm-objdump") | |
| else | |
| case "$BINARY_CPU" in | |
| arm64) CMD=("$PREBUILT_GCC_DIR/bin/aarch64-elf-objdump" -m aarch64) ;; | |
| x64) CMD=("$PREBUILT_GCC_DIR/bin/x86_64-elf-objdump" -m i386:x86-64) ;; | |
| *) | |
| fx-error "Can't handle binary $BINARY_PATH with CPU type $BINARY_CPU" | |
| exit 1 | |
| ;; | |
| esac | |
| fi | |
| CMD+=(-d) | |
| "${CMD[@]}" "${OBJDUMP_ARGS[@]}" "$FUCHSIA_BUILD_DIR/$BINARY_PATH" > "$FUCHSIA_BUILD_DIR/${BINARY_PATH}.lst" | |
| fx-info Wrote "${BINARY_PATH}.lst" for "$BINARY_LABEL" | |
| } | |
| i=0 | |
| while (( i < ${#PATHS[@]} )); do | |
| disassemble "${PATHS[$i]}" "${PATHS[$((i+1))]}" "${PATHS[$((i+2))]}" | |
| ((i+=3)) | |
| done |