Created
May 12, 2017 19:38
-
-
Save S1GSEGV/772db2143671242fe18787dfaee34295 to your computer and use it in GitHub Desktop.
asan_device_setup on Mac
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
#===- lib/asan/scripts/asan_device_setup -----------------------------------===# | |
# | |
# The LLVM Compiler Infrastructure | |
# | |
# This file is distributed under the University of Illinois Open Source | |
# License. See LICENSE.TXT for details. | |
# | |
# Prepare Android device to run ASan applications. | |
# | |
#===------------------------------------------------------------------------===# | |
set -e | |
HERE="$(cd "$(dirname "$0")" && pwd)" | |
revert=no | |
extra_options= | |
device= | |
lib= | |
use_su=0 | |
function usage { | |
echo "usage: $0 [--revert] [--device device-id] [--lib path] [--extra-options options]" | |
echo " --revert: Uninstall ASan from the device." | |
echo " --lib: Path to ASan runtime library." | |
echo " --extra-options: Extra ASAN_OPTIONS." | |
echo " --device: Install to the given device. Use 'adb devices' to find" | |
echo " device-id." | |
echo " --use-su: Use 'su -c' prefix for every adb command instead of using" | |
echo " 'adb root' once." | |
echo | |
exit 1 | |
} | |
function adb_push { | |
if [ $use_su -eq 0 ]; then | |
$ADB push "$1" "$2" | |
else | |
local FILENAME=$(basename $1) | |
$ADB push "$1" "/data/local/tmp/$FILENAME" | |
$ADB shell su -c "rm \\\"$2\\\"" >&/dev/null | |
$ADB shell su -c "cat \\\"/data/local/tmp/$FILENAME\\\" \> \\\"$2\\\"" | |
$ADB shell su -c "rm \\\"/data/local/tmp/$FILENAME\\\"" | |
fi | |
} | |
function adb_remount { | |
if [ $use_su -eq 0 ]; then | |
$ADB remount | |
else | |
local STORAGE=`$ADB shell mount | grep /system | cut -d ' ' -f1` | |
if [ "$STORAGE" != "" ]; then | |
echo Remounting $STORAGE at /system | |
$ADB shell su -c "mount -o remount,rw $STORAGE /system" | |
else | |
echo Failed to get storage device name for "/system" mount point | |
fi | |
fi | |
} | |
function adb_shell { | |
if [ $use_su -eq 0 ]; then | |
$ADB shell $@ | |
else | |
$ADB shell su -c "$*" | |
fi | |
} | |
function adb_root { | |
if [ $use_su -eq 0 ]; then | |
$ADB root | |
fi | |
} | |
function adb_wait_for_device { | |
$ADB wait-for-device | |
} | |
function adb_pull { | |
if [ $use_su -eq 0 ]; then | |
$ADB pull "$1" "$2" | |
else | |
local FILENAME=$(basename $1) | |
$ADB shell rm "/data/local/tmp/$FILENAME" >&/dev/null | |
$ADB shell su -c "cat \\\"$1\\\" \> \\\"/data/local/tmp/$FILENAME\\\"" | |
$ADB shell su -c "chown root.shell \\\"/data/local/tmp/$FILENAME\\\"" | |
$ADB shell su -c "chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" | |
$ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" | |
# $ADB shell su -c "[ -f \\\"$1\\\" ] && cat \\\"$1\\\" > \\\"/data/local/tmp/$FILENAME\\\" && chown root.shell \\\"/data/local/tmp/$FILENAME\\\" && chmod 755 \\\"/data/local/tmp/$FILENAME\\\"" && | |
# $ADB pull "/data/local/tmp/$FILENAME" "$2" >&/dev/null && $ADB shell "rm \"/data/local/tmp/$FILENAME\"" | |
fi | |
} | |
function get_device_arch { # OUT OUT64 | |
local _outvar=$1 | |
local _outvar64=$2 | |
local _ABI=$(adb_shell getprop ro.product.cpu.abi) | |
local _ARCH= | |
local _ARCH64= | |
if [[ $_ABI == x86* ]]; then | |
_ARCH=i686 | |
elif [[ $_ABI == armeabi* ]]; then | |
_ARCH=arm | |
elif [[ $_ABI == arm64-v8a* ]]; then | |
_ARCH=arm | |
_ARCH64=aarch64 | |
else | |
echo "Unrecognized device ABI: $_ABI" | |
exit 1 | |
fi | |
eval $_outvar=\$_ARCH | |
eval $_outvar64=\$_ARCH64 | |
} | |
while [[ $# > 0 ]]; do | |
case $1 in | |
--revert) | |
revert=yes | |
;; | |
--extra-options) | |
shift | |
if [[ $# == 0 ]]; then | |
echo "--extra-options requires an argument." | |
exit 1 | |
fi | |
extra_options="$1" | |
;; | |
--lib) | |
shift | |
if [[ $# == 0 ]]; then | |
echo "--lib requires an argument." | |
exit 1 | |
fi | |
lib="$1" | |
;; | |
--device) | |
shift | |
if [[ $# == 0 ]]; then | |
echo "--device requires an argument." | |
exit 1 | |
fi | |
device="$1" | |
;; | |
--use-su) | |
use_su=1 | |
;; | |
*) | |
usage | |
;; | |
esac | |
shift | |
done | |
ADB=${ADB:-adb} | |
if [[ x$device != x ]]; then | |
ADB="$ADB -s $device" | |
fi | |
if [ $use_su -eq 1 ]; then | |
# Test if 'su' is present on the device | |
SU_TEST_OUT=`$ADB shell su -c "echo foo" 2>&1 | sed 's/\r$//'` | |
SU_TEST_OUT=`echo ${SU_TEST_OUT//[[:space:]]}` | |
if [ $? != 0 -o "$SU_TEST_OUT" != "foo" ]; then | |
echo "ERROR: Cannot use 'su -c':" | |
echo "$ adb shell su -c \"echo foo\"" | |
echo $SU_TEST_OUT | |
echo "Check that 'su' binary is correctly installed on the device or omit" | |
echo " --use-su flag" | |
exit 1 | |
fi | |
fi | |
echo '>> Remounting /system rw' | |
adb_wait_for_device | |
adb_root | |
adb_wait_for_device | |
adb_remount | |
adb_wait_for_device | |
get_device_arch ARCH ARCH64 | |
echo "Target architecture: $ARCH" | |
ASAN_RT="libclang_rt.asan-$ARCH-android.so" | |
if [[ -n $ARCH64 ]]; then | |
echo "Target architecture: $ARCH64" | |
ASAN_RT64="libclang_rt.asan-$ARCH64-android.so" | |
fi | |
if [[ x$revert == xyes ]]; then | |
echo '>> Uninstalling ASan' | |
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then | |
echo '>> Pre-L device detected.' | |
adb_shell mv /system/bin/app_process.real /system/bin/app_process | |
adb_shell rm /system/bin/asanwrapper | |
elif ! adb_shell ls -l /system/bin/app_process64.real | grep -o 'No such file or directory' >&/dev/null; then | |
# 64-bit installation. | |
adb_shell mv /system/bin/app_process32.real /system/bin/app_process32 | |
adb_shell mv /system/bin/app_process64.real /system/bin/app_process64 | |
adb_shell rm /system/bin/asanwrapper | |
adb_shell rm /system/bin/asanwrapper64 | |
else | |
# 32-bit installation. | |
adb_shell rm /system/bin/app_process.wrap | |
adb_shell rm /system/bin/asanwrapper | |
adb_shell rm /system/bin/app_process | |
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process | |
fi | |
echo '>> Restarting shell' | |
adb_shell stop | |
adb_shell start | |
# Remove the library on the last step to give a chance to the 'su' binary to | |
# be executed without problem. | |
adb_shell rm /system/lib/$ASAN_RT | |
echo '>> Done' | |
exit 0 | |
fi | |
if [[ -d "$lib" ]]; then | |
ASAN_RT_PATH="$lib" | |
elif [[ -f "$lib" && "$lib" == *"$ASAN_RT" ]]; then | |
ASAN_RT_PATH=$(dirname "$lib") | |
elif [[ -f "$HERE/$ASAN_RT" ]]; then | |
ASAN_RT_PATH="$HERE" | |
elif [[ $(basename "$HERE") == "bin" ]]; then | |
# We could be in the toolchain's base directory. | |
# Consider ../lib, ../lib/asan, ../lib/linux, | |
# ../lib/clang/$VERSION/lib/linux, and ../lib64/clang/$VERSION/lib/linux. | |
P=$(ls "$HERE"/../lib/"$ASAN_RT" \ | |
"$HERE"/../lib/asan/"$ASAN_RT" \ | |
"$HERE"/../lib/linux/"$ASAN_RT" \ | |
"$HERE"/../lib/clang/*/lib/linux/"$ASAN_RT" \ | |
"$HERE"/../lib64/clang/*/lib/linux/"$ASAN_RT" 2>/dev/null | sort | tail -1) | |
if [[ -n "$P" ]]; then | |
ASAN_RT_PATH="$(dirname "$P")" | |
fi | |
fi | |
if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT" ]]; then | |
echo ">> ASan runtime library not found" | |
exit 1 | |
fi | |
if [[ -n "$ASAN_RT64" ]]; then | |
if [[ -z "$ASAN_RT_PATH" || ! -f "$ASAN_RT_PATH/$ASAN_RT64" ]]; then | |
echo ">> ASan runtime library not found" | |
exit 1 | |
fi | |
fi | |
TMPDIRBASE=$(mktemp -d -t template) | |
TMPDIROLD="$TMPDIRBASE/old" | |
TMPDIR="$TMPDIRBASE/new" | |
mkdir "$TMPDIROLD" | |
RELEASE=$(adb_shell getprop ro.build.version.release) | |
PRE_L=0 | |
if echo "$RELEASE" | grep '^4\.' >&/dev/null; then | |
PRE_L=1 | |
fi | |
if ! adb_shell ls -l /system/bin/app_process | grep -o '\->.*app_process' >&/dev/null; then | |
if adb_pull /system/bin/app_process.real /dev/null >&/dev/null; then | |
echo '>> Old-style ASan installation detected. Reverting.' | |
adb_shell mv /system/bin/app_process.real /system/bin/app_process | |
fi | |
echo '>> Pre-L device detected. Setting up app_process symlink.' | |
adb_shell mv /system/bin/app_process /system/bin/app_process32 | |
adb_shell ln -s /system/bin/app_process32 /system/bin/app_process | |
fi | |
echo '>> Copying files from the device' | |
if [[ -n "$ASAN_RT64" ]]; then | |
adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true | |
adb_pull /system/lib64/"$ASAN_RT64" "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process32 "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process32.real "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process64 "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process64.real "$TMPDIROLD" || true | |
adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true | |
adb_pull /system/bin/asanwrapper64 "$TMPDIROLD" || true | |
else | |
echo "Pulling from device" "$TMPDIROLD" | |
adb_pull /system/lib/"$ASAN_RT" "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process32 "$TMPDIROLD" || true | |
adb_pull /system/bin/app_process.wrap "$TMPDIROLD" || true | |
adb_pull /system/bin/asanwrapper "$TMPDIROLD" || true | |
echo "finish pulling" | |
fi | |
cp -r "$TMPDIROLD" "$TMPDIR" | |
if [[ -f "$TMPDIR/app_process.wrap" || -f "$TMPDIR/app_process64.real" ]]; then | |
echo ">> Previous installation detected" | |
else | |
echo ">> New installation" | |
fi | |
echo '>> Generating wrappers' | |
cp "$ASAN_RT_PATH/$ASAN_RT" "$TMPDIR/" | |
if [[ -n "$ASAN_RT64" ]]; then | |
cp "$ASAN_RT_PATH/$ASAN_RT64" "$TMPDIR/" | |
fi | |
# FIXME: alloc_dealloc_mismatch=0 prevents a failure in libdvm startup, | |
# which may or may not be a real bug (probably not). | |
ASAN_OPTIONS=start_deactivated=1,alloc_dealloc_mismatch=0,malloc_context_size=0 | |
function generate_zygote_wrapper { # from, to, asan_rt | |
local _from=$1 | |
local _to=$2 | |
local _asan_rt=$3 | |
cat <<EOF >"$TMPDIR/$_from" | |
#!/system/bin/sh-from-zygote | |
ASAN_OPTIONS=$ASAN_OPTIONS \\ | |
ASAN_ACTIVATION_OPTIONS=include_if_exists=/data/local/tmp/asan.options.%b \\ | |
LD_PRELOAD=\$LD_PRELOAD:$_asan_rt \\ | |
exec $_to \$@ | |
EOF | |
} | |
# On Android-L not allowing user segv handler breaks some applications. | |
if [[ PRE_L -eq 0 ]]; then | |
ASAN_OPTIONS="$ASAN_OPTIONS,allow_user_segv_handler=1" | |
fi | |
if [[ x$extra_options != x ]] ; then | |
ASAN_OPTIONS="$ASAN_OPTIONS,$extra_options" | |
fi | |
# Zygote wrapper. | |
if [[ -f "$TMPDIR/app_process64" ]]; then | |
# A 64-bit device. | |
if [[ ! -f "$TMPDIR/app_process64.real" ]]; then | |
# New installation. | |
mv "$TMPDIR/app_process32" "$TMPDIR/app_process32.real" | |
mv "$TMPDIR/app_process64" "$TMPDIR/app_process64.real" | |
fi | |
generate_zygote_wrapper "app_process32" "/system/bin/app_process32.real" "$ASAN_RT" | |
generate_zygote_wrapper "app_process64" "/system/bin/app_process64.real" "$ASAN_RT64" | |
else | |
# A 32-bit device. | |
generate_zygote_wrapper "app_process.wrap" "/system/bin/app_process32" "$ASAN_RT" | |
fi | |
# General command-line tool wrapper (use for anything that's not started as | |
# zygote). | |
cat <<EOF >"$TMPDIR/asanwrapper" | |
#!/system/bin/sh | |
LD_PRELOAD=$ASAN_RT \\ | |
exec \$@ | |
EOF | |
if [[ -n "$ASAN_RT64" ]]; then | |
cat <<EOF >"$TMPDIR/asanwrapper64" | |
#!/system/bin/sh | |
LD_PRELOAD=$ASAN_RT64 \\ | |
exec \$@ | |
EOF | |
fi | |
function install { # from, to, chmod, chcon | |
local _from=$1 | |
local _to=$2 | |
local _mode=$3 | |
local _context=$4 | |
local _basename="$(basename "$_from")" | |
echo "Installing $_to/$_basename $_mode $_context" | |
adb_push "$_from" "$_to/$_basename" | |
adb_shell chown root.shell "$_to/$_basename" | |
if [[ -n "$_mode" ]]; then | |
adb_shell chmod "$_mode" "$_to/$_basename" | |
fi | |
if [[ -n "$_context" ]]; then | |
adb_shell chcon "$_context" "$_to/$_basename" | |
fi | |
} | |
if ! ( cd "$TMPDIRBASE" && diff -qr old/ new/ ) ; then | |
# Make SELinux happy by keeping app_process wrapper and the shell | |
# it runs on in zygote domain. | |
ENFORCING=0 | |
if adb_shell getenforce | grep Enforcing >/dev/null; then | |
# Sometimes shell is not allowed to change file contexts. | |
# Temporarily switch to permissive. | |
ENFORCING=1 | |
adb_shell setenforce 0 | |
fi | |
if [[ PRE_L -eq 1 ]]; then | |
CTX=u:object_r:system_file:s0 | |
else | |
CTX=u:object_r:zygote_exec:s0 | |
fi | |
echo '>> Pushing files to the device' | |
if [[ -n "$ASAN_RT64" ]]; then | |
install "$TMPDIR/$ASAN_RT" /system/lib 644 | |
install "$TMPDIR/$ASAN_RT64" /system/lib64 644 | |
install "$TMPDIR/app_process32" /system/bin 755 $CTX | |
install "$TMPDIR/app_process32.real" /system/bin 755 $CTX | |
install "$TMPDIR/app_process64" /system/bin 755 $CTX | |
install "$TMPDIR/app_process64.real" /system/bin 755 $CTX | |
install "$TMPDIR/asanwrapper" /system/bin 755 | |
install "$TMPDIR/asanwrapper64" /system/bin 755 | |
else | |
install "$TMPDIR/$ASAN_RT" /system/lib 644 | |
install "$TMPDIR/app_process32" /system/bin 755 $CTX | |
install "$TMPDIR/app_process.wrap" /system/bin 755 $CTX | |
install "$TMPDIR/asanwrapper" /system/bin 755 $CTX | |
adb_shell rm /system/bin/app_process | |
adb_shell ln -s /system/bin/app_process.wrap /system/bin/app_process | |
fi | |
adb_shell cp /system/bin/sh /system/bin/sh-from-zygote | |
adb_shell chcon $CTX /system/bin/sh-from-zygote | |
if [ $ENFORCING == 1 ]; then | |
adb_shell setenforce 1 | |
fi | |
echo '>> Restarting shell (asynchronous)' | |
adb_shell stop | |
adb_shell start | |
echo '>> Please wait until the device restarts' | |
else | |
echo '>> Device is up to date' | |
fi | |
rm -r "$TMPDIRBASE" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Fixed "--use-su" when run on Mac. From NDK r13b.