1*8975f5c5SAndroid Build Coastguard Worker#!/bin/bash 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2012 The Chromium Authors 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker# 6*8975f5c5SAndroid Build Coastguard Worker# Saves the gdb index for a given binary and its shared library dependencies. 7*8975f5c5SAndroid Build Coastguard Worker# 8*8975f5c5SAndroid Build Coastguard Worker# This will run gdb index in parallel on a number of binaries using SIGUSR1 9*8975f5c5SAndroid Build Coastguard Worker# as the communication mechanism to simulate a semaphore. Because of the 10*8975f5c5SAndroid Build Coastguard Worker# nature of this technique, using "set -e" is very difficult. The SIGUSR1 11*8975f5c5SAndroid Build Coastguard Worker# terminates a "wait" with an error which we need to interpret. 12*8975f5c5SAndroid Build Coastguard Worker# 13*8975f5c5SAndroid Build Coastguard Worker# When modifying this code, most of the real logic is in the index_one_file 14*8975f5c5SAndroid Build Coastguard Worker# function. The rest is cleanup + sempahore plumbing. 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard Workerfunction usage_exit { 17*8975f5c5SAndroid Build Coastguard Worker echo "Usage: $0 [-f] [-r] [-n] <paths-to-binaries>..." 18*8975f5c5SAndroid Build Coastguard Worker echo " -f forces replacement of an existing index." 19*8975f5c5SAndroid Build Coastguard Worker echo " -r removes the index section." 20*8975f5c5SAndroid Build Coastguard Worker echo " -n don't extract the dependencies of each binary with lld." 21*8975f5c5SAndroid Build Coastguard Worker echo " e.g., $0 -n out/Debug/lib.unstripped/lib*" 22*8975f5c5SAndroid Build Coastguard Worker echo 23*8975f5c5SAndroid Build Coastguard Worker echo " Set TOOLCHAIN_PREFIX to use a non-default set of binutils." 24*8975f5c5SAndroid Build Coastguard Worker exit 1 25*8975f5c5SAndroid Build Coastguard Worker} 26*8975f5c5SAndroid Build Coastguard Worker 27*8975f5c5SAndroid Build Coastguard Worker# Cleanup temp directory and ensure all child jobs are dead-dead. 28*8975f5c5SAndroid Build Coastguard Workerfunction on_exit { 29*8975f5c5SAndroid Build Coastguard Worker trap "" EXIT USR1 # Avoid reentrancy. 30*8975f5c5SAndroid Build Coastguard Worker 31*8975f5c5SAndroid Build Coastguard Worker local jobs=$(jobs -p) 32*8975f5c5SAndroid Build Coastguard Worker if [ -n "$jobs" ]; then 33*8975f5c5SAndroid Build Coastguard Worker echo -n "Killing outstanding index jobs..." 34*8975f5c5SAndroid Build Coastguard Worker kill -KILL $(jobs -p) 35*8975f5c5SAndroid Build Coastguard Worker wait 36*8975f5c5SAndroid Build Coastguard Worker echo "done" 37*8975f5c5SAndroid Build Coastguard Worker fi 38*8975f5c5SAndroid Build Coastguard Worker 39*8975f5c5SAndroid Build Coastguard Worker if [ -d "$directory" ]; then 40*8975f5c5SAndroid Build Coastguard Worker echo -n "Removing temp directory $directory..." 41*8975f5c5SAndroid Build Coastguard Worker rm -rf "$directory" 42*8975f5c5SAndroid Build Coastguard Worker echo done 43*8975f5c5SAndroid Build Coastguard Worker fi 44*8975f5c5SAndroid Build Coastguard Worker} 45*8975f5c5SAndroid Build Coastguard Worker 46*8975f5c5SAndroid Build Coastguard Worker# Add index to one binary. 47*8975f5c5SAndroid Build Coastguard Workerfunction index_one_file { 48*8975f5c5SAndroid Build Coastguard Worker local file=$1 49*8975f5c5SAndroid Build Coastguard Worker local basename=$(basename "$file") 50*8975f5c5SAndroid Build Coastguard Worker local should_index_this_file="${should_index}" 51*8975f5c5SAndroid Build Coastguard Worker 52*8975f5c5SAndroid Build Coastguard Worker local readelf_out=$(${TOOLCHAIN_PREFIX}readelf -S "$file") 53*8975f5c5SAndroid Build Coastguard Worker if [[ $readelf_out =~ "gdb_index" ]]; then 54*8975f5c5SAndroid Build Coastguard Worker if $remove_index; then 55*8975f5c5SAndroid Build Coastguard Worker ${TOOLCHAIN_PREFIX}objcopy --remove-section .gdb_index "$file" 56*8975f5c5SAndroid Build Coastguard Worker echo "Removed index from $basename." 57*8975f5c5SAndroid Build Coastguard Worker else 58*8975f5c5SAndroid Build Coastguard Worker echo "Skipped $basename -- already contains index." 59*8975f5c5SAndroid Build Coastguard Worker should_index_this_file=false 60*8975f5c5SAndroid Build Coastguard Worker fi 61*8975f5c5SAndroid Build Coastguard Worker fi 62*8975f5c5SAndroid Build Coastguard Worker 63*8975f5c5SAndroid Build Coastguard Worker if $should_index_this_file; then 64*8975f5c5SAndroid Build Coastguard Worker local start=$(date +"%s%N") 65*8975f5c5SAndroid Build Coastguard Worker echo "Adding index to $basename..." 66*8975f5c5SAndroid Build Coastguard Worker 67*8975f5c5SAndroid Build Coastguard Worker ${TOOLCHAIN_PREFIX}gdb -batch "$file" -ex "save gdb-index $directory" \ 68*8975f5c5SAndroid Build Coastguard Worker -ex "quit" 69*8975f5c5SAndroid Build Coastguard Worker local index_file="$directory/$basename.gdb-index" 70*8975f5c5SAndroid Build Coastguard Worker if [ -f "$index_file" ]; then 71*8975f5c5SAndroid Build Coastguard Worker ${TOOLCHAIN_PREFIX}objcopy --add-section .gdb_index="$index_file" \ 72*8975f5c5SAndroid Build Coastguard Worker --set-section-flags .gdb_index=readonly "$file" "$file" 73*8975f5c5SAndroid Build Coastguard Worker local finish=$(date +"%s%N") 74*8975f5c5SAndroid Build Coastguard Worker local elapsed=$(((finish - start) / 1000000)) 75*8975f5c5SAndroid Build Coastguard Worker echo " ...$basename indexed. [${elapsed}ms]" 76*8975f5c5SAndroid Build Coastguard Worker else 77*8975f5c5SAndroid Build Coastguard Worker echo " ...$basename unindexable." 78*8975f5c5SAndroid Build Coastguard Worker fi 79*8975f5c5SAndroid Build Coastguard Worker fi 80*8975f5c5SAndroid Build Coastguard Worker} 81*8975f5c5SAndroid Build Coastguard Worker 82*8975f5c5SAndroid Build Coastguard Worker# Functions that when combined, concurrently index all files in FILES_TO_INDEX 83*8975f5c5SAndroid Build Coastguard Worker# array. The global FILES_TO_INDEX is declared in the main body of the script. 84*8975f5c5SAndroid Build Coastguard Workerfunction async_index { 85*8975f5c5SAndroid Build Coastguard Worker # Start a background subshell to run the index command. 86*8975f5c5SAndroid Build Coastguard Worker { 87*8975f5c5SAndroid Build Coastguard Worker index_one_file $1 88*8975f5c5SAndroid Build Coastguard Worker kill -SIGUSR1 $$ # $$ resolves to the parent script. 89*8975f5c5SAndroid Build Coastguard Worker exit 129 # See comment above wait loop at bottom. 90*8975f5c5SAndroid Build Coastguard Worker } & 91*8975f5c5SAndroid Build Coastguard Worker} 92*8975f5c5SAndroid Build Coastguard Worker 93*8975f5c5SAndroid Build Coastguard Workercur_file_num=0 94*8975f5c5SAndroid Build Coastguard Workerfunction index_next { 95*8975f5c5SAndroid Build Coastguard Worker if ((cur_file_num >= ${#files_to_index[@]})); then 96*8975f5c5SAndroid Build Coastguard Worker return 97*8975f5c5SAndroid Build Coastguard Worker fi 98*8975f5c5SAndroid Build Coastguard Worker 99*8975f5c5SAndroid Build Coastguard Worker async_index "${files_to_index[cur_file_num]}" 100*8975f5c5SAndroid Build Coastguard Worker ((cur_file_num += 1)) || true 101*8975f5c5SAndroid Build Coastguard Worker} 102*8975f5c5SAndroid Build Coastguard Worker 103*8975f5c5SAndroid Build Coastguard Worker######## 104*8975f5c5SAndroid Build Coastguard Worker### Main body of the script. 105*8975f5c5SAndroid Build Coastguard Worker 106*8975f5c5SAndroid Build Coastguard Workerremove_index=false 107*8975f5c5SAndroid Build Coastguard Workershould_index=true 108*8975f5c5SAndroid Build Coastguard Workershould_index_deps=true 109*8975f5c5SAndroid Build Coastguard Workerfiles_to_index=() 110*8975f5c5SAndroid Build Coastguard Workerwhile (($# > 0)); do 111*8975f5c5SAndroid Build Coastguard Worker case "$1" in 112*8975f5c5SAndroid Build Coastguard Worker -h) 113*8975f5c5SAndroid Build Coastguard Worker usage_exit 114*8975f5c5SAndroid Build Coastguard Worker ;; 115*8975f5c5SAndroid Build Coastguard Worker -f) 116*8975f5c5SAndroid Build Coastguard Worker remove_index=true 117*8975f5c5SAndroid Build Coastguard Worker ;; 118*8975f5c5SAndroid Build Coastguard Worker -r) 119*8975f5c5SAndroid Build Coastguard Worker remove_index=true 120*8975f5c5SAndroid Build Coastguard Worker should_index=false 121*8975f5c5SAndroid Build Coastguard Worker ;; 122*8975f5c5SAndroid Build Coastguard Worker -n) 123*8975f5c5SAndroid Build Coastguard Worker should_index_deps=false 124*8975f5c5SAndroid Build Coastguard Worker ;; 125*8975f5c5SAndroid Build Coastguard Worker -*) 126*8975f5c5SAndroid Build Coastguard Worker echo "Invalid option: $1" >&2 127*8975f5c5SAndroid Build Coastguard Worker usage_exit 128*8975f5c5SAndroid Build Coastguard Worker ;; 129*8975f5c5SAndroid Build Coastguard Worker *) 130*8975f5c5SAndroid Build Coastguard Worker if [[ ! -f "$1" ]]; then 131*8975f5c5SAndroid Build Coastguard Worker echo "Path $1 does not exist." 132*8975f5c5SAndroid Build Coastguard Worker exit 1 133*8975f5c5SAndroid Build Coastguard Worker fi 134*8975f5c5SAndroid Build Coastguard Worker files_to_index+=("$1") 135*8975f5c5SAndroid Build Coastguard Worker ;; 136*8975f5c5SAndroid Build Coastguard Worker esac 137*8975f5c5SAndroid Build Coastguard Worker shift 138*8975f5c5SAndroid Build Coastguard Workerdone 139*8975f5c5SAndroid Build Coastguard Worker 140*8975f5c5SAndroid Build Coastguard Workerif ((${#files_to_index[@]} == 0)); then 141*8975f5c5SAndroid Build Coastguard Worker usage_exit 142*8975f5c5SAndroid Build Coastguard Workerfi 143*8975f5c5SAndroid Build Coastguard Worker 144*8975f5c5SAndroid Build Coastguard Workerdependencies=() 145*8975f5c5SAndroid Build Coastguard Workerif $should_index_deps; then 146*8975f5c5SAndroid Build Coastguard Worker for file in "${files_to_index[@]}"; do 147*8975f5c5SAndroid Build Coastguard Worker # Append the shared library dependencies of this file that 148*8975f5c5SAndroid Build Coastguard Worker # have the same dirname. The dirname is a signal that these 149*8975f5c5SAndroid Build Coastguard Worker # shared libraries were part of the same build as the binary. 150*8975f5c5SAndroid Build Coastguard Worker dependencies+=( \ 151*8975f5c5SAndroid Build Coastguard Worker $(ldd "$file" 2>/dev/null \ 152*8975f5c5SAndroid Build Coastguard Worker | grep $(dirname "$file") \ 153*8975f5c5SAndroid Build Coastguard Worker | sed "s/.*[ \t]\(.*\) (.*/\1/") \ 154*8975f5c5SAndroid Build Coastguard Worker ) 155*8975f5c5SAndroid Build Coastguard Worker done 156*8975f5c5SAndroid Build Coastguard Workerfi 157*8975f5c5SAndroid Build Coastguard Workerfiles_to_index+=("${dependencies[@]}") 158*8975f5c5SAndroid Build Coastguard Worker 159*8975f5c5SAndroid Build Coastguard Worker# Ensure we cleanup on on exit. 160*8975f5c5SAndroid Build Coastguard Workertrap on_exit EXIT INT 161*8975f5c5SAndroid Build Coastguard Worker 162*8975f5c5SAndroid Build Coastguard Worker# We're good to go! Create temp directory for index files. 163*8975f5c5SAndroid Build Coastguard Workerdirectory=$(mktemp -d) 164*8975f5c5SAndroid Build Coastguard Workerecho "Made temp directory $directory." 165*8975f5c5SAndroid Build Coastguard Worker 166*8975f5c5SAndroid Build Coastguard Worker# Start concurrent indexing. 167*8975f5c5SAndroid Build Coastguard Workertrap index_next USR1 168*8975f5c5SAndroid Build Coastguard Worker 169*8975f5c5SAndroid Build Coastguard Worker# 4 is an arbitrary default. When changing, remember we are likely IO bound 170*8975f5c5SAndroid Build Coastguard Worker# so basing this off the number of cores is not sensible. 171*8975f5c5SAndroid Build Coastguard Workerindex_tasks=${INDEX_TASKS:-4} 172*8975f5c5SAndroid Build Coastguard Workerfor ((i = 0; i < index_tasks; i++)); do 173*8975f5c5SAndroid Build Coastguard Worker index_next 174*8975f5c5SAndroid Build Coastguard Workerdone 175*8975f5c5SAndroid Build Coastguard Worker 176*8975f5c5SAndroid Build Coastguard Worker# Do a wait loop. Bash waits that terminate due a trap have an exit 177*8975f5c5SAndroid Build Coastguard Worker# code > 128. We also ensure that our subshell's "normal" exit occurs with 178*8975f5c5SAndroid Build Coastguard Worker# an exit code > 128. This allows us to do consider a > 128 exit code as 179*8975f5c5SAndroid Build Coastguard Worker# an indication that the loop should continue. Unfortunately, it also means 180*8975f5c5SAndroid Build Coastguard Worker# we cannot use set -e since technically the "wait" is failing. 181*8975f5c5SAndroid Build Coastguard Workerwait 182*8975f5c5SAndroid Build Coastguard Workerwhile (($? > 128)); do 183*8975f5c5SAndroid Build Coastguard Worker wait 184*8975f5c5SAndroid Build Coastguard Workerdone 185