Move prefs::kLastPolicyStatisticsUpdate to the policy component.
[chromium-blink-merge.git] / build / android / adb_gdb
blob0f5f2c4cb13b52ce7f51087703efb0a576830a47
1 #!/bin/bash
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)
21 TMPDIR=
22 GDBSERVER_PIDFILE=
23 TARGET_GDBSERVER=
25 clean_exit () {
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"
37 rm -rf "$TMPDIR"
39 trap "" EXIT
40 exit $1
43 # Ensure clean exit on Ctrl-C or normal exit.
44 trap "clean_exit 1" INT HUP QUIT TERM
45 trap "clean_exit \$?" EXIT
47 panic () {
48 echo "ERROR: $@" >&2
49 exit 1
52 fail_panic () {
53 if [ $? != 0 ]; then panic "$@"; fi
56 log () {
57 if [ "$VERBOSE" -gt 0 ]; then
58 echo "$@"
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
66 # display proper
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
81 ADB=
82 ANNOTATE=
83 # Note: Ignore BUILDTYPE variable, because the Ninja build doesn't use it.
84 BUILDTYPE=
85 FORCE=
86 GDBEXEPOSTFIX=gdb
87 GDBINIT=
88 GDBSERVER=
89 HELP=
90 NDK_DIR=
91 NO_PULL_LIBS=
92 PACKAGE_NAME=
93 PID=
94 PROGRAM_NAME="activity"
95 PULL_LIBS=
96 PULL_LIBS_DIR=
97 SANDBOXED=
98 SANDBOXED_INDEX=
99 START=
100 SU_PREFIX=
101 SYMBOL_DIR=
102 TARGET_ARCH=
103 TOOLCHAIN=
104 VERBOSE=0
106 for opt; do
107 optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
108 case $opt in
109 --adb=*)
110 ADB=$optarg
112 --activity=*)
113 ACTIVITY=$optarg
115 --annotate=3)
116 ANNOTATE=$optarg
118 --force)
119 FORCE=true
121 --gdbserver=*)
122 GDBSERVER=$optarg
124 --help|-h|-?)
125 HELP=true
127 --ndk-dir=*)
128 NDK_DIR=$optarg
130 --no-pull-libs)
131 NO_PULL_LIBS=true
133 --package-name=*)
134 PACKAGE_NAME=$optarg
136 --pid=*)
137 PID=$optarg
139 --program-name=*)
140 PROGRAM_NAME=$optarg
142 --pull-libs)
143 PULL_LIBS=true
145 --pull-libs-dir=*)
146 PULL_LIBS_DIR=$optarg
148 --sandboxed)
149 SANDBOXED=true
151 --sandboxed=*)
152 SANDBOXED=true
153 SANDBOXED_INDEX=$optarg
155 --script=*)
156 GDBINIT=$optarg
158 --start)
159 START=true
161 --su-prefix=*)
162 SU_PREFIX=$optarg
164 --symbol-dir=*)
165 SYMBOL_DIR=$optarg
167 --target-arch=*)
168 TARGET_ARCH=$optarg
170 --toolchain=*)
171 TOOLCHAIN=$optarg
173 --ui)
174 GDBEXEPOSTFIX=gdbtui
176 --verbose)
177 VERBOSE=$(( $VERBOSE + 1 ))
179 --debug)
180 BUILDTYPE=Debug
182 --release)
183 BUILDTYPE=Release
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!\
191 See --help."
193 PACKAGE_NAME=$opt
195 esac
196 done
198 print_help_options () {
199 cat <<EOF
203 if [ "$HELP" ]; then
204 if [ "$ADB_GDB_PROGNAME" ]; then
205 # Assume wrapper scripts all provide a default package name.
206 cat <<EOF
207 Usage: $PROGNAME [options]
209 Attach gdb to a running Android $PROGRAM_NAME process.
211 else
212 # Assume this is a direct call to adb_gdb
213 cat <<EOF
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
220 specify it.
224 cat <<EOF
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
243 directory.
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
258 its value.
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.
288 Valid options:
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.
322 exit 0
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!"
334 else
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=' |\
353 cut -d= -f2)
354 case $ARCH in
355 ia32|i?86|x86) echo "x86";;
356 mips|arm) echo "$ARCH";;
357 *) echo "";
358 esac
361 if [ -z "$TARGET_ARCH" ]; then
362 TARGET_ARCH=$(get_gyp_target_arch)
363 if [ -z "$TARGET_ARCH" ]; then
364 TARGET_ARCH=arm
366 else
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
371 TARGET_ARCH=x86
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 () {
379 local HOST_OS
380 if [ -z "$NDK_HOST_SYSTEM" ]; then
381 HOST_OS=$(uname -s)
382 case $HOST_OS in
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";;
386 esac
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)
398 case $HOST_ARCH in
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";;
402 esac
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
409 NDK_HOST_ARCH=x86_64
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 () {
420 case $1 in
421 arm)
422 echo "arm-linux-androideabi"
424 x86)
425 echo "i686-linux-android"
427 mips)
428 echo "mipsel-linux-android"
431 echo "$ARCH-linux-android"
433 esac
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
442 echo "$1"
443 else
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%/}"
457 local ARCH="$2"
458 local SUBPATH="$3"
459 local NAME="$(get_arch_toolchain_prefix $ARCH)"
460 local FILE TARGET
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
465 FILE=
468 echo "$FILE"
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 () {
477 local NDK_DIR="$1"
478 local ARCH="$2"
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.
484 GCC=
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!"
504 echo "${GCC%%gcc}"
507 # $1: NDK install path
508 # $2: target architecture.
509 get_ndk_gdbserver () {
510 local NDK_DIR="$1"
511 local ARCH=$2
512 local BINARY
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)
519 echo "$BINARY"
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"
531 else
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 \
548 --toolchain path."
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 \
560 valid one!"
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 \
572 --adb=<file>"
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"
580 if [ $? != 0 ]; then
581 panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
582 different one: $ADB"
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."
591 exit 1
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
596 # process.
597 TMP_ID=$$
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
612 adb_shell () {
613 local TMPOUT="$(mktemp)"
614 local LASTLINE RET
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
626 # be '%%<code>'.
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
630 # in an empty line.
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"
635 # Remove temp file.
636 rm -f $TMPOUT
637 # Exit with the appropriate status.
638 return $RET
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
644 # be needed.
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
650 done
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.
662 # $1: file path
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
670 # $CHROMIUM_SRC/out/
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.
679 if [ "$1" ]; then
680 SUBDIRS="$1/lib $1/lib.target"
681 else
682 SUBDIRS="Release/lib Debug/lib Release/lib.target Debug/lib.target"
684 LIST=$TMPDIR/scan-subdirs-$$.txt
685 printf "" > "$LIST"
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"
694 continue
696 TSTAMP=$(get_file_timestamp "$DIR")
697 printf "%s %s\n" "$TSTAMP" "$SUBDIR" >> "$LIST"
699 done
700 SUBDIR=$(cat $LIST | sort -r | head -1 | cut -d" " -f2)
701 rm -f "$LIST"
703 if [ -z "$SUBDIR" ]; then
704 if [ -z "$1" ]; then
705 panic "Could not find any build directory under \
706 $CHROMIUM_SRC/out. Please build the program first!"
707 else
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}
734 HOST_FINGERPRINT=
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
748 log "Perfect match!"
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 \
753 fingerprints match."
754 NO_PULL_LIBS=true
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)"
765 PULL_LIBS=true
766 else
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)"
771 NO_PULL_LIBS=true
772 else
773 log "Auto-config: --pull-libs (fingerprint mismatch)"
774 PULL_LIBS=true
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.
789 GDB_ARGS=
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
795 # browser process.
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?"
812 else
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
834 exit 1
836 COMMAND_PREFIX=$SU_PREFIX
837 else
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"
843 else
844 COMMAND_PREFIX=
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)
856 if [ $? != 0 ]; then
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?"
860 else
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 !?"
872 done
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
885 # properly.
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!"
893 PORT=5039
894 HOST_PORT=$PORT
895 TARGET_PORT=$PORT
897 # Pull the app_process binary from the device
898 GDBEXEC=app_process
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 \
919 --attach $PID"
920 ("$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER :$TARGET_PORT \
921 --attach $PID > $GDBSERVER_LOG 2>&1) &
922 GDBSERVER_PID=$!
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
928 sleep 2
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):"
934 cat $GDBSERVER_LOG
935 exit 1
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" \
946 >> $COMMANDS
947 echo "echo Attaching and reading symbols, this may take a while.." \
948 >> $COMMANDS
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"
957 cat $COMMANDS
958 echo "### END $COMMANDS"
961 log "Launching gdb client: $GDB $GDBARGS -x $COMMANDS"
962 $GDB $GDBARGS -x $COMMANDS &&
963 rm -f "$GDBSERVER_PIDFILE"