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