• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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