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