blob: 23462bed8b2b5a991aa40f6bfbb737fcef948267 [file] [log] [blame]
David 'Digit' Turnera08d6052010-04-16 12:45:33 -07001#!/bin/sh
2#
3# Copyright (C) 2010 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17
18# This wrapper script is used to launch a native debugging session
19# on a given NDK application. The application must be debuggable, i.e.
20# its android:debuggable attribute must be set to 'true' in the
21# <application> element of its manifest.
22#
23# See docs/NDK-GDB.TXT for usage description. Essentially, you just
24# need to launch ndk-gdb from your application project directory
25# after doing ndk-build && ant install && <start-application-on-device>
26#
27. `dirname $0`/build/core/ndk-common.sh
28
29force_32bit_binaries
30
31find_program ADB_CMD adb
32ADB_FLAGS=
33
34AWK_CMD=awk
35
36DEBUG_PORT=5039
37
38PARAMETERS=
39OPTION_HELP=no
40OPTION_PROJECT=
41OPTION_FORCE=no
42OPTION_ADB=
43OPTION_EXEC=
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -070044OPTION_START=no
45OPTION_LAUNCH=
46OPTION_LAUNCH_LIST=no
David 'Digit' Turnera08d6052010-04-16 12:45:33 -070047
48check_parameter ()
49{
50 if [ -z "$2" ]; then
51 echo "ERROR: Missing parameter after option '$1'"
52 exit 1
53 fi
54}
55
56check_adb_flags ()
57{
58 if [ -n "$ADB_FLAGS" ] ; then
59 echo "ERROR: Only one of -e, -d or -s <serial> can be used at the same time!"
60 exit 1
61 fi
62}
63
64get_build_var ()
65{
66 if [ -z "$GNUMAKE" ] ; then
67 GNUMAKE=make
68 fi
69 $GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1
70}
71
72get_build_var_for_abi ()
73{
74 if [ -z "$GNUMAKE" ] ; then
75 GNUMAKE=make
76 fi
77 $GNUMAKE --no-print-dir -f $ANDROID_NDK_ROOT/build/core/build-local.mk -C $PROJECT DUMP_$1 APP_ABI=$2
78}
79
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -070080# Used to run an awk script on the manifest
81run_awk_manifest_script ()
82{
83 $AWK_CMD -f $AWK_SCRIPTS/$1 $PROJECT/$MANIFEST
84}
85
David 'Digit' Turnera08d6052010-04-16 12:45:33 -070086VERBOSE=no
87while [ -n "$1" ]; do
88 opt="$1"
89 optarg=`expr "x$opt" : 'x[^=]*=\(.*\)'`
90 case "$opt" in
91 --help|-h|-\?)
92 OPTION_HELP=yes
93 ;;
94 --verbose)
95 VERBOSE=yes
96 ;;
97 -s)
98 check_parameter $1 $2
99 check_adb_flags
100 ADB_FLAGS=" -s $2"
101 shift
102 ;;
103 -s*)
104 check_adb_flags
105 optarg=`expr -- "$opt" : '-s\(.*\)'`
106 ADB_FLAGS=" -s $optarg"
107 ;;
108 -p)
109 check_parameter $1 $2
110 OPTION_PROJECT="$2"
111 shift
112 ;;
113 -p*)
114 optarg=`expr -- "$opt" : '-p\(.*\)'`
115 OPTION_PROJECT="$optarg"
116 ;;
117 --exec=*)
118 OPTION_EXEC="$optarg"
119 ;;
120 -x)
121 check_parameter $1 $2
122 OPTION_EXEC="$2"
123 shift
124 ;;
125 -x*)
126 optarg=`expr -- "$opt" : '-x\(.*\)'`
127 OPTION_EXEC="$optarg"
128 ;;
129 -e)
130 check_adb_flags
131 ADB_FLAGS=" -e"
132 ;;
133 -d)
134 check_adb_flags
135 ADB_FLAGS=" -d"
136 ;;
137 --adb=*) # specify ADB command
138 OPTION_ADB="$optarg"
139 ;;
140 --awk=*)
141 AWK_CMD="$optarg"
142 ;;
143 --project=*)
144 OPTION_PROJECT="$optarg"
145 ;;
146 --port=*)
147 DEBUG_PORT="$optarg"
148 ;;
149 --force)
150 OPTION_FORCE="yes"
151 ;;
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700152 --launch-list)
153 OPTION_LAUNCH_LIST="yes"
154 ;;
155 --launch=*)
156 OPTION_LAUNCH="$optarg"
157 ;;
158 --start)
159 OPTION_START=yes
160 ;;
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700161 -*) # unknown options
162 echo "ERROR: Unknown option '$opt', use --help for list of valid ones."
163 exit 1
164 ;;
165 *) # Simply record parameter
166 if [ -z "$PARAMETERS" ] ; then
167 PARAMETERS="$opt"
168 else
169 PARAMETERS="$PARAMETERS $opt"
170 fi
171 ;;
172 esac
173 shift
174done
175
176if [ "$OPTION_HELP" = "yes" ] ; then
177 echo "Usage: $PROGNAME [options]"
178 echo ""
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700179 echo "Setup a gdb debugging session for your Android NDK application."
180 echo "Read $$NDK/docs/NDK-GDB.TXT for complete usage instructions."
181 echo ""
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700182 echo "Valid options:"
183 echo ""
184 echo " --help|-h|-? Print this help"
185 echo " --verbose Enable verbose mode"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700186 echo " --force Kill existing debug session if it exists"
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700187 echo " --start Launch application instead of attaching to existing one"
188 echo " --launch=<name> Same as --start, but specify activity name (see below)"
189 echo " --launch-list List all launchable activity names from manifest"
190 echo " --project=<path> Specify application project path"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700191 echo " -p <path> Same as --project=<path>"
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700192 echo " --port=<port> Use tcp:localhost:<port> to communicate with gdbserver [$DEBUG_PORT]"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700193 echo " --exec=<file> Execute gdb initialization commands in <file> after connection"
194 echo " -x <file> Same as --exec=<file>"
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700195 echo " --adb=<file> Use specific adb command [$ADB_CMD]"
196 echo " --awk=<file> Use specific awk command [$AWK_CMD]"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700197 echo " -e Connect to single emulator instance"
198 echo " -d Connect to single target device"
199 echo " -s <serial> Connect to specific emulator or device"
200 echo ""
201 exit 0
202fi
203
204log "Android NDK installation path: $ANDROID_NDK_ROOT"
205
206if [ -n "$OPTION_EXEC" ] ; then
207 if [ ! -f "$OPTION_EXEC" ]; then
208 echo "ERROR: Invalid initialization file: $OPTION_EXEC"
209 exit 1
210 fi
211fi
212
213# Check ADB tool version
214if [ -n "$OPTION_ADB" ] ; then
215 ADB_CMD="$OPTION_ADB"
216 log "Using specific adb command: $ADB_CMD"
217else
218 if [ -z "$ADB_CMD" ] ; then
219 echo "ERROR: The 'adb' tool is not in your path."
220 echo " You can change your PATH variable, or use"
221 echo " --adb=<executable> to point to a valid one."
222 exit 1
223 fi
224 log "Using default adb command: $ADB_CMD"
225fi
226
227ADB_VERSION=`$ADB_CMD version`
228if [ $? != 0 ] ; then
229 echo "ERROR: Could not run ADB with: $ADB_CMD"
230 exit 1
231fi
232log "ADB version found: $ADB_VERSION"
233
234ADB_CMD="${ADB_CMD}${ADB_FLAGS}"
235log "Using final ADB command: '$ADB_CMD'"
236
237
238# Check the awk tool
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700239AWK_SCRIPTS=$ANDROID_NDK_ROOT/build/awk
240AWK_TEST=`$AWK_CMD -f $AWK_SCRIPTS/check-awk.awk`
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700241if [ $? != 0 ] ; then
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700242 echo "ERROR: Could not run '$AWK_CMD' command. Do you have it installed properly?"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700243 exit 1
244fi
245if [ "$AWK_TEST" != "Pass" ] ; then
246 echo "ERROR: Your version of 'awk' is obsolete. Please use --awk=<file> to point to Nawk or Gawk!"
247 exit 1
248fi
249
250# Name of the manifest file
251MANIFEST=AndroidManifest.xml
252
253# Find the root of the application project.
254if [ -n "$OPTION_PROJECT" ] ; then
255 PROJECT=$OPTION_PROJECT
256 log "Using specified project path: $PROJECT"
257 if [ ! -d "$PROJECT" ] ; then
258 echo "ERROR: Your --project option does not point to a directory!"
259 exit 1
260 fi
261 if [ ! -f "$PROJECT/$MANIFEST" ] ; then
262 echo "ERROR: Your --project does not point to an Android project path!"
263 echo " It is missing a $MANIFEST file."
264 exit 1
265 fi
266else
267 # Assume we are in the project directory
268 if [ -f "$MANIFEST" ] ; then
269 PROJECT=.
270 else
271 PROJECT=
272 CURDIR=`pwd`
273 while [ "$CURDIR" != "/" ] ; do
274 if [ -f "$CURDIR/$MANIFEST" ] ; then
275 PROJECT="$CURDIR"
276 break
277 fi
278 CURDIR=`dirname $CURDIR`
279 done
280 if [ -z "$PROJECT" ] ; then
281 echo "ERROR: Launch this script from an application project directory, or use --project=<path>."
282 exit 1
283 fi
284 fi
285 log "Using auto-detected project path: $PROJECT"
286fi
287
288# Extract the package name from the manifest
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700289PACKAGE_NAME=`run_awk_manifest_script extract-package-name.awk`
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700290log "Found package name: $PACKAGE_NAME"
291if [ $? != 0 -o "$PACKAGE_NAME" = "<none>" ] ; then
292 echo "ERROR: Could not extract package name from $PROJECT/$MANIFEST."
293 echo " Please check that the file is well-formed!"
294 exit 1
295fi
296
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700297# If --launch-list is used, list all launchable activities, and be done with it
298if [ "$OPTION_LAUNCH_LIST" = "yes" ] ; then
299 log "Extracting list of launchable activities from manifest:"
300 run_awk_manifest_script extract-launchable.awk
301 exit 0
302fi
303
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700304# Check that the application is debuggable, or nothing will work
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700305DEBUGGABLE=`run_awk_manifest_script extract-debuggable.awk`
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700306log "Found debuggable flag: $DEBUGGABLE"
307if [ $? != 0 -o "$DEBUGGABLE" != "true" ] ; then
308 echo "ERROR: Package $PACKAGE_NAME is not debuggable ! Please fix your manifest,"
309 echo " rebuild your application and re-install it to fix this."
310 exit 1
311fi
312
313APP_ABIS=`get_build_var APP_ABI`
314log "ABIs targetted by application: $APP_ABIS"
315
316# Check the ADB command, and that we can connect to the device/emulator
317ADB_TEST=`$ADB_CMD shell ls`
318if [ $? != 0 ] ; then
319 echo "ERROR: Could not connect to device or emulator!"
320 echo " Please check that an emulator is running or a device is connected"
321 echo " through USB to this machine. You can use the -e, -d and -s <serial>"
322 echo " in case of multiple ones."
323 exit 1
324fi
325
326# Get the target device's supported ABI(s)
327# And check that they are supported by the application
328#
329COMPAT_ABI=none
330CPU_ABI=`$ADB_CMD shell getprop ro.product.cpu.abi | sed -e 's!\\r!!g'`
331echo "$APP_ABIS" | grep -q -F "$CPU_ABI"
332if [ $? = 0 ] ; then
333 COMPAT_ABI=$CPU_ABI
334fi
335
336CPU_ABI2=`$ADB_CMD shell getprop ro.product.cpu.abi2 | sed -e 's!\\r!!g'`
337if [ -z "$CPU_ABI2" ] ; then
338 log "Device CPU ABI: $CPU_ABI"
339else
340 log "Device CPU ABIs: $CPU_ABI $CPU_ABI2"
341 echo "$APP_ABIS" | grep -q -F "$CPU_ABI2"
342 if [ $? = 0 ] ; then
343 COMPAT_ABI=$CPU_ABI2
344 fi
345fi
346if [ "$COMPAT_ABI" = none ] ; then
347 echo "ERROR: The device does not support the application's targetted CPU ABIs!"
348 if [ "$CPU_ABI2" = "$CPU_ABI" ] ; then
349 CPU_ABI2=
350 fi
351 echo " Device supports: $CPU_ABI $CPU_ABI2"
352 echo " Package supports: $APP_ABIS"
353 exit 1
354fi
355log "Compatible device ABI: $COMPAT_ABI"
356
357# Get information from the build system
358GDBSETUP_INIT=`get_build_var_for_abi NDK_APP_GDBSETUP $COMPAT_ABI`
359log "Using gdb setup init: $GDBSETUP_INIT"
360
361TOOLCHAIN_PREFIX=`get_build_var_for_abi TOOLCHAIN_PREFIX $COMPAT_ABI`
362log "Using toolchain prefix: $TOOLCHAIN_PREFIX"
363
364APP_OUT=`get_build_var_for_abi TARGET_OUT $COMPAT_ABI`
365log "Using app out directory: $APP_OUT"
366
367# Find the <dataDir> of the package on the device
368DATA_DIR=`$ADB_CMD shell run-as $PACKAGE_NAME /system/bin/sh -c pwd`
369# mmm, a rogue \r at the end, get rid of it.
370DATA_DIR=`echo "$DATA_DIR" | sed -e 's!\\r!!g'`
371log "Found data directory: '$DATA_DIR'"
372if [ $? != 0 ] ; then
373 echo "ERROR: Could not extract package's data directory. Are you sure that"
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700374 echo " your installed application is debuggable?"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700375 exit 1
376fi
377
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700378# Launch the activity if needed
379if [ -n "$OPTION_START" ] ; then
380 # If --launch is used, ignore --start, otherwise extract the first
381 # launchable activity name from the manifest and use it as if --launch=<name>
382 # was used instead.
383 #
384 if [ -z "$OPTION_LAUNCH" ] ; then
385 OPTION_LAUNCH=`run_awk_manifest_script extract-launchable.awk | sed 2q`
386 if [ $? != 0 ] ; then
387 echo "ERROR: Could not extract name of launchable activity from manifest!"
388 echo " Try to use --launch=<name> directly instead as a work-around."
389 exit 1
390 fi
391 log "Found first launchable activity: $OPTION_LAUNCH"
392 if [ -z "$OPTION_LAUNCH" ] ; then
393 echo "ERROR: It seems that your Application does not have any launchable activity!"
394 echo " Please fix your manifest file and rebuild/re-install your application."
395 exit 1
396 fi
397 fi
398fi
399
400if [ -n "$OPTION_LAUNCH" ] ; then
401 log "Launching activity: $PACKAGE_NAME/$OPTION_LAUNCH"
402 run $ADB_CMD shell am start -n $PACKAGE_NAME/$OPTION_LAUNCH
403 if [ $? != 0 ] ; then
404 echo "ERROR: Could not launch specified activity: $OPTION_LAUNCH"
405 echo " Use --launch-list to dump a list of valid values."
406 exit 1
407 fi
408 # Sleep a bit, it sometimes take one second to start properly
409 # Note that we use the 'sleep' command on the device here.
410 run $ADB_CMD shell sleep 1
411fi
412
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700413# Find the PID of the application being run
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700414PID=`$ADB_CMD shell ps | $AWK_CMD -f $AWK_SCRIPTS/extract-pid.awk -v PACKAGE=$PACKAGE_NAME`
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700415log "Found running PID: $PID"
416if [ $? != 0 -o "$PID" = "0" ] ; then
417 echo "ERROR: Could not extract PID of application on device/emulator."
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700418 if [ -n "$OPTION_LAUNCH" ] ; then
419 echo " Weird, this probably means that the installed package does not"
420 echo " match your current manifest. Try using the --verbose option and"
421 echo " look at its output for details."
422 else
423 echo " Are you sure the application is already started?"
424 echo " Consider using --start or --launch=<name> if not."
425 fi
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700426 exit 1
427fi
428
429# Check that there is no other instance of gdbserver running
430GDBSERVER_PS=`$ADB_CMD shell ps | grep lib/gdbserver`
431if [ -n "$GDBSERVER_PS" ] ; then
432 if [ "$OPTION_FORCE" = "no" ] ; then
433 echo "ERROR: Another debug session running, Use --force to kill it."
434 exit 1
435 fi
436 log "Killing existing debugging session"
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700437 GDBSERVER_PID=`echo $GDBSERVER_PS | $AWK_CMD -f $AWK_SCRIPTS/extract-pid.awk -v PACKAGE=lib/gdbserver`
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700438 if [ $GDBSERVER_PID != 0 ] ; then
439 run $ADB_CMD shell kill -9 $GDBSERVER_PID
440 fi
441fi
442
443# Launch gdbserver now
444DEBUG_SOCKET=debug-socket
445run $ADB_CMD shell run-as $PACKAGE_NAME lib/gdbserver +$DEBUG_SOCKET --attach $PID &
446if [ $? != 0 ] ; then
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700447 echo "ERROR: Could not launch gdbserver on the device?"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700448 exit 1
449fi
450log "Launched gdbserver succesfully."
451
452# Setup network redirection
453log "Setup network redirection"
454run $ADB_CMD forward tcp:$DEBUG_PORT localfilesystem:$DATA_DIR/$DEBUG_SOCKET
455if [ $? != 0 ] ; then
David 'Digit' Turner0b2676b2010-04-27 12:33:46 -0700456 echo "ERROR: Could not setup network redirection to gdbserver?"
457 echo " Maybe using --port=<port> to use a different TCP port might help?"
David 'Digit' Turnera08d6052010-04-16 12:45:33 -0700458 exit 1
459fi
460
461# Get the app_server binary from the device
462APP_PROCESS=$APP_OUT/app_process
463run adb pull /system/bin/app_process $APP_PROCESS
464log "Pulled $APP_BINARY from device/emulator."
465
466# Now launch the appropriate gdb client with the right init commands
467#
468GDBCLIENT=${TOOLCHAIN_PREFIX}gdb
469GDBSETUP=$APP_OUT/gdb.setup
470cp -f $GDBSETUP_INIT $GDBSETUP
471echo "target remote :$DEBUG_PORT" >> $GDBSETUP
472if [ -n "$OPTION_EXEC" ] ; then
473 cat $OPTION_EXEC >> $GDBSETUP
474fi
475$GDBCLIENT -x $GDBSETUP -e $APP_PROCESS