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