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.
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
12 # Use --help to print full usage instructions.
15 PROGNAME
=$
(basename "$0")
16 PROGDIR
=$
(dirname "$0")
18 # Location of Chromium-top-level sources.
19 CHROMIUM_SRC
=$
(cd "$PROGDIR"/..
/..
&& pwd 2>/dev
/null
)
26 if [ "$TMPDIR" ]; then
27 GDBSERVER_PID
=$
(cat $GDBSERVER_PIDFILE 2>/dev
/null
)
28 if [ "$GDBSERVER_PID" ]; then
29 log
"Killing background gdbserver process: $GDBSERVER_PID"
30 kill -9 $GDBSERVER_PID >/dev
/null
2>&1
32 if [ "$TARGET_GDBSERVER" ]; then
33 log
"Removing target gdbserver binary: $TARGET_GDBSERVER."
34 "$ADB" shell
rm "$TARGET_GDBSERVER" >/dev
/null
2>&1
36 log
"Cleaning up: $TMPDIR"
43 # Ensure clean exit on Ctrl-C or normal exit.
44 trap "clean_exit 1" INT HUP QUIT TERM
45 trap "clean_exit \$?" EXIT
53 if [ $?
!= 0 ]; then panic
"$@"; fi
57 if [ "$VERBOSE" -gt 0 ]; then
62 DEFAULT_PULL_LIBS_DIR
=/tmp
/$USER-adb-gdb-libs
64 # NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX
65 # environment variables. This is only for cosmetic reasons, i.e. to
68 # Allow wrapper scripts to set the default activity through
69 # the ADB_GDB_ACTIVITY variable. Users are still able to change the
70 # final activity name through --activity=<name> option.
72 # This is only for cosmetic reasons, i.e. to display the proper default
73 # in the --help output.
75 DEFAULT_ACTIVITY
=${ADB_GDB_ACTIVITY:-".Main"}
77 # Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME
78 PROGNAME
=${ADB_GDB_PROGNAME:-$(basename "$0")}
80 ACTIVITY
=$DEFAULT_ACTIVITY
83 # Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it.
94 PROGRAM_NAME
="activity"
107 optarg
=$
(expr "x$opt" : 'x[^=]*=\(.*\)')
146 PULL_LIBS_DIR
=$optarg
153 SANDBOXED_INDEX
=$optarg
177 VERBOSE
=$
(( $VERBOSE + 1 ))
186 panic
"Unknown option $OPT, see --help." >&2
189 if [ "$PACKAGE_NAME" ]; then
190 panic
"You can only provide a single package name as argument!\
198 print_help_options
() {
204 if [ "$ADB_GDB_PROGNAME" ]; then
205 # Assume wrapper scripts all provide a default package name.
207 Usage: $PROGNAME [options]
209 Attach gdb to a running Android $PROGRAM_NAME process.
212 # Assume this is a direct call to adb_gdb
214 Usage: $PROGNAME [options] [<package-name>]
216 Attach gdb to a running Android $PROGRAM_NAME process.
218 If provided, <package-name> must be the name of the Android application's
219 package name to be debugged. You can also use --package-name=<name> to
226 This script is used to debug a running $PROGRAM_NAME process.
227 This can be a regular Android application process, or a sandboxed
228 service, if you use the --sandboxed or --sandboxed=<num> option.
230 This script needs several things to work properly. It will try to pick
231 them up automatically for you though:
233 - target gdbserver binary
234 - host gdb client (e.g. arm-linux-androideabi-gdb)
235 - directory with symbolic version of $PROGRAM_NAME's shared libraries.
237 If you have sourced Chromium's build/android/envsetup.sh, this script will
238 find all of them automatically. This is the recommended way to use it.
240 Otherwise, if you have ANDROID_NDK_ROOT defined in your environment,
241 the script will use it to find the gdb and gdbserver binaries. You can
242 also use --ndk-dir=<path> to specify an alternative NDK installation
245 The script tries to find the most recent version of the debug version of
246 shared libraries under one of the following directories:
248 \$CHROMIUM_SRC/out/Release/lib/ (used by Ninja builds)
249 \$CHROMIUM_SRC/out/Debug/lib/ (used by Ninja builds)
250 \$CHROMIUM_SRC/out/Release/lib.target/ (used by Make builds)
251 \$CHROMIUM_SRC/out/Debug/lib.target/ (used by Make builds)
253 You can restrict this search by using --release or --debug to specify the
254 build type, or simply use --symbol-dir=<path> to specify the file manually.
256 The script tries to extract the target architecture from your GYP_DEFINES,
257 but if this fails, will default to 'arm'. Use --target-arch=<name> to force
260 Otherwise, the script will complain, but you can use the --gdbserver,
261 --gdb and --symbol-lib options to specify everything manually.
263 An alternative to --gdb=<file> is to use --toollchain=<path> to specify
264 the path to the host target-specific cross-toolchain.
266 You will also need the 'adb' tool in your path. Otherwise, use the --adb
267 option. The script will complain if there is more than one device connected
268 and ANDROID_SERIAL is not defined.
270 The first time you use it on a device, the script will pull many system
271 libraries required by the process into a temporary directory. This
272 is done to strongly improve the debugging experience, like allowing
273 readable thread stacks and more. The libraries are copied to the following
274 directory by default:
276 $DEFAULT_PULL_LIBS_DIR/
278 But you can use the --pull-libs-dir=<path> option to specify an
279 alternative. The script can detect when you change the connected device,
280 and will re-pull the libraries only in this case. You can however force it
281 with the --pull-libs option.
283 Any local .gdbinit script will be ignored, but it is possible to pass a
284 gdb command script with the --script=<file> option. Note that its commands
285 will be passed to gdb after the remote connection and library symbol
286 loading have completed.
289 --help|-h|-? Print this message.
290 --verbose Increase verbosity.
292 --sandboxed Debug first sandboxed process we find.
293 --sandboxed=<num> Debug specific sandboxed process.
294 --symbol-dir=<path> Specify directory with symbol shared libraries.
295 --package-name=<name> Specify package name (alternative to 1st argument).
296 --program-name=<name> Specify program name (cosmetic only).
297 --pid=<pid> Specify application process pid.
298 --force Kill any previous debugging session, if any.
299 --start Start package's activity on device.
300 --ui Use gdbtui instead of gdb
301 --activity=<name> Activity name for --start [$DEFAULT_ACTIVITY].
302 --annotate=<num> Enable gdb annotation.
303 --script=<file> Specify extra GDB init script.
305 --gdbserver=<file> Specify targer gdbserver binary.
306 --gdb=<program> Specify host gdb client binary.
307 --target-arch=<name> Specify NDK target arch.
308 --adb=<program> Specify host ADB binary.
310 --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are
311 run by this script. This can be useful to use
312 the 'su' program on rooted production devices.
314 --pull-libs Force system libraries extraction.
315 --no-pull-libs Do not extract any system library.
316 --libs-dir=<path> Specify system libraries extraction directory.
318 --debug Use libraries under out/Debug.
319 --release Use libraries under out/Release.
325 if [ -z "$PACKAGE_NAME" ]; then
326 panic
"Please specify a package name on the command line. See --help."
329 if [ -z "$NDK_DIR" ]; then
330 if [ -z "$ANDROID_NDK_ROOT" ]; then
331 panic
"Can't find NDK directory, please source \
332 build/android/envsetup.sh!"
335 if [ ! -d "$NDK_DIR" ]; then
336 panic
"Invalid directory: $NDK_DIR"
338 if [ ! -f "$NDK_DIR/ndk-build" ]; then
339 panic
"Not a valid NDK directory: $NDK_DIR"
341 ANDROID_NDK_ROOT
=$NDK_DIR
344 if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then
345 panic
"Unknown --script file: $GDBINIT"
348 # Find the target architecture from our $GYP_DEFINES
349 # This returns an NDK-compatible architecture name.
350 # out: NDK Architecture name, or empty string.
351 get_gyp_target_arch
() {
352 local ARCH
=$
(echo $GYP_DEFINES |
tr ' ' '\n' |
grep '^target_arch=' |\
355 ia32|i?
86|x86
) echo "x86";;
356 mips|arm
) echo "$ARCH";;
361 if [ -z "$TARGET_ARCH" ]; then
362 TARGET_ARCH
=$
(get_gyp_target_arch
)
363 if [ -z "$TARGET_ARCH" ]; then
367 # Nit: accept Chromium's 'ia32' as a valid target architecture. This
368 # script prefers the NDK 'x86' name instead because it uses it to find
369 # NDK-specific files (host gdb) with it.
370 if [ "$TARGET_ARCH" = "ia32" ]; then
372 log
"Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)"
376 # Detect the NDK system name, i.e. the name used to identify the host.
377 # out: NDK system name (e.g. 'linux' or 'darwin')
378 get_ndk_host_system
() {
380 if [ -z "$NDK_HOST_SYSTEM" ]; then
383 Linux
) NDK_HOST_SYSTEM
=linux
;;
384 Darwin
) NDK_HOST_SYSTEM
=darwin
;;
385 *) panic
"You can't run this script on this system: $HOST_OS";;
388 echo "$NDK_HOST_SYSTEM"
391 # Detect the NDK host architecture name.
392 # out: NDK arch name (e.g. 'x86' or 'x86_64')
393 get_ndk_host_arch
() {
394 local HOST_ARCH HOST_OS
395 if [ -z "$NDK_HOST_ARCH" ]; then
396 HOST_OS
=$
(get_ndk_host_system
)
397 HOST_ARCH
=$
(uname
-p)
399 i?
86) NDK_HOST_ARCH
=x86
;;
400 x86_64|amd64
) NDK_HOST_ARCH
=x86_64
;;
401 *) panic
"You can't run this script on this host architecture: $HOST_ARCH";;
403 # Darwin trick: "uname -p" always returns i386 on 64-bit installations.
404 if [ "$HOST_OS" = darwin
-a "$NDK_HOST_ARCH" = "x86" ]; then
405 # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts
406 # implementations of the tool. See http://b.android.com/53769
407 HOST_64BITS
=$
(/usr
/bin
/file -L "$SHELL" |
grep -e "x86[_-]64")
408 if [ "$HOST_64BITS" ]; then
413 echo "$NDK_HOST_ARCH"
416 # Convert an NDK architecture name into a GNU configure triplet.
417 # $1: NDK architecture name (e.g. 'arm')
418 # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi')
419 get_arch_gnu_config
() {
422 echo "arm-linux-androideabi"
425 echo "i686-linux-android"
428 echo "mipsel-linux-android"
431 echo "$ARCH-linux-android"
436 # Convert an NDK architecture name into a toolchain name prefix
437 # $1: NDK architecture name (e.g. 'arm')
438 # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi')
439 get_arch_toolchain_prefix
() {
440 # Return the configure triplet, except for x86!
441 if [ "$1" = "x86" ]; then
444 get_arch_gnu_config
$1
448 # Find a NDK toolchain prebuilt file or sub-directory.
449 # This will probe the various arch-specific toolchain directories
450 # in the NDK for the needed file.
451 # $1: NDK install path
452 # $2: NDK architecture name
453 # $3: prebuilt sub-path to look for.
454 # Out: file path, or empty if none is found.
455 get_ndk_toolchain_prebuilt
() {
456 local NDK_DIR
="${1%/}"
459 local NAME
="$(get_arch_toolchain_prefix $ARCH)"
461 FILE
=$NDK_DIR/toolchains
/$NAME-4.6
/prebuilt
/$SUBPATH
462 if [ ! -f "$FILE" ]; then
463 FILE
=$NDK_DIR/toolchains
/$NAME-4.4
.3/prebuilt
/$SUBPATH
464 if [ ! -f "$FILE" ]; then
471 # Find the path to an NDK's toolchain full prefix for a given architecture
472 # $1: NDK install path
473 # $2: NDK target architecture name
474 # Out: install path + binary prefix (e.g.
475 # ".../path/to/bin/arm-linux-androideabi-")
476 get_ndk_toolchain_fullprefix
() {
479 local TARGET NAME HOST_OS HOST_ARCH GCC CONFIG
481 # NOTE: This will need to be updated if the NDK changes the names or moves
482 # the location of its prebuilt toolchains.
485 HOST_OS
=$
(get_ndk_host_system
)
486 HOST_ARCH
=$
(get_ndk_host_arch
)
487 CONFIG
=$
(get_arch_gnu_config
$ARCH)
488 GCC
=$
(get_ndk_toolchain_prebuilt \
489 "$NDK_DIR" "$ARCH" "$HOST_OS-$HOST_ARCH/bin/$CONFIG-gcc")
490 if [ -z "$GCC" -a "$HOST_ARCH" = "x86_64" ]; then
491 GCC
=$
(get_ndk_toolchain_prebuilt \
492 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/$CONFIG-gcc")
494 if [ ! -f "$GCC" -a "$ARCH" = "x86" ]; then
495 # Special case, the x86 toolchain used to be incorrectly
496 # named i686-android-linux-gcc!
497 GCC
=$
(get_ndk_toolchain_prebuilt \
498 "$NDK_DIR" "$ARCH" "$HOST_OS-x86/bin/i686-android-linux-gcc")
500 if [ -z "$GCC" ]; then
501 panic
"Cannot find Android NDK toolchain for '$ARCH' architecture. \
502 Please verify your NDK installation!"
507 # $1: NDK install path
508 # $2: target architecture.
509 get_ndk_gdbserver
() {
514 # The location has moved after NDK r8
515 BINARY
=$NDK_DIR/prebuilt
/android-
$ARCH/gdbserver
/gdbserver
516 if [ ! -f "$BINARY" ]; then
517 BINARY
=$
(get_ndk_toolchain_prebuilt
"$NDK_DIR" "$ARCH" gdbserver
)
522 # Check/probe the path to the Android toolchain installation. Always
523 # use the NDK versions of gdb and gdbserver. They must match to avoid
524 # issues when both binaries do not speak the same wire protocol.
526 if [ -z "$TOOLCHAIN" ]; then
527 ANDROID_TOOLCHAIN
=$
(get_ndk_toolchain_fullprefix \
528 "$ANDROID_NDK_ROOT" "$TARGET_ARCH")
529 ANDROID_TOOLCHAIN
=$
(dirname "$ANDROID_TOOLCHAIN")
530 log
"Auto-config: --toolchain=$ANDROID_TOOLCHAIN"
532 # Be flexible, allow one to specify either the install path or the bin
533 # sub-directory in --toolchain:
535 if [ -d "$TOOLCHAIN/bin" ]; then
536 TOOLCHAIN
=$TOOLCHAIN/bin
538 ANDROID_TOOLCHAIN
=$TOOLCHAIN
541 # Cosmetic: Remove trailing directory separator.
542 ANDROID_TOOLCHAIN
=${ANDROID_TOOLCHAIN%/}
544 # Find host GDB client binary
545 GDB
=$
(which $ANDROID_TOOLCHAIN/*-$GDBEXEPOSTFIX 2>/dev
/null |
head -1)
546 if [ -z "$GDB" ]; then
547 panic
"Can't find Android gdb client in your path, check your \
550 log
"Host gdb client: $GDB"
552 # Find gdbserver binary, we will later push it to /data/local/tmp
553 # This ensures that both gdbserver and $GDB talk the same binary protocol,
554 # otherwise weird problems will appear.
556 if [ -z "$GDBSERVER" ]; then
557 GDBSERVER
=$
(get_ndk_gdbserver
"$ANDROID_NDK_ROOT" "$TARGET_ARCH")
558 if [ -z "$GDBSERVER" ]; then
559 panic
"Can't find NDK gdbserver binary. use --gdbserver to specify \
562 log
"Auto-config: --gdbserver=$GDBSERVER"
567 # Check that ADB is in our path
568 if [ -z "$ADB" ]; then
569 ADB
=$
(which adb
2>/dev
/null
)
570 if [ -z "$ADB" ]; then
571 panic
"Can't find 'adb' tool in your path. Install it or use \
574 log
"Auto-config: --adb=$ADB"
577 # Check that it works minimally
578 ADB_VERSION
=$
($ADB version
2>/dev
/null
)
579 echo "$ADB_VERSION" | fgrep
-q -e "Android Debug Bridge"
581 panic
"Your 'adb' tool seems invalid, use --adb=<file> to specify a \
585 # If there are more than one device connected, and ANDROID_SERIAL is not
586 # defined, print an error message.
587 NUM_DEVICES_PLUS2
=$
($ADB devices
2>/dev
/null |
wc -l)
588 if [ "$NUM_DEVICES_PLUS2" -lt 3 -a -z "$ANDROID_SERIAL" ]; then
589 echo "ERROR: There is more than one Android device connected to ADB."
590 echo "Please define ANDROID_SERIAL to specify which one to use."
594 # A unique ID for this script's session. This needs to be the same in all
595 # sub-shell commands we're going to launch, so take the PID of the launcher
599 # Temporary directory, will get cleaned up on exit.
600 TMPDIR
=/tmp
/$USER-adb-gdb-tmp-$TMP_ID
601 mkdir
-p "$TMPDIR" && rm -rf "$TMPDIR"/*
603 GDBSERVER_PIDFILE
="$TMPDIR"/gdbserver-
$TMP_ID.pid
605 # Run a command through adb shell, strip the extra \r from the output
606 # and return the correct status code to detect failures. This assumes
607 # that the adb shell command prints a final \n to stdout.
608 # $1+: command to run
609 # Out: command's stdout
610 # Return: command's status
611 # Note: the command's stderr is lost
613 local TMPOUT
="$(mktemp)"
615 local ADB
=${ADB:-adb}
617 # The weird sed rule is to strip the final \r on each output line
618 # Since 'adb shell' never returns the command's proper exit/status code,
619 # we force it to print it as '%%<status>' in the temporary output file,
620 # which we will later strip from it.
621 $ADB shell $@
";" echo "%%\$?" 2>/dev
/null | \
622 sed -e 's![[:cntrl:]]!!g' > $TMPOUT
623 # Get last line in log, which contains the exit code from the command
624 LASTLINE
=$
(sed -e '$!d' $TMPOUT)
625 # Extract the status code from the end of the line, which must
627 RET
=$
(echo "$LASTLINE" | \
628 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }')
629 # Remove the status code from the last line. Note that this may result
631 LASTLINE
=$
(echo "$LASTLINE" | \
632 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }')
633 # The output itself: all lines except the status code.
634 sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE"
637 # Exit with the appropriate status.
641 # If --force is specified, try to kill any gdbserver process started by the
642 # same user on the device. Normally, these are killed automatically by the
643 # script on exit, but there are a few corner cases where this would still
645 if [ "$FORCE" ]; then
646 GDBSERVER_PIDS
=$
(adb_shell ps |
awk '$9 ~ /gdbserver/ { print $2; }')
647 for GDB_PID
in $GDBSERVER_PIDS; do
648 log
"Killing previous gdbserver (PID=$GDB_PID)"
649 adb_shell
kill -9 $GDB_PID
653 if [ "$START" ]; then
654 log
"Starting $PROGRAM_NAME on device."
655 adb_shell am start
-n $PACKAGE_NAME/$ACTIVITY 2>/dev
/null
656 adb_shell ps |
grep -q $PACKAGE_NAME
657 fail_panic
"Could not start $PROGRAM_NAME on device. Are you sure the \
658 package is installed?"
661 # Return the timestamp of a given time, as number of seconds since epoch.
663 # Out: file timestamp
664 get_file_timestamp
() {
665 stat
-c %Y
"$1" 2>/dev
/null
668 # Detect the build type and symbol directory. This is done by finding
669 # the most recent sub-directory containing debug shared libraries under
672 # $1: $BUILDTYPE value, can be empty
673 # Out: nothing, but this sets SYMBOL_DIR
675 detect_symbol_dir
() {
676 local SUBDIRS SUBDIR LIST DIR DIR_LIBS TSTAMP
677 # Note: Ninja places debug libraries under out/$BUILDTYPE/lib/, while
678 # Make places then under out/$BUILDTYPE/lib.target.
680 SUBDIRS
="$1/lib $1/lib.target"
682 SUBDIRS
="Release/lib Debug/lib Release/lib.target Debug/lib.target"
684 LIST
=$TMPDIR/scan-subdirs-$$.txt
686 for SUBDIR
in $SUBDIRS; do
687 DIR
=$CHROMIUM_SRC/out
/$SUBDIR
688 if [ -d "$DIR" ]; then
689 # Ignore build directories that don't contain symbol versions
690 # of the shared libraries.
691 DIR_LIBS
=$
(ls "$DIR"/lib
*.so
2>/dev
/null
)
692 if [ -z "$DIR_LIBS" ]; then
693 echo "No shared libs: $DIR"
696 TSTAMP
=$
(get_file_timestamp
"$DIR")
697 printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
700 SUBDIR
=$
(cat $LIST |
sort -r |
head -1 | cut
-d" " -f2)
703 if [ -z "$SUBDIR" ]; then
705 panic
"Could not find any build directory under \
706 $CHROMIUM_SRC/out. Please build the program first!"
708 panic
"Could not find any $1 directory under \
709 $CHROMIUM_SRC/out. Check your build type!"
713 SYMBOL_DIR
=$CHROMIUM_SRC/out
/$SUBDIR
714 log
"Auto-config: --symbol-dir=$SYMBOL_DIR"
717 if [ -z "$SYMBOL_DIR" ]; then
718 detect_symbol_dir
"$BUILDTYPE"
721 # Allow several concurrent debugging sessions
722 TARGET_GDBSERVER
=/data
/local
/tmp
/gdbserver-adb-gdb-
$TMP_ID
724 # Return the build fingerprint contained in a build.prop file.
725 # $1: path to build.prop file
726 get_build_fingerprint_from
() {
727 cat "$1" |
grep -e '^ro.build.fingerprint=' | cut
-d= -f2
731 ORG_PULL_LIBS_DIR
=$PULL_LIBS_DIR
732 PULL_LIBS_DIR
=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
735 DEVICE_FINGERPRINT
=$
(adb_shell getprop ro.build.fingerprint
)
736 log
"Device build fingerprint: $DEVICE_FINGERPRINT"
738 # If --pull-libs-dir is not specified, and this is a platform build, look
739 # if we can use the symbolic libraries under $ANDROID_PRODUCT_OUT/symbols/
740 # directly, if the build fingerprint matches the device.
741 if [ -z "$ORG_PULL_LIBS_DIR" -a \
742 "$ANDROID_PRODUCT_OUT" -a \
743 -f "$ANDROID_PRODUCT_OUT/system/build.prop" ]; then
744 ANDROID_FINGERPRINT
=$
(get_build_fingerprint_from \
745 "$ANDROID_PRODUCT_OUT"/system
/build.prop
)
746 log
"Android build fingerprint: $ANDROID_FINGERPRINT"
747 if [ "$ANDROID_FINGERPRINT" = "$DEVICE_FINGERPRINT" ]; then
749 PULL_LIBS_DIR
=$ANDROID_PRODUCT_OUT/symbols
750 HOST_FINGERPRINT
=$ANDROID_FINGERPRINT
751 if [ "$PULL_LIBS" ]; then
752 log
"Ignoring --pull-libs since the device and platform build \
759 # If neither --pull-libs an --no-pull-libs were specified, check the build
760 # fingerprints of the device, and the cached system libraries on the host.
762 if [ -z "$NO_PULL_LIBS" -a -z "$PULL_LIBS" ]; then
763 if [ ! -f "$PULL_LIBS_DIR/build.prop" ]; then
764 log
"Auto-config: --pull-libs (no cached libraries)"
767 HOST_FINGERPRINT
=$
(get_build_fingerprint_from
"$PULL_LIBS_DIR/build.prop")
768 log
"Host build fingerprint: $HOST_FINGERPRINT"
769 if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
770 log
"Auto-config: --no-pull-libs (fingerprint match)"
773 log
"Auto-config: --pull-libs (fingerprint mismatch)"
779 # Extract the system libraries from the device if necessary.
780 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
781 echo "Extracting system libraries into: $PULL_LIBS_DIR"
784 mkdir
-p "$PULL_LIBS_DIR"
785 fail_panic
"Can't create --libs-dir directory: $PULL_LIBS_DIR"
787 # If requested, work for M-x gdb. The gdb indirections make it
788 # difficult to pass --annotate=3 to the gdb binary itself.
790 if [ "$ANNOTATE" ]; then
791 GDB_ARGS
=$GDB_ARGS" --annotate=$ANNOTATE"
794 # Get the PID from the first argument or else find the PID of the
796 if [ -z "$PID" ]; then
797 PROCESSNAME
=$PACKAGE_NAME
798 if [ "$SANDBOXED_INDEX" ]; then
799 PROCESSNAME
=$PROCESSNAME:sandboxed_process
$SANDBOXED_INDEX
800 elif [ "$SANDBOXED" ]; then
801 PROCESSNAME
=$PROCESSNAME:sandboxed_process
802 PID
=$
(adb_shell ps | \
803 awk '$9 ~ /^'$PROCESSNAME'/ { print $2; }' |
head -1)
805 if [ -z "$PID" ]; then
806 PID
=$
(adb_shell ps | \
807 awk '$9 == "'$PROCESSNAME'" { print $2; }' |
head -1)
809 if [ -z "$PID" ]; then
810 if [ "$START" ]; then
811 panic
"Can't find application process PID, did it crash?"
813 panic
"Can't find application process PID, are you sure it is \
814 running? Try using --start."
817 log
"Found process PID: $PID"
818 elif [ "$SANDBOXED" ]; then
819 echo "WARNING: --sandboxed option ignored due to use of --pid."
822 # Determine if 'adb shell' runs as root or not.
823 # If so, we can launch gdbserver directly, otherwise, we have to
824 # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable.
826 if [ "$SU_PREFIX" ]; then
827 # Need to check that this works properly.
828 SU_PREFIX_TEST_LOG
=$TMPDIR/su-prefix.log
829 adb_shell
$SU_PREFIX echo "foo" > $SU_PREFIX_TEST_LOG 2>&1
830 if [ $?
!= 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then
831 echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:"
832 echo "$ adb shell $SU_PREFIX echo foo"
833 cat $SU_PREFIX_TEST_LOG
836 COMMAND_PREFIX
=$SU_PREFIX
838 SHELL_UID
=$
(adb shell
cat /proc
/self
/status | \
839 awk '$1 == "Uid:" { print $2; }')
840 log
"Shell UID: $SHELL_UID"
841 if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
842 COMMAND_PREFIX
="run-as $PACKAGE_NAME"
847 log
"Command prefix: '$COMMAND_PREFIX'"
849 # Pull device's system libraries that are mapped by our process.
850 # Pulling all system libraries is too long, so determine which ones
851 # we need by looking at /proc/$PID/maps instead
852 if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then
853 echo "Extracting system libraries into: $PULL_LIBS_DIR"
854 rm -f $PULL_LIBS_DIR/build.prop
855 MAPPINGS
=$
(adb_shell
$COMMAND_PREFIX cat /proc
/$PID/maps
)
857 echo "ERROR: Could not list process's memory mappings."
858 if [ "$SU_PREFIX" ]; then
859 panic
"Are you sure your --su-prefix is correct?"
861 panic
"Use --su-prefix if the application is not debuggable."
864 SYSTEM_LIBS
=$
(echo "$MAPPINGS" | \
865 awk '$6 ~ /\/system\/.*\.so$/ { print $6; }' |
sort -u)
866 for SYSLIB
in /system
/bin
/linker
$SYSTEM_LIBS; do
867 echo "Pulling from device: $SYSLIB"
868 DST_FILE
=$PULL_LIBS_DIR$SYSLIB
869 DST_DIR
=$
(dirname "$DST_FILE")
870 mkdir
-p "$DST_DIR" && adb pull
$SYSLIB "$DST_FILE" 2>/dev
/null
871 fail_panic
"Could not pull $SYSLIB from device !?"
873 echo "Pulling device build.prop"
874 adb pull
/system
/build.prop
$PULL_LIBS_DIR/build.prop
875 fail_panic
"Could not pull device build.prop !?"
878 # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4
879 # so we can add them to solib-search-path later.
880 SOLIB_DIRS
=$
(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
881 grep -v "^$" |
tr '\n' ':')
883 # This is a re-implementation of gdbclient, where we use compatible
884 # versions of gdbserver and $GDBNAME to ensure that everything works
888 # Push gdbserver to the device
889 log
"Pushing gdbserver to $TARGET_GDBSERVER"
890 adb push
$GDBSERVER $TARGET_GDBSERVER &>/dev
/null
891 fail_panic
"Could not copy gdbserver to the device!"
897 # Pull the app_process binary from the device
899 log
"Pulling $GDBEXEC from device"
900 adb pull
/system
/bin
/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev
/null
901 fail_panic
"Could not retrieve $GDBEXEC from the device!"
903 # Setup network redirection
904 log
"Setting network redirection (host:$HOST_PORT -> device:$TARGET_PORT)"
905 adb forward tcp
:$HOST_PORT tcp
:$TARGET_PORT
906 fail_panic
"Could not setup network redirection from \
907 host:localhost:$HOST_PORT to device:localhost:$TARGET_PORT!"
909 # Start gdbserver in the background
910 # Note that using run-as requires the package to be debuggable.
912 # If not, this will fail horribly. The alternative is to run the
913 # program as root, which requires of course root privileges.
914 # Maybe we should add a --root option to enable this?
916 log
"Starting gdbserver in the background:"
917 GDBSERVER_LOG
=$TMPDIR/gdbserver-
$TMP_ID.log
918 log
"adb shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
920 ("$ADB" shell
$COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
921 --attach $PID > $GDBSERVER_LOG 2>&1) &
923 echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE
924 log
"background job pid: $GDBSERVER_PID"
926 # Check that it is still running after a few seconds. If not, this means we
927 # could not properly attach to it
929 log
"Job control: $(jobs -l)"
930 STATE
=$
(jobs -l |
awk '$2 == "'$GDBSERVER_PID'" { print $3; }')
931 if [ "$STATE" != "Running" ]; then
932 echo "ERROR: GDBServer could not attach to PID $PID!"
933 echo "Failure log (use --verbose for more information):"
938 # Generate a file containing useful GDB initialization commands
939 readonly COMMANDS
=$TMPDIR/gdb.init
940 log
"Generating GDB initialization commands file: $COMMANDS"
941 echo -n "" > $COMMANDS
942 echo "file $TMPDIR/$GDBEXEC" >> $COMMANDS
943 echo "directory $CHROMIUM_SRC" >> $COMMANDS
944 echo "set solib-absolute-prefix $PULL_LIBS_DIR" >> $COMMANDS
945 echo "set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR" \
947 echo "echo Attaching and reading symbols, this may take a while.." \
949 echo "target remote :$HOST_PORT" >> $COMMANDS
951 if [ "$GDBINIT" ]; then
952 cat "$GDBINIT" >> $COMMANDS
955 if [ "$VERBOSE" -gt 0 ]; then
956 echo "### START $COMMANDS"
958 echo "### END $COMMANDS"
961 log
"Launching gdb client: $GDB $GDBARGS -x $COMMANDS"
962 $GDB $GDBARGS -x $COMMANDS &&
963 rm -f "$GDBSERVER_PIDFILE"