toolkit/crashreporter/google-breakpad/android/run-checks.sh

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rwxr-xr-x

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 #!/bin/sh
     2 # Copyright (c) 2012 Google Inc.
     3 # All rights reserved.
     4 #
     5 # Redistribution and use in source and binary forms, with or without
     6 # modification, are permitted provided that the following conditions are
     7 # met:
     8 #
     9 #     * Redistributions of source code must retain the above copyright
    10 # notice, this list of conditions and the following disclaimer.
    11 #     * Redistributions in binary form must reproduce the above
    12 # copyright notice, this list of conditions and the following disclaimer
    13 # in the documentation and/or other materials provided with the
    14 # distribution.
    15 #     * Neither the name of Google Inc. nor the names of its
    16 # contributors may be used to endorse or promote products derived from
    17 # this software without specific prior written permission.
    18 #
    19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    31 # Sanitize the environment
    32 export LANG=C
    33 export LC_ALL=C
    35 if [ "$BASH_VERSION" ]; then
    36   set -o posix
    37 fi
    39 PROGDIR=$(dirname "$0")
    40 PROGDIR=$(cd "$PROGDIR" && pwd)
    41 PROGNAME=$(basename "$0")
    43 . $PROGDIR/common-functions.sh
    45 DEFAULT_ABI="armeabi"
    46 VALID_ABIS="armeabi armeabi-v7a x86 mips"
    48 ABI=
    49 ADB=
    50 ALL_TESTS=
    51 ENABLE_M32=
    52 HELP=
    53 HELP_ALL=
    54 NDK_DIR=
    55 NO_CLEANUP=
    56 NO_DEVICE=
    57 NUM_JOBS=$(get_core_count)
    58 TMPDIR=
    60 for opt do
    61   # The following extracts the value if the option is like --name=<value>.
    62   optarg=$(expr -- $opt : '^--[^=]*=\(.*\)$')
    63   case $opt in
    64     --abi=*) ABI=$optarg;;
    65     --adb=*) ADB=$optarg;;
    66     --all-tests) ALL_TESTS=true;;
    67     --enable-m32) ENABLE_M32=true;;
    68     --help|-h|-?) HELP=TRUE;;
    69     --help-all) HELP_ALL=true;;
    70     --jobs=*) NUM_JOBS=$optarg;;
    71     --ndk-dir=*) NDK_DIR=$optarg;;
    72     --tmp-dir=*) TMPDIR=$optarg;;
    73     --no-cleanup) NO_CLEANUP=true;;
    74     --no-device) NO_DEVICE=true;;
    75     --quiet) decrease_verbosity;;
    76     --verbose) increase_verbosity;;
    77     -*) panic "Invalid option '$opt', see --help for details.";;
    78     *) panic "This script doesn't take any parameters. See --help for details."
    79        ;;
    80   esac
    81 done
    83 if [ "$HELP" -o "$HELP_ALL" ]; then
    84   echo "\
    85   Usage: $PROGNAME [options]
    87   This script is used to check that your Google Breakpad source tree can
    88   be properly built for Android, and that the client library and host tools
    89   work properly together.
    90 "
    91   if [ "$HELP_ALL" ]; then
    92     echo "\
    93   In more details, this script will:
    95   - Rebuild the host version of Google Breakpad in a temporary
    96     directory (with the Auto-tools based build system).
    98   - Rebuild the Android client library with the Google Breakpad build
    99     system (using autotools/configure). This requires that you define
   100     ANDROID_NDK_ROOT in your environment to point to a valid Android NDK
   101     installation directory, or use the --ndk-dir=<path> option.
   103   - Rebuild the Android client library and a test crashing program with the
   104     Android NDK build system (ndk-build).
   106   - Require an Android device connected to your machine, and the 'adb'
   107     tool in your path. They are used to:
   109       - Install and  run a test crashing program.
   110       - Extract the corresponding minidump from the device.
   111       - Dump the symbols from the test program on the host with 'dump_syms'
   112       - Generate a stack trace with 'minidump_stackwalk'
   113       - Check the stack trace content for valid source file locations.
   115     You can however skip this requirement and only test the builds by using
   116     the --no-device flag.
   118     By default, all generated files will be created in a temporary directory
   119     that is removed when the script completion. If you want to inspect the
   120     files, use the --no-cleanup option.
   122     Finally, use --verbose to increase the verbosity level, this will help
   123     you see which exact commands are being issues and their result. Use the
   124     flag twice for even more output. Use --quiet to decrease verbosity
   125     instead and run the script silently.
   127     If you have a device connected, the script will probe it to determine
   128     its primary CPU ABI, and build the test program for it. You can however
   129     use the --abi=<name> option to override this (this can be useful to check
   130     the secondary ABI, e.g. using --abi=armeabi to check that such a program
   131     works correctly on an ARMv7-A device).
   133     If you don't have a device connected, the test program will be built (but
   134     not run) with the default '$DEFAULT_ABI' ABI. Again, you can use
   135     --abi=<name> to override this. Valid ABI names are:
   137         $VALID_ABIS
   139     The script will only run the client library unit test on the device
   140     by default. You can use --all-tests to also build and run the unit
   141     tests for the Breakpad tools and processor, but be warned that this
   142     adds several minutes of testing time. --all-tests will also run the
   143     host unit tests suite.
   144 "
   146   fi  # HELP_ALL
   148   echo "\
   149   Valid options:
   151       --help|-h|-?     Display this message.
   152       --help-all       Display extended help.
   153       --enable-m32     Build 32-bit version of host tools.
   154       --abi=<name>     Specify target CPU ABI [auto-detected].
   155       --jobs=<count>   Run <count> build tasks in parallel [$NUM_JOBS].
   156       --ndk-dir=<path> Specify NDK installation directory.
   157       --tmp-dir=<path> Specify temporary directory (will be wiped-out).
   158       --adb=<path>     Specify adb program path.
   159       --no-cleanup     Don't remove temporary directory after completion.
   160       --no-device      Do not try to detect devices, nor run crash test.
   161       --all-tests      Run all unit tests (i.e. tools and processor ones too).
   162       --verbose        Increase verbosity.
   163       --quiet          Decrease verbosity."
   165   exit 0
   166 fi
   168 TESTAPP_DIR=$PROGDIR/sample_app
   170 # Select NDK install directory.
   171 if [ -z "$NDK_DIR" ]; then
   172   if [ -z "$ANDROID_NDK_ROOT" ]; then
   173     panic "Please define ANDROID_NDK_ROOT in your environment, or use \
   174 --ndk-dir=<path>."
   175   fi
   176   NDK_DIR="$ANDROID_NDK_ROOT"
   177   log "Found NDK directory: $NDK_DIR"
   178 else
   179   log "Using NDK directory: $NDK_DIR"
   180 fi
   181 # Small sanity check.
   182 NDK_BUILD="$NDK_DIR/ndk-build"
   183 if [ ! -f "$NDK_BUILD" ]; then
   184   panic "Your NDK directory is not valid (missing ndk-build): $NDK_DIR"
   185 fi
   187 # Ensure the temporary directory is deleted on exit, except if the --no-cleanup
   188 # option is used.
   190 clean_tmpdir () {
   191   if [ "$TMPDIR" ]; then
   192     if [ -z "$NO_CLEANUP" ]; then
   193       log "Cleaning up: $TMPDIR"
   194       rm -rf "$TMPDIR"
   195     else
   196       dump "Temporary directory contents preserved: $TMPDIR"
   197     fi
   198   fi
   199   exit "$@"
   200 }
   202 atexit clean_tmpdir
   204 # If --tmp-dir=<path> is not used, create a temporary directory.
   205 # Otherwise, start by cleaning up the user-provided path.
   206 if [ -z "$TMPDIR" ]; then
   207   TMPDIR=$(mktemp -d /tmp/$PROGNAME.XXXXXXXX)
   208   fail_panic "Can't create temporary directory!"
   209   log "Using temporary directory: $TMPDIR"
   210 else
   211   if [ ! -d "$TMPDIR" ]; then
   212     mkdir -p "$TMPDIR"
   213     fail_panic "Can't create temporary directory: $TMPDIR"
   214   else
   215     log "Cleaning up temporary directory: $TMPDIR"
   216     rm -rf "$TMPDIR"/*
   217     fail_panic "Cannot cleanup temporary directory!"
   218   fi
   219 fi
   221 if [ -z "$NO_DEVICE" ]; then
   222   if ! adb_check_device $ADB; then
   223     echo "$(adb_get_error)"
   224     echo "Use --no-device to build the code without running any tests."
   225     exit 1
   226   fi
   227 fi
   229 BUILD_LOG="$TMPDIR/build.log"
   230 RUN_LOG="$TMPDIR/run.log"
   231 CRASH_LOG="$TMPDIR/crash.log"
   233 set_run_log "$RUN_LOG"
   235 TMPHOST="$TMPDIR/host-local"
   237 cd "$TMPDIR"
   239 # Build host version of the tools
   240 dump "Building host binaries."
   241 CONFIGURE_FLAGS=
   242 if [ "$ENABLE_M32" ]; then
   243   CONFIGURE_FLAGS="$CONFIGURE_FLAGS --enable-m32"
   244 fi
   245 (
   246   run mkdir "$TMPDIR/build-host" &&
   247   run cd "$TMPDIR/build-host" &&
   248   run2 "$PROGDIR/../configure" --prefix="$TMPHOST" $CONFIGURE_FLAGS &&
   249   run2 make -j$NUM_JOBS install
   250 )
   251 fail_panic "Can't build host binaries!"
   253 if [ "$ALL_TESTS" ]; then
   254   dump "Running host unit tests."
   255   (
   256     run cd "$TMPDIR/build-host" &&
   257     run2 make -j$NUM_JOBS check
   258   )
   259   fail_panic "Host unit tests failed!!"
   260 fi
   262 TMPBIN=$TMPHOST/bin
   264 # Generate a stand-alone NDK toolchain
   266 # Extract CPU ABI and architecture from device, if any.
   267 if adb_check_device; then
   268   DEVICE_ABI=$(adb_shell getprop ro.product.cpu.abi)
   269   DEVICE_ABI2=$(adb_shell getprop ro.product.cpu.abi2)
   270   if [ -z "$DEVICE_ABI" ]; then
   271     panic "Can't extract ABI from connected device!"
   272   fi
   273   if [ "$DEVICE_ABI2" ]; then
   274     dump "Found device ABIs: $DEVICE_ABI $DEVICE_ABI2"
   275   else
   276     dump "Found device ABI: $DEVICE_ABI"
   277     DEVICE_ABI2=$DEVICE_ABI
   278   fi
   280   # If --abi=<name> is used, check that the device supports it.
   281   if [ "$ABI" -a "$DEVICE_ABI" != "$ABI" -a "$DEVICE_ABI2" != "$ABI" ]; then
   282     dump  "ERROR: Device ABI(s) do not match --abi command-line value ($ABI)!"
   283     panic "Please use --no-device to skip device tests."
   284   fi
   286   if [ -z "$ABI" ]; then
   287     ABI=$DEVICE_ABI
   288     dump "Using CPU ABI: $ABI (device)"
   289   else
   290     dump "Using CPU ABI: $ABI (command-line)"
   291   fi
   292 else
   293   if [ -z "$ABI" ]; then
   294     # No device connected, choose default ABI
   295     ABI=$DEFAULT_ABI
   296     dump "Using CPU ABI: $ABI (default)"
   297   else
   298     dump "Using CPU ABI: $ABI (command-line)"
   299   fi
   300 fi
   302 # Check the ABI value
   303 VALID=
   304 for VALID_ABI in $VALID_ABIS; do
   305   if [ "$ABI" = "$VALID_ABI" ]; then
   306     VALID=true
   307     break
   308   fi
   309 done
   311 if [ -z "$VALID" ]; then
   312   panic "Unknown CPU ABI '$ABI'. Valid values are: $VALID_ABIS"
   313 fi
   315 # Extract architecture name from ABI
   316 case $ABI in
   317   armeabi*) ARCH=arm;;
   318   *) ARCH=$ABI;;
   319 esac
   321 # Extract GNU configuration name
   322 case $ARCH in
   323   arm)
   324     GNU_CONFIG=arm-linux-androideabi
   325     ;;
   326   x86)
   327     GNU_CONFIG=i686-linux-android
   328     ;;
   329   *)
   330     GNU_CONFIG="$ARCH-linux-android"
   331     ;;
   332 esac
   334 # Generate standalone NDK toolchain installation
   335 NDK_STANDALONE="$TMPDIR/ndk-$ARCH-toolchain"
   336 echo "Generating NDK standalone toolchain installation"
   337 mkdir -p "$NDK_STANDALONE"
   338 # NOTE: The --platform=android-9 is required to provide <regex.h> for GTest.
   339 run "$NDK_DIR/build/tools/make-standalone-toolchain.sh" \
   340       --arch="$ARCH" \
   341       --platform=android-9 \
   342       --install-dir="$NDK_STANDALONE"
   343 fail_panic "Can't generate standalone NDK toolchain installation!"
   345 # Rebuild the client library, processor and tools with the auto-tools based
   346 # build system. Even though it's not going to be used, this checks that this
   347 # still works correctly.
   348 echo "Building full Android binaries with configure/make"
   349 TMPTARGET="$TMPDIR/target-local"
   350 (
   351   PATH="$NDK_STANDALONE/bin:$PATH"
   352   run mkdir "$TMPTARGET" &&
   353   run mkdir "$TMPDIR"/build-target &&
   354   run cd "$TMPDIR"/build-target &&
   355   run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
   356                                --host="$GNU_CONFIG" &&
   357   run2 make -j$NUM_JOBS install
   358 )
   359 fail_panic "Could not rebuild Android binaries!"
   361 # Build and/or run unit test suite.
   362 # If --no-device is used, only rebuild it, otherwise, run in on the
   363 # connected device.
   364 if [ "$NO_DEVICE" ]; then
   365   ACTION="Building"
   366   # This is a trick to force the Makefile to ignore running the scripts.
   367   TESTS_ENVIRONMENT="TESTS_ENVIRONMENT=true"
   368 else
   369   ACTION="Running"
   370   TESTS_ENVIRONMENT=
   371 fi
   373 (
   374   PATH="$NDK_STANDALONE/bin:$PATH"
   375   run cd "$TMPDIR"/build-target &&
   376   # Reconfigure to only run the client unit test suite.
   377   # This one should _never_ fail.
   378   dump "$ACTION Android client library unit tests."
   379   run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
   380                                --host="$GNU_CONFIG" \
   381                                --disable-tools \
   382                                --disable-processor &&
   383   run make -j$NUM_JOBS check $TESTS_ENVIRONMENT || exit $?
   385   if [ "$ALL_TESTS" ]; then
   386     dump "$ACTION Tools and processor unit tests."
   387     # Reconfigure to run the processor and tools tests.
   388     # Most of these fail for now, so do not worry about it.
   389     run2 "$PROGDIR"/../configure --prefix="$TMPTARGET" \
   390                                  --host="$GNU_CONFIG" &&
   391     run make -j$NUM_JOBS check $TESTS_ENVIRONMENT
   392     if [ $? != 0 ]; then
   393       dump "Tools and processor unit tests failed as expected. \
   394 Use --verbose for results."
   395     fi                           
   396   fi
   397 )
   398 fail_panic "Client library unit test suite failed!"
   400 # Copy sources to temporary directory
   401 PROJECT_DIR=$TMPDIR/project
   402 dump "Copying test program sources to: $PROJECT_DIR"
   403 run cp -r "$TESTAPP_DIR" "$PROJECT_DIR" &&
   404 run rm -rf "$PROJECT_DIR/obj" &&
   405 run rm -rf "$PROJECT_DIR/libs"
   406 fail_panic "Could not copy test program sources to: $PROJECT_DIR"
   408 # Build the test program with ndk-build.
   409 dump "Building test program with ndk-build"
   410 export NDK_MODULE_PATH="$PROGDIR"
   411 NDK_BUILD_FLAGS="-j$NUM_JOBS"
   412 if verbosity_is_higher_than 1; then
   413   NDK_BUILD_FLAGS="$NDK_BUILD_FLAGS NDK_LOG=1 V=1"
   414 fi
   415 run "$NDK_DIR/ndk-build" -C "$PROJECT_DIR" $NDK_BUILD_FLAGS APP_ABI=$ABI
   416 fail_panic "Can't build test program!"
   418 # Unless --no-device was used, stop right here if ADB isn't in the path,
   419 # or there is no connected device.
   420 if [ "$NO_DEVICE" ]; then
   421   dump "Done. Please connect a device to run all tests!"
   422   clean_exit 0
   423 fi
   425 # Push the program to the device.
   426 TESTAPP=test_google_breakpad
   427 TESTAPP_FILE="$PROJECT_DIR/libs/$ABI/test_google_breakpad"
   428 if [ ! -f "$TESTAPP_FILE" ]; then
   429   panic "Device requires '$ABI' binaries. None found!"
   430 fi
   432 # Run the program there
   433 dump "Installing test program on device"
   434 DEVICE_TMP=/data/local/tmp
   435 adb_push "$TESTAPP_FILE" "$DEVICE_TMP/"
   436 fail_panic "Cannot push test program to device!"
   438 dump "Running test program on device"
   439 adb_shell cd "$DEVICE_TMP" "&&" ./$TESTAPP > "$CRASH_LOG" 2>/dev/null
   440 if [ $? = 0 ]; then
   441   panic "Test program did *not* crash as expected!"
   442 fi
   443 if verbosity_is_higher_than 0; then
   444   echo -n "Crash log: "
   445   cat "$CRASH_LOG"
   446 fi
   448 # Extract minidump from device
   449 MINIDUMP_NAME=$(awk '$1 == "Dump" && $2 == "path:" { print $3; }' "$CRASH_LOG")
   450 MINIDUMP_NAME=$(basename "$MINIDUMP_NAME")
   451 if [ -z "$MINIDUMP_NAME" ]; then
   452   panic "Test program didn't write minidump properly!"
   453 fi
   455 dump "Extracting minidump: $MINIDUMP_NAME"
   456 adb_pull "$DEVICE_TMP/$MINIDUMP_NAME" .
   457 fail_panic "Can't extract minidump!"
   459 dump "Parsing test program symbols"
   460 if verbosity_is_higher_than 1; then
   461   log "COMMAND: $TMPBIN/dump_syms \
   462                 $PROJECT_DIR/obj/local/$ABI/$TESTAPP >$TESTAPP.sym"
   463 fi
   464 "$TMPBIN/dump_syms" "$PROJECT_DIR/obj/local/$ABI/$TESTAPP" > $TESTAPP.sym
   465 fail_panic "dump_syms doesn't work!"
   467 VERSION=$(awk '$1 == "MODULE" { print $4; }' $TESTAPP.sym)
   468 dump "Found module version: $VERSION"
   469 if [ -z "$VERSION" ]; then
   470   echo "ERROR: Can't find proper module version from symbol dump!"
   471   head -n5 $TESTAPP.sym
   472   clean_exit 1
   473 fi
   475 run mkdir -p "$TMPDIR/symbols/$TESTAPP/$VERSION"
   476 run mv $TESTAPP.sym "$TMPDIR/symbols/$TESTAPP/$VERSION/"
   478 dump "Generating stack trace"
   479 # Don't use 'run' to be able to send stdout and stderr to two different files.
   480 log "COMMAND: $TMPBIN/minidump_stackwalk $MINIDUMP_NAME symbols"
   481 "$TMPBIN/minidump_stackwalk" $MINIDUMP_NAME \
   482                              "$TMPDIR/symbols" \
   483                              > "$BUILD_LOG" 2>>"$RUN_LOG"
   484 fail_panic "minidump_stackwalk doesn't work!"
   486 dump "Checking stack trace content"
   488 if verbosity_is_higher_than 1; then
   489   cat "$BUILD_LOG"
   490 fi
   492 # The generated stack trace should look like the following:
   493 #
   494 # Thread 0 (crashed)
   495 #  0  test_google_breakpad!crash [test_breakpad.cpp : 17 + 0x4]
   496 #      r4 = 0x00015530    r5 = 0xbea2cbe4    r6 = 0xffffff38    r7 = 0xbea2cb5c
   497 #      r8 = 0x00000000    r9 = 0x00000000   r10 = 0x00000000    fp = 0x00000000
   498 #      sp = 0xbea2cb50    lr = 0x00009025    pc = 0x00008f84
   499 #     Found by: given as instruction pointer in context
   500 #  1  test_google_breakpad!main [test_breakpad.cpp : 25 + 0x3]
   501 #      r4 = 0x00015530    r5 = 0xbea2cbe4    r6 = 0xffffff38    r7 = 0xbea2cb5c
   502 #      r8 = 0x00000000    r9 = 0x00000000   r10 = 0x00000000    fp = 0x00000000
   503 #      sp = 0xbea2cb50    pc = 0x00009025
   504 #     Found by: call frame info
   505 #  2  libc.so + 0x164e5
   506 #      r4 = 0x00008f64    r5 = 0xbea2cc34    r6 = 0x00000001    r7 = 0xbea2cc3c
   507 #      r8 = 0x00000000    r9 = 0x00000000   r10 = 0x00000000    fp = 0x00000000
   508 #      sp = 0xbea2cc18    pc = 0x400c34e7
   509 #     Found by: call frame info
   510 # ...
   511 #
   512 # The most important part for us is ensuring that the source location could
   513 # be extracted, so look at the 'test_breakpad.cpp' references here.
   514 #
   515 # First, extract all the lines with test_google_breakpad! in them, and
   516 # dump the corresponding crash location.
   517 #
   518 # Note that if the source location can't be extracted, the second field
   519 # will only be 'test_google_breakpad' without the exclamation mark.
   520 #
   521 LOCATIONS=$(awk '$2 ~ "^test_google_breakpad!.*" { print $3; }' "$BUILD_LOG")
   523 if [ -z "$LOCATIONS" ]; then
   524   if verbosity_is_lower_than 1; then
   525     cat "$BUILD_LOG"
   526   fi
   527   panic "No source location found in stack trace!"
   528 fi
   530 # Now check that they all match "[<source file>"
   531 BAD_LOCATIONS=
   532 for LOCATION in $LOCATIONS; do
   533   case $LOCATION in
   534     # Escape the opening bracket, or some shells like Dash will not
   535     # match them properly.
   536     \[*.cpp|\[*.cc|\[*.h) # These are valid source locations in our executable
   537       ;;
   538     *) # Everything else is not!
   539       BAD_LOCATIONS="$BAD_LOCATIONS $LOCATION"
   540       ;;
   541   esac
   542 done
   544 if [ "$BAD_LOCATIONS" ]; then
   545   dump "ERROR: Generated stack trace doesn't contain valid source locations:"
   546   cat "$BUILD_LOG"
   547   echo "Bad locations are: $BAD_LOCATIONS"
   548   exit 1
   549 fi
   551 echo "All clear! Congratulations."

mercurial