blob: ba2cc35b035a93e1681141175a194074ed8a9f9f [file] [log] [blame]
#!/bin/bash
#
# Copyright (C) 2020 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# This program fixes prebuilt ELF check errors by updating the "shared_libs"
# fields in Android.bp.
#
# Example:
# $ source build/envsetup.sh
# $ m fix_android_bp_prebuilt bpflatten bpmodify
# $ fix_android_bp_prebuilt --in-place path_to_problematic_android_bp
set -e
function usage() {
cat <<EOF
Usage:
$0 [OPTION]... FILE
Options:
--in-place
Edit file in place (overwrites source file)
--diff
Show diffs
-h, --help, --usage
Display this message and exit
EOF
}
function exit_handler() {
readonly EXIT_CODE="$?"
# Cleanup any temporary files
rm -rf "$TEMP_DIR"
exit "$EXIT_CODE"
}
trap exit_handler EXIT
function trim_space() {
echo "$1" | sed -E 's/^[[:space:]]+//;s/[[:space:]]+$//'
}
function get_prop() {
echo "${MODULE_PROP_VALUES_DICT[${1}:${2}]}"
}
function rewrite_prop() {
local ORIGINAL_VALUE=$(trim_space "$(get_prop "$1" "$2")")
if [[ -n "$ORIGINAL_VALUE" ]]; then
bpmodify -m "$1" -property "$2" -r "$ORIGINAL_VALUE" -w "$TEMP_ANDROID_BP"
fi
if [[ -n "$3" ]]; then
bpmodify -m "$1" -property "$2" -a "$3" -w "$TEMP_ANDROID_BP"
fi
}
function get_dt_needed() {
local DYNAMIC_TABLE=$($READELF -d "${ANDROID_BP_DIR}/$1")
if [[ "$?" -ne 0 ]]; then
return 1
fi
echo "$DYNAMIC_TABLE" |
sed -n -E 's/^[[:space:]]*0x[[:xdigit:]]+[[:space:]]+\(NEEDED\).*\[(.+)\.so\].*$/\1/p' |
xargs
}
function unique() {
echo "$1" | xargs -n1 | sort | uniq | xargs
}
while [[ "$1" =~ ^- ]]; do
case "$1" in
-h | --help | --usage)
usage
exit 0
;;
--in-place)
EDIT_IN_PLACE=1
;;
--diff)
SHOW_DIFF=1
;;
-x)
set -x
;;
--)
shift
break
;;
*)
echo >&2 "Unexpected flag: $1"
usage >&2
exit 1
;;
esac
shift
done
if ! [[ -f "$1" ]]; then
echo >&2 "No such file: '$1'"
exit 1
fi
if [[ -e "$(command -v llvm-readelf)" ]]; then
READELF="llvm-readelf"
elif [[ -e "$(command -v readelf)" ]]; then
READELF="readelf -W"
else
echo >&2 'Cannot find readelf in $PATH, please run:'
echo >&2 '$ source build/envsetup.sh'
exit 1
fi
if ! [[ -e "$(command -v bpflatten)" && -e "$(command -v bpmodify)" ]]; then
echo >&2 'Cannot find bpflatten and bpmodify in $PATH, please run:'
echo >&2 '$ source build/envsetup.sh'
echo >&2 '$ m blueprint_tools'
exit 1
fi
readonly EDIT_IN_PLACE
readonly SHOW_DIFF
readonly READELF
readonly ANDROID_BP="$1"
readonly ANDROID_BP_DIR=$(dirname "$ANDROID_BP")
readonly TEMP_DIR=$(mktemp -d)
readonly TEMP_ANDROID_BP="${TEMP_DIR}/Android.bp"
cp -L "$ANDROID_BP" "$TEMP_ANDROID_BP"
# This subshell and `eval` must be on separate lines, so that eval would not
# shadow the subshell's exit code.
# In other words, if `bpflatten` fails, we mustn't eval its output.
FLATTEN_COMMAND=$(bpflatten --bash "$ANDROID_BP")
eval "$FLATTEN_COMMAND"
for MODULE_NAME in "${MODULE_NAMES[@]}" ; do
MODULE_TYPE="${MODULE_TYPE_DICT[${MODULE_NAME}]}"
if ! [[ "$MODULE_TYPE" =~ ^(.+_)?prebuilt(_.+)?$ ]]; then
continue
fi
SRCS=$(get_prop "$MODULE_NAME" "srcs")
SHARED_LIBS=$(get_prop "$MODULE_NAME" "shared_libs")
if [[ -n "${SRCS}" ]]; then
DT_NEEDED=$(get_dt_needed "$SRCS")
if [[ $(unique "$DT_NEEDED") != $(unique "$SHARED_LIBS") ]]; then
rewrite_prop "$MODULE_NAME" "shared_libs" "$DT_NEEDED"
fi
fi
# Handle different arch / target variants...
for PROP in ${MODULE_PROP_KEYS_DICT[${MODULE_NAME}]} ; do
if ! [[ "$PROP" =~ \.srcs$ ]]; then
continue
fi
SRCS=$(get_prop "$MODULE_NAME" "$PROP")
DT_NEEDED=$(get_dt_needed "$SRCS")
SHARED_LIBS_PROP="${PROP%.srcs}.shared_libs"
VARIANT_SHARED_LIBS="${SHARED_LIBS} $(get_prop "$MODULE_NAME" "$SHARED_LIBS_PROP")"
if [[ $(unique "$DT_NEEDED") != $(unique "$VARIANT_SHARED_LIBS") ]]; then
rewrite_prop "$MODULE_NAME" "$SHARED_LIBS_PROP" "$DT_NEEDED"
fi
done
done
if [[ -n "$SHOW_DIFF" ]]; then
diff -u "$ANDROID_BP" "$TEMP_ANDROID_BP" || true
fi
if [[ -n "$EDIT_IN_PLACE" ]]; then
cp "$TEMP_ANDROID_BP" "$ANDROID_BP"
fi
if [[ -z "${SHOW_DIFF}${EDIT_IN_PLACE}" ]]; then
cat "$TEMP_ANDROID_BP"
fi