1#!/bin/bash 2# 3# Copyright (C) 2021 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16 17### Usage: shares_common_elfs.sh [-m] [-a] <path/to/dump/directory/or/elf> 18### 19### This script is used to eliminate copies of the same ELF file(s) across 20### subdirectories of 'offline_files/' by placing common ELF(s) in 21### 'offline_files/common'. The build id is appended to each ELF name to allow 22### for different versions of the same shared library. Unless -a is used, the 23### path must be a valid ELF file. 24### 25### Options: 26### -m 27### If the ELF(s) does not currently reside in the 'common' directory, move 28### the elf to 'common' and rename it. 29### -a 30### Eliminate copies for all ELFs in a directory. The path specified point 31### to a directory and NOT an individual ELF file. 32 33usage() { 34 grep '^###' $0 | sed -e 's/^###//' 35 exit 1 36} 37 38update_elf() { 39 local elf_path="$1" 40 local move_if_not_in_common="$2" 41 42 local basename=$(basename "$elf_path") 43 local maps_path=$(dirname "$elf_path")"/maps.txt" 44 local build_id=$(readelf -n "$elf_path" | grep -oP 'Build ID: \K([\w\d]+)') 45 local new_elf_name="${basename}_${build_id}" 46 local common_dir="${ANDROID_BUILD_TOP}/system/unwinding/libunwindstack/offline_files/common/" 47 48 if [[ -f "${common_dir}${new_elf_name}" ]]; then 49 # If the ELF is already found in the common directory, delete the local copy. 50 git rm "$elf_path" 51 elif [[ $move_if_not_in_common == true ]]; then 52 # If the ELF is not found in the common directory and the `move_if_not_common` 53 # flag was set, move the local ELF to the common directory. 54 git mv "$elf_path" "${common_dir}${new_elf_name}" 55 else 56 # The ELF was not found in the common directory so exit this function. 57 return 0 58 fi 59 60 # Replace the name of the elf we just deleted/moved to the relative 61 # path to that ELF in the common directory. 62 local elf_dir_path=$(dirname "$elf_path") 63 local rel_path_to_common=$(realpath --relative-to="$elf_dir_path" "$common_dir") 64 sed -i -e "s/${basename}/${rel_path_to_common}\/${new_elf_name}/g" "$maps_path" 65} 66 67is_an_elf() { 68 if [[ $(head -c 4 $1 | cut -c2-) == "ELF" ]]; then 69 echo true 70 else 71 echo false 72 fi 73} 74 75main () { 76 set -e # abort the script if some error occurs. 77 local move_if_not_in_common=false 78 local update_all_elfs=false 79 while getopts ":hma" arg; do 80 case $arg in 81 m) 82 move_if_not_in_common=true 83 ;; 84 a) 85 update_all_elfs=true 86 ;; 87 h | *) 88 usage 89 ;; 90 esac 91 done 92 path=${@:$OPTIND:1} 93 if [[ -z $path ]]; then 94 usage 95 fi 96 97 if [[ $update_all_elfs == true ]]; then 98 if [[ ! -d $path || "${path: -1}" != "/" ]]; then 99 echo "$path is not a valid path to a directory." >&2 100 usage 101 fi 102 for elf_path in "${path}"*; do 103 if [[ $(is_an_elf $elf_path) == true ]]; then 104 update_elf $elf_path $move_if_not_in_common 105 fi 106 done 107 else 108 if [[ ! -f $path ]]; then 109 echo "$path is not a valid path to a file." >&2 110 usage 111 elif [[ $(is_an_elf $path) == false ]]; then 112 echo "$path is not a valid ELF file." >&2 113 else 114 update_elf $path $move_if_not_in_common 115 fi 116 fi 117} 118 119main "$@"