| #! /bin/bash -eu |
| |
| # This script prints linker trace for a given ELF file. |
| # It extracts the command that has built this ELF file from the |
| # build log (verbose.log.gz file in the given output directory), |
| # appends `-t` linker option to it in order to print its source |
| # files and runs this command |
| # This script can be used when we want to compare ELF executables |
| # built by two different configurations (e.g., conventional and mixed |
| # builds). In this case, we run the build for one configuration, then |
| # rename `out` directory to something else, and then run the build |
| # for another configuration. To accommodate this scenario, an optional |
| # second argument specifies the renamed output directory. The linker |
| # command then runs inside nsjail that maps the renamed output |
| # directory to `out`. |
| |
| function die() { format=$1; shift; printf >&2 "$format\n" $@; exit 1; } |
| function usage() { |
| die "usage: ${0##*/} [-v] ELF [DIR]" |
| } |
| |
| # Delouse |
| declare show_command= |
| while getopts "v" opt; do |
| case $opt in |
| v) show_command=t ;; |
| *) usage ;; |
| esac |
| done |
| shift $(($OPTIND-1)) |
| (($# >= 1)) || usage |
| |
| declare -r elf="$1"; shift |
| declare -r outdir="${1:-out}" |
| [[ -d "$outdir" ]] || die "$outdir does not exist" |
| [[ -f "$outdir/verbose.log.gz" ]] || \ |
| die "$outdir does not contain Android build (verbose.log.gz is missing)" |
| |
| function zgrep_command() { |
| zgrep -e "bin/clang\+\+.* -o [^ ]*$elf " $outdir/verbose.log.gz |
| } |
| |
| # Locate the command that builds this ELF file and write it to |
| # the temporary file editing it on the way: |
| # * remove step number (`[nn/NN]`) prefix |
| # * linker should write to the bit bucket |
| # * add `-Wl,-t` (linker's `-t` option) |
| cmdfile=$(mktemp); trap 'rm -f $cmdfile' EXIT |
| zgrep_command |\ |
| sed -r 's| -o ([^ ]+) | -Wl,-t -o /dev/null |;s|^\[.*\]||' > $cmdfile |
| [[ -z "${show_command}" ]] || cat $cmdfile >&2 |
| [[ -s $cmdfile ]] || die "no ELF file ending with $elf was built in $outdir" |
| (($(wc -l $cmdfile | cut -f1 -d ' ') == 1)) || \ |
| { printf >&2 "Multiple elf files ending with $elf were built in $outdir:\n"; |
| die " %s" $(zgrep_command | sed -r 's|.* -o ([^ ]+) .*|\1|'); } |
| |
| # Run the linker (i.e., the command we have written into $cmdfile). Its output |
| # is the list of the object files it read. If output directory has been renamed, |
| # run it inside `nsjail`, mapping output directory ot `out/` |
| if [[ "$outdir" == out ]]; then |
| /bin/bash $cmdfile |
| else |
| prebuilts/build-tools/linux-x86/bin/nsjail \ |
| -Mo -q -e -t 0 -B / -B /tmp -B $(realpath $outdir):$PWD/out \ |
| --cwd $PWD --skip_setsid --keep_caps --disable_clone_newcgroup --disable_clone_newnet \ |
| --rlimit_as soft --rlimit_core soft --rlimit_cpu soft --rlimit_fsize soft --rlimit_nofile soft \ |
| --proc_rw --hostname "$(hostname)" -- /bin/bash $cmdfile |
| fi |