Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(240)

Side by Side Diff: build/android/adb_gdb

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

Powered by Google App Engine
This is Rietveld 408576698