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