| #!/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 | -L | -P <path to objdump>] 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 |
| ## -P <path> use objdump binary in argument |
| ## |
| ## 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" |
| readonly LLVM_OBJDUMP="$PREBUILT_CLANG_DIR/bin/llvm-objdump" |
| readonly GNU_OBJDUMP="$PREBUILT_BINUTILS_DIR/bin/objdump" |
| |
| DEMANGLE=true |
| USE_LLVM=false |
| PATH_OBJDUMP="" |
| OBJDUMP_ARGS=(-d) |
| |
| while getopts lSrLnP: OPT; do |
| case $OPT in |
| [lSr]) OBJDUMP_ARGS+=(-$OPT) ;; |
| L) USE_LLVM=true ;; |
| n) DEMANGLE=false ;; |
| P) PATH_OBJDUMP=$OPTARG ;; |
| esac |
| done |
| shift $((OPTIND-1)) |
| |
| if $DEMANGLE; then |
| OBJDUMP_ARGS+=(--demangle) |
| fi |
| |
| if [[ $# -eq 0 ]]; then |
| fx-command-help |
| exit 1 |
| fi |
| |
| if [[ ! -z "$PATH_OBJDUMP" ]] ; then |
| readonly OBJDUMP="$PATH_OBJDUMP" |
| elif $USE_LLVM; then |
| readonly OBJDUMP="$LLVM_OBJDUMP" |
| else |
| readonly OBJDUMP="$GNU_OBJDUMP" |
| 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+=') | "\(.debug) \(.label)"' |
| |
| PATHS=($($RUN_FILTER "$FILTER")) |
| |
| if (( ${#PATHS[@]} == 0 )); then |
| fx-error "No binaries matched any of: $*" |
| exit 1 |
| fi |
| |
| disassemble() { |
| local BINARY_PATH="$1" BINARY_LABEL="$2" |
| |
| (cd "$FUCHSIA_BUILD_DIR" && "$OBJDUMP" "${OBJDUMP_ARGS[@]}" "$BINARY_PATH" > "${BINARY_PATH}.lst") |
| |
| fx-info Wrote "${BINARY_PATH}.lst" for "$BINARY_LABEL" |
| } |
| |
| i=0 |
| while (( i < ${#PATHS[@]} )); do |
| disassemble "${PATHS[$i]}" "${PATHS[$((i+1))]}" |
| ((i+=2)) |
| done |