1 #!/bin/bash 2 # 3 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 4 # Use of this source code is governed by a BSD-style license that can be 5 # found in the LICENSE file. 6 # 7 8 # A generic script used to attach to a running Chromium process and 9 # debug it. Most users should not use this directly, but one of the 10 # wrapper scripts like adb_gdb_content_shell 11 # 12 # Use --help to print full usage instructions. 13 # 14 15 PROGNAME=$(basename "$0") 16 PROGDIR=$(dirname "$0") 17 18 # Location of Chromium-top-level sources. 19 CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null) 20 21 # Location of Chromium out/ directory. 22 if [ -z "$CHROMIUM_OUT_DIR" ]; then 23 CHROMIUM_OUT_DIR=out 24 fi 25 26 TMPDIR= 27 GDBSERVER_PIDFILE= 28 TARGET_GDBSERVER= 29 30 clean_exit () { 31 if [ "$TMPDIR" ]; then 32 GDBSERVER_PID=$(cat $GDBSERVER_PIDFILE 2>/dev/null) 33 if [ "$GDBSERVER_PID" ]; then 34 log "Killing background gdbserver process: $GDBSERVER_PID" 35 kill -9 $GDBSERVER_PID >/dev/null 2>&1 36 fi 37 if [ "$TARGET_GDBSERVER" ]; then 38 log "Removing target gdbserver binary: $TARGET_GDBSERVER." 39 "$ADB" shell rm "$TARGET_GDBSERVER" >/dev/null 2>&1 40 fi 41 log "Cleaning up: $TMPDIR" 42 rm -rf "$TMPDIR" 43 fi 44 trap "" EXIT 45 exit $1 46 } 47 48 # Ensure clean exit on Ctrl-C or normal exit. 49 trap "clean_exit 1" INT HUP QUIT TERM 50 trap "clean_exit \$?" EXIT 51 52 panic () { 53 echo "ERROR: $@" >&2 54 exit 1 55 } 56 57 fail_panic () { 58 if [ $? != 0 ]; then panic "$@"; fi 59 } 60 61 log () { 62 if [ "$VERBOSE" -gt 0 ]; then 63 echo "$@" 64 fi 65 } 66 67 DEFAULT_PULL_LIBS_DIR=/tmp/$USER-adb-gdb-libs 68 69 # NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX 70 # environment variables. This is only for cosmetic reasons, i.e. to 71 # display proper 72 73 # Allow wrapper scripts to set the default activity through 74 # the ADB_GDB_ACTIVITY variable. Users are still able to change the 75 # final activity name through --activity=<name> option. 76 # 77 # This is only for cosmetic reasons, i.e. to display the proper default 78 # in the --help output. 79 # 80 DEFAULT_ACTIVITY=${ADB_GDB_ACTIVITY:-".Main"} 81 82 # Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME 83 PROGNAME=${ADB_GDB_PROGNAME:-$(basename "$0")} 84 85 ACTIVITY=$DEFAULT_ACTIVITY 86 ADB= 87 ANNOTATE= 88 # Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it. 89 BUILDTYPE= 90 FORCE= 91 GDBEXEPOSTFIX=gdb 92 GDBINIT= 93 GDBSERVER= 94 HELP= 95 NDK_DIR= 96 NO_PULL_LIBS= 97 PACKAGE_NAME= 98 PID= 99 PROGRAM_NAME="activity" 100 PULL_LIBS= 101 PULL_LIBS_DIR= 102 SANDBOXED= 103 SANDBOXED_INDEX= 104 START= 105 SU_PREFIX= 106 SYMBOL_DIR= 107 TARGET_ARCH= 108 TOOLCHAIN= 109 VERBOSE=0 110 111 for opt; do 112 optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') 113 case $opt in 114 --adb=*) 115 ADB=$optarg 116 ;; 117 --activity=*) 118 ACTIVITY=$optarg 119 ;; 120 --annotate=3) 121 ANNOTATE=$optarg 122 ;; 123 --force) 124 FORCE=true 125 ;; 126 --gdbserver=*) 127 GDBSERVER=$optarg 128 ;; 129 --gdb=*) 130 GDB=$optarg 131 ;; 132 --help|-h|-?) 133 HELP=true 134 ;; 135 --ndk-dir=*) 136 NDK_DIR=$optarg 137 ;; 138 --no-pull-libs) 139 NO_PULL_LIBS=true 140 ;; 141 --package-name=*) 142 PACKAGE_NAME=$optarg 143 ;; 144 --pid=*) 145 PID=$optarg 146 ;; 147 --program-name=*) 148 PROGRAM_NAME=$optarg 149 ;; 150 --pull-libs) 151 PULL_LIBS=true 152 ;; 153 --pull-libs-dir=*) 154 PULL_LIBS_DIR=$optarg 155 ;; 156 --sandboxed) 157 SANDBOXED=true 158 ;; 159 --sandboxed=*) 160 SANDBOXED=true 161 SANDBOXED_INDEX=$optarg 162 ;; 163 --script=*) 164 GDBINIT=$optarg 165 ;; 166 --start) 167 START=true 168 ;; 169 --su-prefix=*) 170 SU_PREFIX=$optarg 171 ;; 172 --symbol-dir=*) 173 SYMBOL_DIR=$optarg 174 ;; 175 --out-dir=*) 176 CHROMIUM_OUT_DIR=$optarg 177 ;; 178 --target-arch=*) 179 TARGET_ARCH=$optarg 180 ;; 181 --toolchain=*) 182 TOOLCHAIN=$optarg 183 ;; 184 --ui) 185 GDBEXEPOSTFIX=gdbtui 186 ;; 187 --verbose) 188 VERBOSE=$(( $VERBOSE + 1 )) 189 ;; 190 --debug) 191 BUILDTYPE=Debug 192 ;; 193 --release) 194 BUILDTYPE=Release 195 ;; 196 -*) 197 panic "Unknown option $OPT, see --help." >&2 198 ;; 199 *) 200 if [ "$PACKAGE_NAME" ]; then 201 panic "You can only provide a single package name as argument!\ 202 See --help." 203 fi 204 PACKAGE_NAME=$opt 205 ;; 206 esac 207 done 208 209 print_help_options () { 210 cat <<EOF 211 EOF 212 } 213 214 if [ "$HELP" ]; then 215 if [ "$ADB_GDB_PROGNAME" ]; then 216 # Assume wrapper scripts all provide a default package name. 217 cat <<EOF 218 Usage: $PROGNAME [options] 219 220 Attach gdb to a running Android $PROGRAM_NAME process. 221 EOF 222 else 223 # Assume this is a direct call to adb_gdb 224 cat <<EOF 225 Usage: $PROGNAME [options] [<package-name>] 226 227 Attach gdb to a running Android $PROGRAM_NAME process. 228 229 If provided, <package-name> must be the name of the Android application's 230 package name to be debugged. You can also use --package-name=<name> to 231 specify it. 232 EOF 233 fi 234 235 cat <<EOF 236 237 This script is used to debug a running $PROGRAM_NAME process. 238 This can be a regular Android application process, or a sandboxed 239 service, if you use the --sandboxed or --sandboxed=<num> option. 240 241 This script needs several things to work properly. It will try to pick 242 them up automatically for you though: 243 244 - target gdbserver binary 245 - host gdb client (e.g. arm-linux-androideabi-gdb) 246 - directory with symbolic version of $PROGRAM_NAME's shared libraries. 247 248 You can also use --ndk-dir=<path> to specify an alternative NDK installation 249 directory. 250 251 The script tries to find the most recent version of the debug version of 252 shared libraries under one of the following directories: 253 254 \$CHROMIUM_SRC/<out>/Release/lib/ (used by Ninja builds) 255 \$CHROMIUM_SRC/<out>/Debug/lib/ (used by Ninja builds) 256 \$CHROMIUM_SRC/<out>/Release/lib.target/ (used by Make builds) 257 \$CHROMIUM_SRC/<out>/Debug/lib.target/ (used by Make builds) 258 259 Where <out> is 'out' by default, unless the --out=<name> option is used or 260 the CHROMIUM_OUT_DIR environment variable is defined. 261 262 You can restrict this search by using --release or --debug to specify the 263 build type, or simply use --symbol-dir=<path> to specify the file manually. 264 265 The script tries to extract the target architecture from your GYP_DEFINES, 266 but if this fails, will default to 'arm'. Use --target-arch=<name> to force 267 its value. 268 269 Otherwise, the script will complain, but you can use the --gdbserver, 270 --gdb and --symbol-lib options to specify everything manually. 271 272 An alternative to --gdb=<file> is to use --toollchain=<path> to specify 273 the path to the host target-specific cross-toolchain. 274 275 You will also need the 'adb' tool in your path. Otherwise, use the --adb 276 option. The script will complain if there is more than one device connected 277 and ANDROID_SERIAL is not defined. 278 279 The first time you use it on a device, the script will pull many system 280 libraries required by the process into a temporary directory. This 281 is done to strongly improve the debugging experience, like allowing 282 readable thread stacks and more. The libraries are copied to the following 283 directory by default: 284 285 $DEFAULT_PULL_LIBS_DIR/ 286 287 But you can use the --pull-libs-dir=<path> option to specify an 288 alternative. The script can detect when you change the connected device, 289 and will re-pull the libraries only in this case. You can however force it 290 with the --pull-libs option. 291 292 Any local .gdbinit script will be ignored, but it is possible to pass a 293 gdb command script with the --script=<file> option. Note that its commands 294 will be passed to gdb after the remote connection and library symbol 295 loading have completed. 296 297 Valid options: 298 --help|-h|-? Print this message. 299 --verbose Increase verbosity. 300 301 --sandboxed Debug first sandboxed process we find. 302 --sandboxed=<num> Debug specific sandboxed process. 303 --symbol-dir=<path> Specify directory with symbol shared libraries. 304 --out-dir=<path> Specify the out directory. 305 --package-name=<name> Specify package name (alternative to 1st argument). 306 --program-name=<name> Specify program name (cosmetic only). 307 --pid=<pid> Specify application process pid. 308 --force Kill any previous debugging session, if any. 309 --start Start package's activity on device. 310 --ui Use gdbtui instead of gdb 311 --activity=<name> Activity name for --start [$DEFAULT_ACTIVITY]. 312 --annotate=<num> Enable gdb annotation. 313 --script=<file> Specify extra GDB init script. 314 315 --gdbserver=<file> Specify target gdbserver binary. 316 --gdb=<file> Specify host gdb client binary. 317 --target-arch=<name> Specify NDK target arch. 318 --adb=<file> Specify host ADB binary. 319 320 --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are 321 run by this script. This can be useful to use 322 the 'su' program on rooted production devices. 323 e.g. --su-prefix="su -c" 324 325 --pull-libs Force system libraries extraction. 326 --no-pull-libs Do not extract any system library. 327 --libs-dir=<path> Specify system libraries extraction directory. 328 329 --debug Use libraries under out/Debug. 330 --release Use libraries under out/Release. 331 332 EOF 333 exit 0 334 fi 335 336 if [ -z "$PACKAGE_NAME" ]; then 337 panic "Please specify a package name on the command line. See --help." 338 fi 339 340 if [ -z "$NDK_DIR" ]; then 341 ANDROID_NDK_ROOT=$(PYTHONPATH=build/android python -c \ 342 'from pylib.constants import ANDROID_NDK_ROOT; print ANDROID_NDK_ROOT,') 343 else 344 if [ ! -d "$NDK_DIR" ]; then 345 panic "Invalid directory: $NDK_DIR" 346 fi 347 if [ ! -f "$NDK_DIR/ndk-build" ]; then 348 panic "Not a valid NDK directory: $NDK_DIR" 349 fi 350 ANDROID_NDK_ROOT=$NDK_DIR 351 fi 352 353 if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then 354 panic "Unknown --script file: $GDBINIT" 355 fi 356 357 # Find the target architecture from our $GYP_DEFINES 358 # This returns an NDK-compatible architecture name. 359 # out: NDK Architecture name, or empty string. 360 get_gyp_target_arch () { 361 local ARCH=$(echo $GYP_DEFINES | tr ' ' '\n' | grep '^target_arch=' |\ 362 cut -d= -f2) 363 case $ARCH in 364 ia32|i?86|x86) echo "x86";; 365 mips|arm|arm64|x86_64) echo "$ARCH";; 366 *) echo ""; 367 esac 368 } 369 370 if [ -z "$TARGET_ARCH" ]; then 371 TARGET_ARCH=$(get_gyp_target_arch) 372 if [ -z "$TARGET_ARCH" ]; then 373 TARGET_ARCH=arm 374 fi 375 else 376 # Nit: accept Chromium's 'ia32' as a valid target architecture. This 377 # script prefers the NDK 'x86' name instead because it uses it to find 378 # NDK-specific files (host gdb) with it. 379 if [ "$TARGET_ARCH" = "ia32" ]; then 380 TARGET_ARCH=x86 381 log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)" 382 fi 383 fi 384 385 # Detect the NDK system name, i.e. the name used to identify the host. 386 # out: NDK system name (e.g. 'linux' or 'darwin') 387 get_ndk_host_system () { 388 local HOST_OS 389 if [ -z "$NDK_HOST_SYSTEM" ]; then 390 HOST_OS=$(uname -s) 391 case $HOST_OS in 392 Linux) NDK_HOST_SYSTEM=linux;; 393 Darwin) NDK_HOST_SYSTEM=darwin;; 394 *) panic "You can't run this script on this system: $HOST_OS";; 395 esac 396 fi 397 echo "$NDK_HOST_SYSTEM" 398 } 399 400 # Detect the NDK host architecture name. 401 # out: NDK arch name (e.g. 'x86' or 'x86_64') 402 get_ndk_host_arch () { 403 local HOST_ARCH HOST_OS 404 if [ -z "$NDK_HOST_ARCH" ]; then 405 HOST_OS=$(get_ndk_host_system) 406 HOST_ARCH=$(uname -p) 407 case $HOST_ARCH in 408 i?86) NDK_HOST_ARCH=x86;; 409 x86_64|amd64) NDK_HOST_ARCH=x86_64;; 410 *) panic "You can't run this script on this host architecture: $HOST_ARCH";; 411 esac 412 # Darwin trick: "uname -p" always returns i386 on 64-bit installations. 413 if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then 414 # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts 415 # implementations of the tool. See http://b.android.com/53769 416 HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64") 417 if [ "$HOST_64BITS" ]; then 418 NDK_HOST_ARCH=x86_64 419 fi 420 fi 421 fi 422 echo "$NDK_HOST_ARCH" 423 } 424 425 # Convert an NDK architecture name into a GNU configure triplet. 426 # $1: NDK architecture name (e.g. 'arm') 427 # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi') 428 get_arch_gnu_config () { 429 case $1 in 430 arm) 431 echo "arm-linux-androideabi" 432 ;; 433 arm64) 434 echo "aarch64-linux-android" 435 ;; 436 x86) 437 echo "i686-linux-android" 438 ;; 439 x86_64) 440 echo "x86_64-linux-android" 441 ;; 442 mips) 443 echo "mipsel-linux-android" 444 ;; 445 *) 446 echo "$ARCH-linux-android" 447 ;; 448 esac 449 } 450 451 # Convert an NDK architecture name into a toolchain name prefix 452 # $1: NDK architecture name (e.g. 'arm') 453 # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi') 454 get_arch_toolchain_prefix () { 455 # Return the configure triplet, except for x86! 456 if [ "$1" = "x86" ]; then 457 echo "$1" 458 else 459 get_arch_gnu_config $1 460 fi 461 } 462 463 # Find a NDK toolchain prebuilt file or sub-directory. 464 # This will probe the various arch-specific toolchain directories 465 # in the NDK for the needed file. 466 # $1: NDK install path 467 # $2: NDK architecture name 468 # $3: prebuilt sub-path to look for. 469 # Out: file path, or empty if none is found. 470 get_ndk_toolchain_prebuilt () { 471 local NDK_DIR="${1%/}" 472 local ARCH="$2" 473 local SUBPATH="$3" 474 local NAME="$(get_arch_toolchain_prefix $ARCH)" 475 local FILE TARGET 476 FILE=$NDK_DIR/toolchains/$NAME-4.8/prebuilt/$SUBPATH 477 if [ ! -f "$FILE" ]; then 478 FILE=$NDK_DIR/toolchains/$NAME-4.9/prebuilt/$SUBPATH 479 if [ ! -f "$FILE" ]; then 480 FILE=$NDK_DIR/toolchains/$NAME-4.6/prebuilt/$SUBPATH 481 if [ ! -f "$FILE" ]; then 482 FILE= 483 fi 484 fi 485 fi 486 echo "$FILE" 487 } 488 489 # Find the path to an NDK's toolchain full prefix for a given architecture 490 # $1: NDK install path 491 # $2: NDK target architecture name 492 # Out: install path + binary prefix (e.g. 493 # ".../path/to/bin/arm-linux-androideabi-") 494 get_ndk_toolchain_fullprefix () { 495 local NDK_DIR="$1" 496 local ARCH="$2" 497 local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG 498 499 # NOTE: This will need to be updated if the NDK changes the names or moves 500 # the location of its prebuilt toolchains. 501 # 502 GCC= 503 HOST_OS=$(get_ndk_host_system) 504 HOST_ARCH=$(get_ndk_host_arch) 505 CONFIG=$(get_arch_gnu_config $ARCH) 506 GCC=$(get_ndk_toolchain_prebuilt \ 507 "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc") 508 if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then 509 GCC=$(get_ndk_toolchain_prebuilt \ 510 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc") 511 fi 512 if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then 513 # Special case, the x86 toolchain used to be incorrectly 514 # named i686-android-linux-gcc! 515 GCC=$(get_ndk_toolchain_prebuilt \ 516 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc") 517 fi 518 if [ -z "$GCC" ]; then 519 panic "Cannot find Android NDK toolchain for '$ARCH' architecture. \ 520 Please verify your NDK installation!" 521 fi 522 echo "${GCC%%gcc}" 523 } 524 525 # $1: NDK install path 526 # $2: target architecture. 527 get_ndk_gdbserver () { 528 local NDK_DIR="$1" 529 local ARCH=$2 530 local BINARY 531 532 # The location has moved after NDK r8 533 BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver 534 if [ ! -f "$BINARY" ]; then 535 BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver) 536 fi 537 echo "$BINARY" 538 } 539 540 # Check/probe the path to the Android toolchain installation. Always 541 # use the NDK versions of gdb and gdbserver. They must match to avoid 542 # issues when both binaries do not speak the same wire protocol. 543 # 544 if [ -z "$TOOLCHAIN" ]; then 545 ANDROID_TOOLCHAIN=$(get_ndk_toolchain_fullprefix \ 546 "$ANDROID_NDK_ROOT" "$TARGET_ARCH") 547 ANDROID_TOOLCHAIN=$(dirname "$ANDROID_TOOLCHAIN") 548 log "Auto-config: --toolchain=$ANDROID_TOOLCHAIN" 549 else 550 # Be flexible, allow one to specify either the install path or the bin 551 # sub-directory in --toolchain: 552 # 553 if [ -d "$TOOLCHAIN/bin" ]; then 554 TOOLCHAIN=$TOOLCHAIN/bin 555 fi 556 ANDROID_TOOLCHAIN=$TOOLCHAIN 557 fi 558 559 # Cosmetic: Remove trailing directory separator. 560 ANDROID_TOOLCHAIN=${ANDROID_TOOLCHAIN%/} 561 562 # Find host GDB client binary 563 if [ -z "$GDB" ]; then 564 GDB=$(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev/null | head -1) 565 if [ -z "$GDB" ]; then 566 panic "Can't find Android gdb client in your path, check your \ 567 --toolchain or --gdb path." 568 fi 569 log "Host gdb client: $GDB" 570 fi 571 572 # Find gdbserver binary, we will later push it to /data/local/tmp 573 # This ensures that both gdbserver and $GDB talk the same binary protocol, 574 # otherwise weird problems will appear. 575 # 576 if [ -z "$GDBSERVER" ]; then 577 GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH") 578 if [ -z "$GDBSERVER" ]; then 579 panic "Can't find NDK gdbserver binary. use --gdbserver to specify \ 580 valid one!" 581 fi 582 log "Auto-config: --gdbserver=$GDBSERVER" 583 fi 584 585 586 587 # Check that ADB is in our path 588 if [ -z "$ADB" ]; then 589 ADB=$(which adb 2>/dev/null) 590 if [ -z "$ADB" ]; then 591 panic "Can't find 'adb' tool in your path. Install it or use \ 592 --adb=<file>" 593 fi 594 log "Auto-config: --adb=$ADB" 595 fi 596 597 # Check that it works minimally 598 ADB_VERSION=$($ADB version 2>/dev/null) 599 echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge" 600 if [ $? != 0 ]; then 601 panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \ 602 different one: $ADB" 603 fi 604 605 # If there are more than one device connected, and ANDROID_SERIAL is not 606 # defined, print an error message. 607 NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l) 608 if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then 609 echo "ERROR: There is more than one Android device connected to ADB." 610 echo "Please define ANDROID_SERIAL to specify which one to use." 611 exit 1 612 fi 613 614 # A unique ID for this script's session. This needs to be the same in all 615 # sub-shell commands we're going to launch, so take the PID of the launcher 616 # process. 617 TMP_ID=$$ 618 619 # Temporary directory, will get cleaned up on exit. 620 TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID 621 mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/* 622 623 GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid 624 625 # Run a command through adb shell, strip the extra \r from the output 626 # and return the correct status code to detect failures. This assumes 627 # that the adb shell command prints a final \n to stdout. 628 # $1+: command to run 629 # Out: command's stdout 630 # Return: command's status 631 # Note: the command's stderr is lost 632 adb_shell () { 633 local TMPOUT="$(mktemp)" 634 local LASTLINE RET 635 local ADB=${ADB:-adb} 636 637 # The weird sed rule is to strip the final \r on each output line 638 # Since 'adb shell' never returns the command's proper exit/status code, 639 # we force it to print it as '%%<status>' in the temporary output file, 640 # which we will later strip from it. 641 $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \ 642 sed -e 's![[:cntrl:]]!!g' > $TMPOUT 643 # Get last line in log, which contains the exit code from the command 644 LASTLINE=$(sed -e '$!d' $TMPOUT) 645 # Extract the status code from the end of the line, which must 646 # be '%%<code>'. 647 RET=$(echo "$LASTLINE" | \ 648 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }') 649 # Remove the status code from the last line. Note that this may result 650 # in an empty line. 651 LASTLINE=$(echo "$LASTLINE" | \ 652 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }') 653 # The output itself: all lines except the status code. 654 sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE" 655 # Remove temp file. 656 rm -f $TMPOUT 657 # Exit with the appropriate status. 658 return $RET 659 } 660 661 # If --force is specified, try to kill any gdbserver process started by the 662 # same user on the device. Normally, these are killed automatically by the 663 # script on exit, but there are a few corner cases where this would still 664 # be needed. 665 if [ "$FORCE" ]; then 666 GDBSERVER_PIDS=$(adb_shell ps | awk '$9 ~ /gdbserver/ { print $2; }') 667 for GDB_PID in $GDBSERVER_PIDS; do 668 log "Killing previous gdbserver (PID=$GDB_PID)" 669 adb_shell kill -9 $GDB_PID 670 done 671 fi 672 673 if [ "$START" ]; then 674 log "Starting $PROGRAM_NAME on device." 675 adb_shell am start -n $PACKAGE_NAME/$ACTIVITY 2>/dev/null 676 adb_shell ps | grep -q $PACKAGE_NAME 677 fail_panic "Could not start $PROGRAM_NAME on device. Are you sure the \ 678 package is installed?" 679 fi 680 681 # Return the timestamp of a given time, as number of seconds since epoch. 682 # $1: file path 683 # Out: file timestamp 684 get_file_timestamp () { 685 stat -c %Y "$1" 2>/dev/null 686 } 687 688 # Detect the build type and symbol directory. This is done by finding 689 # the most recent sub-directory containing debug shared libraries under 690 # $CHROMIUM_SRC/$CHROMIUM_OUT_DIR/ 691 # 692 # $1: $BUILDTYPE value, can be empty 693 # Out: nothing, but this sets SYMBOL_DIR 694 # 695 detect_symbol_dir () { 696 local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP 697 # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while 698 # Make places then under out/$BUILDTYPE/lib.target. 699 if [ "$1" ]; then 700 SUBDIRS="$1/lib $1/lib.target" 701 else 702 SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target" 703 fi 704 LIST=$TMPDIR/scan-subdirs-$$.txt 705 printf "" > "$LIST" 706 for SUBDIR in $SUBDIRS; do 707 DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR 708 if [ -d "$DIR" ]; then 709 # Ignore build directories that don't contain symbol versions 710 # of the shared libraries. 711 DIR_LIBS=$(ls "$DIR"/lib*.so 2>/dev/null) 712 if [ -z "$DIR_LIBS" ]; then 713 echo "No shared libs: $DIR" 714 continue 715 fi 716 TSTAMP=$(get_file_timestamp "$DIR") 717 printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST" 718 fi 719 done 720 SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2) 721 rm -f "$LIST" 722 723 if [ -z "$SUBDIR" ]; then 724 if [ -z "$1" ]; then 725 panic "Could not find any build directory under \ 726 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Please build the program first!" 727 else 728 panic "Could not find any $1 directory under \ 729 $CHROMIUM_SRC/$CHROMIUM_OUT_DIR. Check your build type!" 730 fi 731 fi 732 733 SYMBOL_DIR=$CHROMIUM_SRC/$CHROMIUM_OUT_DIR/$SUBDIR 734 log "Auto-config: --symbol-dir=$SYMBOL_DIR" 735 } 736 737 if [ -z "$SYMBOL_DIR" ]; then 738 detect_symbol_dir "$BUILDTYPE" 739 fi 740 741 # Allow several concurrent debugging sessions 742 TARGET_GDBSERVER=/data/local/tmp/gdbserver-adb-gdb-$TMP_ID 743 744 # Return the build fingerprint contained in a build.prop file. 745 # $1: path to build.prop file 746 get_build_fingerprint_from () { 747 cat "$1" | grep -e '^ro.build.fingerprint=' | cut -d= -f2 748 } 749 750 751 ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR 752 PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR} 753 754 HOST_FINGERPRINT= 755 DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) 756 log "Device build fingerprint: $DEVICE_FINGERPRINT" 757 758 # If --pull-libs-dir is not specified, and this is a platform build, look 759 # if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/ 760 # directly, if the build fingerprint matches the device. 761 if [ -z "$ORG_PULL_LIBS_DIR" -a \ 762 "$ANDROID_PRODUCT_OUT" -a \ 763 -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then 764 ANDROID_FINGERPRINT=$(get_build_fingerprint_from \ 765 "$ANDROID_PRODUCT_OUT"/system/build.prop) 766 log "Android build fingerprint: $ANDROID_FINGERPRINT" 767 if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then 768 log "Perfect match!" 769 PULL_LIBS_DIR=$ANDROID_PRODUCT_OUT/symbols 770 HOST_FINGERPRINT=$ANDROID_FINGERPRINT 771 if [ "$PULL_LIBS" ]; then 772 log "Ignoring --pull-libs since the device and platform build \ 773 fingerprints match." 774 NO_PULL_LIBS=true 775 fi 776 fi 777 fi 778 779 # If neither --pull-libs an --no-pull-libs were specified, check the build 780 # fingerprints of the device, and the cached system libraries on the host. 781 # 782 if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then 783 if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then 784 log "Auto-config: --pull-libs (no cached libraries)" 785 PULL_LIBS=true 786 else 787 HOST_FINGERPRINT=$(get_build_fingerprint_from "$PULL_LIBS_DIR/build.prop") 788 log "Host build fingerprint: $HOST_FINGERPRINT" 789 if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then 790 log "Auto-config: --no-pull-libs (fingerprint match)" 791 NO_PULL_LIBS=true 792 else 793 log "Auto-config: --pull-libs (fingerprint mismatch)" 794 PULL_LIBS=true 795 fi 796 fi 797 fi 798 799 # Extract the system libraries from the device if necessary. 800 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then 801 echo "Extracting system libraries into: $PULL_LIBS_DIR" 802 fi 803 804 mkdir -p "$PULL_LIBS_DIR" 805 fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR" 806 807 # If requested, work for M-x gdb. The gdb indirections make it 808 # difficult to pass --annotate=3 to the gdb binary itself. 809 GDB_ARGS= 810 if [ "$ANNOTATE" ]; then 811 GDB_ARGS=$GDB_ARGS" --annotate=$ANNOTATE" 812 fi 813 814 # Get the PID from the first argument or else find the PID of the 815 # browser process. 816 if [ -z "$PID" ]; then 817 PROCESSNAME=$PACKAGE_NAME 818 if [ "$SANDBOXED_INDEX" ]; then 819 PROCESSNAME=$PROCESSNAME:sandboxed_process$SANDBOXED_INDEX 820 elif [ "$SANDBOXED" ]; then 821 PROCESSNAME=$PROCESSNAME:sandboxed_process 822 PID=$(adb_shell ps | \ 823 awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' | head -1) 824 fi 825 if [ -z "$PID" ]; then 826 PID=$(adb_shell ps | \ 827 awk '$9 == "'$PROCESSNAME'" { print $2; }' | head -1) 828 fi 829 if [ -z "$PID" ]; then 830 if [ "$START" ]; then 831 panic "Can't find application process PID, did it crash?" 832 else 833 panic "Can't find application process PID, are you sure it is \ 834 running? Try using --start." 835 fi 836 fi 837 log "Found process PID: $PID" 838 elif [ "$SANDBOXED" ]; then 839 echo "WARNING: --sandboxed option ignored due to use of --pid." 840 fi 841 842 # Determine if 'adb shell' runs as root or not. 843 # If so, we can launch gdbserver directly, otherwise, we have to 844 # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable. 845 # 846 if [ "$SU_PREFIX" ]; then 847 # Need to check that this works properly. 848 SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log 849 adb_shell $SU_PREFIX echo "foo" > $SU_PREFIX_TEST_LOG 2>&1 850 if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then 851 echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:" 852 echo "$ adb shell $SU_PREFIX echo foo" 853 cat $SU_PREFIX_TEST_LOG 854 exit 1 855 fi 856 COMMAND_PREFIX="$SU_PREFIX" 857 else 858 SHELL_UID=$(adb shell cat /proc/self/status | \ 859 awk '$1 == "Uid:" { print $2; }') 860 log "Shell UID: $SHELL_UID" 861 if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then 862 COMMAND_PREFIX="run-as $PACKAGE_NAME" 863 else 864 COMMAND_PREFIX= 865 fi 866 fi 867 log "Command prefix: '$COMMAND_PREFIX'" 868 869 # Pull device's system libraries that are mapped by our process. 870 # Pulling all system libraries is too long, so determine which ones 871 # we need by looking at /proc/$PID/maps instead 872 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then 873 echo "Extracting system libraries into: $PULL_LIBS_DIR" 874 rm -f $PULL_LIBS_DIR/build.prop 875 MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps) 876 if [ $? != 0 ]; then 877 echo "ERROR: Could not list process's memory mappings." 878 if [ "$SU_PREFIX" ]; then 879 panic "Are you sure your --su-prefix is correct?" 880 else 881 panic "Use --su-prefix if the application is not debuggable." 882 fi 883 fi 884 SYSTEM_LIBS=$(echo "$MAPPINGS" | \ 885 awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' | sort -u) 886 for SYSLIB in /system/bin/linker $SYSTEM_LIBS; do 887 echo "Pulling from device: $SYSLIB" 888 DST_FILE=$PULL_LIBS_DIR$SYSLIB 889 DST_DIR=$(dirname "$DST_FILE") 890 mkdir -p "$DST_DIR" && adb pull $SYSLIB "$DST_FILE" 2>/dev/null 891 fail_panic "Could not pull $SYSLIB from device !?" 892 done 893 echo "Pulling device build.prop" 894 adb pull /system/build.prop $PULL_LIBS_DIR/build.prop 895 fail_panic "Could not pull device build.prop !?" 896 fi 897 898 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4 899 # so we can add them to solib-search-path later. 900 SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \ 901 grep -v "^$" | tr '\n' ':') 902 903 # This is a re-implementation of gdbclient, where we use compatible 904 # versions of gdbserver and $GDBNAME to ensure that everything works 905 # properly. 906 # 907 908 # Push gdbserver to the device 909 log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER" 910 adb push $GDBSERVER $TARGET_GDBSERVER &>/dev/null 911 fail_panic "Could not copy gdbserver to the device!" 912 913 PORT=5039 914 HOST_PORT=$PORT 915 TARGET_PORT=$PORT 916 917 # Select correct app_process for architecture. 918 case $TARGET_ARCH in 919 arm|x86|mips) GDBEXEC=app_process;; 920 arm64|x86_64) GDBEXEC=app_process64;; 921 *) fail_panic "Unknown app_process for architecture!";; 922 esac 923 924 # Detect AddressSanitizer setup on the device. In that case app_process is a 925 # script, and the real executable is app_process.real. 926 GDBEXEC_ASAN=app_process.real 927 adb_shell ls /system/bin/$GDBEXEC_ASAN 928 if [ $? == 0 ]; then 929 GDBEXEC=$GDBEXEC_ASAN 930 fi 931 932 # Pull the app_process binary from the device. 933 log "Pulling $GDBEXEC from device" 934 adb pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null 935 fail_panic "Could not retrieve $GDBEXEC from the device!" 936 937 # Setup network redirection 938 log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)" 939 adb forward tcp:$HOST_PORT tcp:$TARGET_PORT 940 fail_panic "Could not setup network redirection from \ 941 host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!" 942 943 # Start gdbserver in the background 944 # Note that using run-as requires the package to be debuggable. 945 # 946 # If not, this will fail horribly. The alternative is to run the 947 # program as root, which requires of course root privileges. 948 # Maybe we should add a --root option to enable this? 949 # 950 log "Starting gdbserver in the background:" 951 GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log 952 log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \ 953 --attach $PID" 954 ("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \ 955 --attach $PID > $GDBSERVER_LOG 2>&1) & 956 GDBSERVER_PID=$! 957 echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE 958 log "background job pid: $GDBSERVER_PID" 959 960 # Check that it is still running after a few seconds. If not, this means we 961 # could not properly attach to it 962 sleep 2 963 log "Job control: $(jobs -l)" 964 STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }') 965 if [ "$STATE" != "Running" ]; then 966 echo "ERROR: GDBServer could not attach to PID $PID!" 967 echo "Failure log (use --verbose for more information):" 968 cat $GDBSERVER_LOG 969 exit 1 970 fi 971 972 # Generate a file containing useful GDB initialization commands 973 readonly COMMANDS=$TMPDIR/gdb.init 974 log "Generating GDB initialization commands file: $COMMANDS" 975 echo -n "" > $COMMANDS 976 echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS 977 echo "directory $CHROMIUM_SRC" >> $COMMANDS 978 echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS 979 echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \ 980 >> $COMMANDS 981 echo "echo Attaching and reading symbols, this may take a while.." \ 982 >> $COMMANDS 983 echo "target remote :$HOST_PORT" >> $COMMANDS 984 985 if [ "$GDBINIT" ]; then 986 cat "$GDBINIT" >> $COMMANDS 987 fi 988 989 if [ "$VERBOSE" -gt 0 ]; then 990 echo "### START $COMMANDS" 991 cat $COMMANDS 992 echo "### END $COMMANDS" 993 fi 994 995 log "Launching gdb client: $GDB $GDB_ARGS -x $COMMANDS" 996 $GDB $GDB_ARGS -x $COMMANDS && 997 rm -f "$GDBSERVER_PIDFILE" 998