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 15set -e 16 17TOPDIR=$(realpath "$(dirname ${BASH_SOURCE[0]})/../../../") 18 19PATH="${TOPDIR}/prebuilts/build-tools/linux-x86/bin/:${TOPDIR}/prebuilts/python/linux-x86/current/bin/:${PATH}" 20 21command -v jq &>/dev/null || { echo >&2 "jq command not found, please install by: apt install -y jq"; exit 1; } 22command -v ninja &>/dev/null || { echo >&2 "ninja command not found, please install by: apt install -y ninja-build"; exit 1; } 23 24args=() 25cfg_groups=() 26build_variant=root 27asan_in_data=true 28while test $# -gt 0; do 29 case "$1" in 30 -g[0-9]:*) 31 cfg_groups+=(${1:2}) 32 ;; 33 --gn-args) 34 case "$2" in 35 is_asan=*);; 36 *)args+=("$1" "$2");; 37 esac 38 shift 39 ;; 40 --build-variant) 41 build_variant=$2 42 shift 43 ;; 44 --no-build) 45 no_build=true 46 ;; 47 --no-data-asan) 48 asan_in_data=false 49 ;; 50 --data-asan) 51 asan_in_data=true 52 ;; 53 *) 54 args+=("$1") 55 ;; 56 esac 57 shift 58done 59 60extra_args=( 61 --build-variant ${build_variant} 62 --disable-package-image 63 --disable-part-of-post-build output_part_rom_status 64 --disable-part-of-post-build get_warning_list 65 --disable-part-of-post-build compute_overlap_rate 66 --gn-args asan_detector=true 67 --gn-args skip_generate_module_list_file=true 68 --gn-args enable_notice_collection=false 69 # --gn-args enable_lto_O0=true 70 # --gn-args load_test_config=false 71) 72set -e -- "${extra_args[@]}" "${args[@]}" 73 74# build both asan and nonasan images 75start_time=$(date +%s) 76cd "${TOPDIR}" 77if [ -d out.a ]; then 78 if [ -d out ]; then 79 mv out out.n 80 fi 81 mv out.a out 82fi 83${no_build+echo skip} ./build.sh "$@" --gn-args is_asan=true --gn-args asan_detector=true --gn-args use_thin_lto=false --gn-args ohos_extra_cppflags="-fno-lto" --keep-ninja-going --gn-args ohos_extra_cxxflags="-fno-whole-program-vtables" --gn-args ohos_extra_cflags="-fno-whole-program-vtables" 84step1_time=$(date +%s) 85mv out out.a 86if [ -d out.n ]; then 87 mv out.n out 88fi 89${no_build+echo skip} ./build.sh "$@" --gn-args is_asan=false --gn-args asan_detector=true 90step2_time=$(date +%s) 91 92 93asan_dir=$(ls -d out.a/*/packages/phone/) 94nonasan_dir=$(ls -d out/*/packages/phone/) 95 96asan_dir=$(realpath "$asan_dir") 97nonasan_dir=$(realpath "$nonasan_dir") 98 99echo "asan dir is $asan_dir" 100echo "non-asan dir is $nonasan_dir" 101 102# check directories 103for d in {"$asan_dir","$nonasan_dir"}/{system,vendor,data} ; do 104 if [ ! -d "$d" ]; then 105 echo "directory '$d' does not exist." 106 exit 1 107 fi 108done 109 110# following works should all be done in nonasan dir 111pushd "$nonasan_dir" 112 113handle_error() { 114 errcode=$? 115 trap '' INT HUP 116 set +e 117 if [ $errcode -ne 0 ]; then 118 pushd "$nonasan_dir" 119 test -d system.bak && rm -rf system && mv system.bak system 120 test -d vendor.bak && rm -rf vendor && mv vendor.bak vendor 121 test -d images.bak && rm -rf images && mv images.bak images 122 test -f "${TOPDIR}"/build/ohos/images/build_image.py.bak && mv "$_" "${_%.bak}" 123 test -f "${TOPDIR}"/build/ohos/images/mkimage/dac.txt.bak && mv "$_" "${_%.bak}" 124 fi 125 command -v handle_error_hook && handle_error_hook $errcode "$@" 126 exit $errcode 127} 128trap 'handle_error "${args[@]}"' EXIT 129 130# get make image command 131json_data="$(ninja -w dupbuild=warn -C ../../ -t compdb | jq '.[]|select(.output|startswith("packages/phone/images/"))')" 132make_system_img_cmd="$(echo "$json_data" | jq -r 'select(.output=="packages/phone/images/system.img")|.command')" 133make_vendor_img_cmd="$(echo "$json_data" | jq -r 'select(.output=="packages/phone/images/vendor.img")|.command')" 134make_userdata_img_cmd="$(echo "$json_data" | jq -r 'select(.output=="packages/phone/images/userdata.img")|.command')" 135make_system_img() { pushd ../../; $make_system_img_cmd; popd; } 136make_vendor_img() { pushd ../../; $make_vendor_img_cmd; popd; } 137make_userdata_img() { pushd ../../; $make_userdata_img_cmd; popd; } 138 139make_mixed_asan_img() { 140 echo "make mixed asan system$1.img or/and vendor$1.img ..." 141 cfg_group=(${@:2}) 142 143 # backup system and vendor 144 mv system system.bak && cp -a system.bak system 145 mv vendor vendor.bak && cp -a vendor.bak vendor 146 147 # prepare asan related files for system image 148 cp -a "$asan_dir"/system/etc/asan.options system/etc/ 149 cp -a "$asan_dir"/system/etc/init/asan.cfg system/etc/init/ 150 cp -a "$asan_dir"/system/lib/ld-musl-*-asan.so.1 system/lib/ 151 if grep -qw LD_PRELOAD system/etc/init/faultloggerd.cfg; then 152 sed -i '/LD_PRELOAD/d' system/etc/init/asan.cfg 153 sed -i 's/LD_PRELOAD\s\+/&libasan_helper.z.so:/g' system/etc/init/faultloggerd.cfg 154 fi 155 test -f system/etc/selinux/config && sed -i 's,enforcing,permissive,g' $_ 156 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 157 sed -i '/^\s*namespace.default.asan.lib.paths\s*=/s/\/\(system\|vendor\)\/\([^:]*:\?\)/\/\1\/asan\/\2/g' system/etc/ld-musl-namespace-*.ini 158 if [ "$asan_in_data" = true ]; then 159 for d in data/asan/*; do ln -snf /$d ${d#data/asan/}/asan; done 160 else 161 mkdir -p system/asan/ && cp -a "$asan_dir"/system/{lib*,bin} $_ 162 mkdir -p vendor/asan/ && cp -a "$asan_dir"/vendor/{lib*,bin} $_ 163 sed -i.bak '$asystem/asan/bin/*, 00755, 0, 2000, 0\nvendor/asan/bin/*, 00755, 0, 2000, 0' "${TOPDIR}"/build/ohos/images/mkimage/dac.txt 164 fi 165 166 # make some services run in asan version 167 local -A make_images 168 for f in ${cfg_group[@]}; do 169 for cfg in {system,vendor}/etc/init/$f.cfg*; do 170 echo -e "\033[35mModifying service cfg: $cfg\033[0m" 171 sed -i 's,/bin/,/asan&,g;/"critical"/d' $cfg 172 make_images[${cfg::6}]=true 173 done 174 done 175 176 command -v make_mixed_asan_img_hook && make_mixed_asan_img_hook "$@" 177 178 # make image 179 if [ "${make_images[system]}" = true -o $# -eq 0 ]; then 180 make_system_img 181 mv images/system.img system${1}.img 182 fi 183 if [ "${make_images[vendor]}" = true -o $# -eq 0 ]; then 184 make_vendor_img 185 mv images/vendor.img vendor${1}.img 186 fi 187 188 # restore dac.txt 189 if [ "$asan_in_data" != true ]; then 190 mv "${TOPDIR}"/build/ohos/images/mkimage/dac.txt.bak "${TOPDIR}"/build/ohos/images/mkimage/dac.txt 191 fi 192 193 # restore system and vendor 194 rm -rf system && mv system.bak system 195 rm -rf vendor && mv vendor.bak vendor 196} 197 198add_mkshrc() { 199 sed -i '/export HOME /d' "$asan_dir"/system/etc/init/asan.cfg 200 sed -i '/export ASAN_OPTIONS /i"export HOME /'$1'",' "$asan_dir"/system/etc/init/asan.cfg 201 cat <<EOF >${1:-.}/.mkshrc 202dmesg -n1 203alias ls='ls --color=auto' 204alias ll='ls -al' 205remount() { 206 mount -o remount,rw \${1:-/} 207} 208EOF 209} 210 211make_data_asan_img() { 212 test $asan_in_data = true || return 0 213 echo "make mixed asan userdata.img ..." 214 mkdir -p data/asan/{vendor,system} 215 cp -a "$asan_dir"/vendor/{lib*,bin} data/asan/vendor/ 216 cp -a "$asan_dir"/system/{lib*,bin} data/asan/system/ 217 chmod +x data/asan/*/bin/* 218 add_mkshrc data/ 219 sed -i.bak 's,shutil.rmtree(userdata_path),return,g' "${TOPDIR}"/build/ohos/images/build_image.py 220 sed -i.bak '$adata/asan/*, 00755, 0, 2000, 0' "${TOPDIR}"/build/ohos/images/mkimage/dac.txt 221 make_userdata_img 222 mv "${TOPDIR}"/build/ohos/images/mkimage/dac.txt.bak "${TOPDIR}"/build/ohos/images/mkimage/dac.txt 223 mv "${TOPDIR}"/build/ohos/images/build_image.py.bak "${TOPDIR}"/build/ohos/images/build_image.py 224} 225 226make_custom_asan_imgs() { 227 # backup images 228 mv images images.bak && mkdir images 229 230 # make custom asan images 231 for cfg_group in ${cfg_groups[@]}; do 232 make_mixed_asan_img $(IFS=:,; echo ${cfg_group}) 233 done 234 235 # restore images 236 rm -rf images && mv images.bak images 237} 238 239# Collect all necessary artifacts into images directory 240collect_all_artifacts() { 241 # uncomment the following three lines if you need full asan images 242 #rm -rf images/{system,vendor}F.img 243 #cp -l "$asan_dir"/images/system.img images/systemF.img 244 #cp -l "$asan_dir"/images/vendor.img images/vendorF.img 245 # unstripped binaries 246 rm -rf images/unstripped 247 mkdir -p images/unstripped/{asan,nonasan} 248 cp -al "$asan_dir"/../../{exe,lib}.unstripped images/unstripped/asan/ 249 cp "$asan_dir"/../../libclang_rt.asan.so images/unstripped/asan/lib.unstripped/ 250 cp -al ../../{exe,lib}.unstripped images/unstripped/nonasan/ 251 cp system/lib*/libc++.so images/unstripped/nonasan/lib.unstripped/ 252 # mixed asan images 253 mv system*.img vendor*.img images/ 254} 255 256shopt -s nullglob 257 258make_data_asan_img 259make_mixed_asan_img 260make_custom_asan_imgs 261collect_all_artifacts 262 263step3_time=$(date +%s) 264 265echo -e "\033[32m==== Done! ====\033[0m" 266echo "asan build cost $((${step1_time}-${start_time}))s, nonasan build cost $((${step2_time}-${step1_time}))s, image build cost $((${step3_time}-${step2_time}))s" 267popd 268