1#!/bin/bash 2# Copyright (c) 2022 Huawei Device Co., Ltd. 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15TOPDIR=$(realpath "$(dirname ${BASH_SOURCE[0]})/../../../") 16 17PATH="${TOPDIR}/prebuilts/build-tools/linux-x86/bin/:${TOPDIR}/prebuilts/python/linux-x86/3.9.2/bin/:${PATH}" 18 19command -v jq &>/dev/null || { echo >&2 "jq command not found, please install by: apt install -y jq"; exit 1; } 20command -v ninja &>/dev/null || { echo >&2 "ninja command not found, please install by: apt install -y ninja-build"; exit 1; } 21 22args=() 23cfg_groups=() 24build_variant=root 25while test $# -gt 0; do 26 case "$1" in 27 -g[0-9]:*) 28 cfg_groups+=(${1:2}) 29 ;; 30 --gn-args) 31 case "$2" in 32 is_asan=*);; 33 *)args+=("$1" "$2");; 34 esac 35 shift 36 ;; 37 --build-variant) 38 build_variant=$2 39 shift 40 ;; 41 --no-build) 42 no_build=true 43 shift 44 ;; 45 *) 46 args+=("$1") 47 ;; 48 esac 49 shift 50done 51 52set -e -- "${args[@]}" 53 54# build both asan and nonasan images 55start_time=$(date +%s) 56cd "${TOPDIR}" 57if [ -d out.a ]; then 58 if [ -d out ]; then 59 mv out out.n 60 fi 61 mv out.a out 62fi 63${no_build+echo skip} ./build.sh "$@" --gn-args is_asan=true --build-variant ${build_variant} 64step1_time=$(date +%s) 65mv out out.a 66if [ -d out.n ]; then 67 mv out.n out 68fi 69${no_build+echo skip} ./build.sh "$@" --gn-args is_asan=false --build-variant ${build_variant} 70step2_time=$(date +%s) 71 72 73asan_dir=$(ls -d out.a/*/packages/phone/) 74nonasan_dir=$(ls -d out/*/packages/phone/) 75 76asan_dir=$(realpath "$asan_dir") 77nonasan_dir=$(realpath "$nonasan_dir") 78 79echo "asan dir is $asan_dir" 80echo "non-asan dir is $nonasan_dir" 81 82# check directories 83for d in {"$asan_dir","$nonasan_dir"}/{system,vendor,data} ; do 84 if [ ! -d "$d" ]; then 85 echo "directory '$d' does not exist." 86 exit 1 87 fi 88done 89 90# following works should all be done in nonasan dir 91pushd "$nonasan_dir" 92 93handle_error() { 94 if [ "$?" -ne 0 ]; then 95 set +e 96 pushd "$nonasan_dir" 97 test -d system.bak && rm -rf system && mv system.bak system 98 test -d vendor.bak && rm -rf vendor && mv vendor.bak vendor 99 test -d images.bak && rm -rf images && mv images.bak images 100 fi 101} 102trap handle_error EXIT 103 104# get make image command 105json_data="$(ninja -w dupbuild=warn -C ../../ -t compdb | jq '.[]|select(.output|startswith("packages/phone/images/"))')" 106make_system_img_cmd="$(echo "$json_data" | jq -r 'select(.output=="packages/phone/images/system.img")|.command')" 107make_vendor_img_cmd="$(echo "$json_data" | jq -r 'select(.output=="packages/phone/images/vendor.img")|.command')" 108make_userdata_img_cmd="$(echo "$json_data" | jq -r 'select(.output=="packages/phone/images/userdata.img")|.command')" 109make_system_img() { pushd ../../; $make_system_img_cmd; popd; } 110make_vendor_img() { pushd ../../; $make_vendor_img_cmd; popd; } 111make_userdata_img() { pushd ../../; $make_userdata_img_cmd; popd; } 112 113make_mixed_asan_img() { 114 echo "make mixed asan system$1.img or/and vendor$1.img ..." 115 cfg_group=(${@:2}) 116 117 # backup system and vendor 118 mv system system.bak && cp -a system.bak system 119 mv vendor vendor.bak && cp -a vendor.bak vendor 120 121 # prepare asan related files for system image 122 cp -a "$asan_dir"/system/etc/asan.options system/etc/ 123 cp -a "$asan_dir"/system/etc/init/asan.cfg system/etc/init/ 124 cp -a "$asan_dir"/system/lib/ld-musl-*-asan.so.1 system/lib/ 125 cp -a "$asan_dir"/system/etc/ld-musl-*-asan.path system/etc/ 126 sed -i 's/LD_PRELOAD\s\+/&libasan_helper.z.so:/g' system/etc/init/faultloggerd.cfg 127 sed -i 's,enforcing,permissive,g' system/etc/selinux/config || : 128 sed -i 's,/system/\([^:]*\),/data/\1:&,g' system/etc/ld-musl-*-asan.path 129 sed -i '/^\s*namespace.default.asan.lib.paths\s*=/d;s/^\(\s*namespace.default.\)\(lib.paths\s*=.*\)$/&\n\1asan.\2/g' system/etc/ld-musl-namespace-*.ini 130 sed -i '/^\s*namespace.default.asan.lib.paths\s*=/s/\/\(system\|vendor\)\/\([^:]*:\?\)/\/data\/\2/g' system/etc/ld-musl-namespace-*.ini 131 132 # make some services run in asan version 133 local make_system=false 134 local make_vendor=false 135 for f in ${cfg_group[@]/%/.cfg}; do 136 if [ -f system/etc/init/$f ]; then 137 echo "$f is found in /system/etc/init/" 138 sed -i 's,/system/bin/,/data/bin/,g' system/etc/init/$f 139 sed -i '/"critical"/d' system/etc/init/$f 140 for xml in $(sed -n '/\/data\/bin\/sa_main/s/.*"\([^" ]*.xml\)".*/\1/p' system/etc/init/$f); do 141 sed -i 's,/system/\(lib[^/]*\)/,/data/\1/,g' ./$xml 142 done 143 make_system=true 144 elif [ -f vendor/etc/init/$f ]; then 145 echo "$f is found in /vendor/etc/init/" 146 sed -i 's,/vendor/bin/,/data/bin/,g' vendor/etc/init/$f 147 sed -i 's,/system/bin/,/data/bin/,g' vendor/etc/init/$f 148 sed -i '/"critical"/d' vendor/etc/init/$f 149 for xml in $(sed -n '/\/data\/bin\/sa_main/s/.*"\([^" ]*.xml\)".*/\1/p' vendor/etc/init/$f); do 150 sed -i 's,/vendor/\(lib[^/]*\)/,/data/\1/,g' ./$xml 151 sed -i 's,/system/\(lib[^/]*\)/,/data/\1/,g' ./$xml 152 done 153 make_vendor=true 154 else 155 echo -e "\033[33m==== WARNING: $f is not found in /system/etc/init/ nor in /vendor/etc/init/ ====\033[0m" 156 fi 157 done 158 159 # make image 160 if [ "$make_system" = true -o $# -eq 0 ]; then 161 make_system_img 162 mv images/system.img system${1}.img 163 fi 164 if [ "$make_vendor" = true ]; then 165 make_vendor_img 166 mv images/vendor.img vendor${1}.img 167 fi 168 169 # restore system and vendor 170 rm -rf system && mv system.bak system 171 rm -rf vendor && mv vendor.bak vendor 172} 173 174add_mkshrc() { 175 sed -i '/export HOME /d' "$asan_dir"/system/etc/init/asan.cfg 176 sed -i '/export ASAN_OPTIONS /i"export HOME /data",' "$asan_dir"/system/etc/init/asan.cfg 177 cat <<EOF >${1:-.}/.mkshrc 178dmesg -n1 179alias ls='ls --color=auto' 180alias ll='ls -al' 181remount() { 182 mount -o remount,rw \${1:-/} 183} 184EOF 185} 186 187# $1 file that need to be patched 188# $2 file offset 189# $3 instruction count, 4 bytes per instruction on arm architecture 190patch_file_nop() { 191 while true; do echo -e -n "\x1F\x20\x03\xD5"; done | dd conv=notrunc bs=1 of=$1 seek=$2 count=$((4*$3)) 192} 193 194make_data_asan_img() { 195 echo "make mixed asan userdata.img ..." 196 cp -a "$asan_dir"/vendor/{lib*,bin} data/ 197 cp -a "$asan_dir"/system/{lib*,bin} data/ 198 add_mkshrc data/ 199 sed -i.bak 's,shutil.rmtree(userdata_path),return,g' "${TOPDIR}"/build/ohos/images/build_image.py 200 sed -i.bak '$adata/bin/*, 00755, 0, 2000, 0' "${TOPDIR}"/build/ohos/images/mkimage/dac.txt 201 if [ -f data/lib64/libclang_rt.asan.so ]; then 202 if [ "$(md5sum data/lib64/libclang_rt.asan.so|awk '{print $1}')" = "e4ade6eb02f6bbbd7f7faebcda3f0a26" ]; then 203 patch_file_nop data/lib64/libclang_rt.asan.so 356872 17 # patch function 'GetThreadStackAndTls' 204 fi 205 fi 206 make_userdata_img 207 mv "${TOPDIR}"/build/ohos/images/mkimage/dac.txt.bak "${TOPDIR}"/build/ohos/images/mkimage/dac.txt 208 mv "${TOPDIR}"/build/ohos/images/build_image.py.bak "${TOPDIR}"/build/ohos/images/build_image.py 209} 210 211make_custom_asan_imgs() { 212 # backup images 213 mv images images.bak && mkdir images 214 215 # make custom asan images 216 for cfg_group in ${cfg_groups[@]}; do 217 local old_lfs="$IFS" 218 IFS+=":," 219 make_mixed_asan_img ${cfg_group} 220 IFS="$old_lfs" 221 done 222 223 # restore images 224 rm -rf images && mv images.bak images 225} 226 227make_data_asan_img 228make_mixed_asan_img 229make_custom_asan_imgs 230 231# Collect all necessary artifacts into images directory 232if [ -f "$asan_dir"/images/system.img ]; then 233 # full asan images 234 mv "$asan_dir"/images/system.img images/systemF.img 235 mv "$asan_dir"/images/vendor.img images/vendorF.img 236 # unstripped binaries 237 rm -rf images/unstripped 238 mkdir -p images/unstripped/{asan,nonasan} 239 mv "$asan_dir"/../../{exe,lib}.unstripped images/unstripped/asan/ 240 cp "$asan_dir"/../../libclang_rt.asan.so images/unstripped/asan/lib.unstripped/ 241 mv ../../{exe,lib}.unstripped images/unstripped/nonasan/ 242 # asan log resolve scripts 243 cp "${TOPDIR}"/build/common/asan/{symbolize,resolve_asan_log}.sh images/ 244 chmod +x images/*.sh 245fi 246 247shopt -s nullglob && mv system*.img vendor*.img images/ 248step3_time=$(date +%s) 249 250echo -e "\033[32m==== Done! ====\033[0m" 251echo "asan build cost $((${step1_time}-${start_time}))s, nonasan build cost $((${step2_time}-${step1_time}))s, image build cost $((${step3_time}-${step2_time}))s" 252popd 253