[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # |
Avi Drissman | 73a09d1 | 2022-09-08 20:33:38 | [diff] [blame] | 3 | # Copyright 2012 The Chromium Authors |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 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] | 732d7e6 | 2013-09-03 20:15:58 | [diff] [blame] | 10 | # wrapper scripts like adb_gdb_content_shell |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 11 | # |
| 12 | # Use --help to print full usage instructions. |
| 13 | # |
| 14 | |
| 15 | PROGNAME=$(basename "$0") |
| 16 | PROGDIR=$(dirname "$0") |
| 17 | |
liushouqun | 353749a2 | 2015-12-25 15:15:20 | [diff] [blame] | 18 | # Force locale to C to allow recognizing output from subprocesses. |
| 19 | LC_ALL=C |
| 20 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 21 | # Location of Chromium-top-level sources. |
[email protected] | 222d547 | 2014-05-24 02:34:38 | [diff] [blame] | 22 | CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null) |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 23 | |
| 24 | TMPDIR= |
| 25 | GDBSERVER_PIDFILE= |
| 26 | TARGET_GDBSERVER= |
jimmym | bb4db81 | 2015-02-04 16:03:00 | [diff] [blame] | 27 | COMMAND_PREFIX= |
cathiechen | 899f5b3 | 2016-08-31 13:49:56 | [diff] [blame] | 28 | COMMAND_SUFFIX= |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 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 |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 36 | rm -f "$GDBSERVER_PIDFILE" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 37 | fi |
| 38 | if [ "$TARGET_GDBSERVER" ]; then |
| 39 | log "Removing target gdbserver binary: $TARGET_GDBSERVER." |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 40 | "$ADB" shell "$COMMAND_PREFIX" rm "$TARGET_GDBSERVER" \ |
| 41 | "$TARGET_DOMAIN_SOCKET" "$COMMAND_SUFFIX" >/dev/null 2>&1 |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 42 | fi |
| 43 | log "Cleaning up: $TMPDIR" |
| 44 | rm -rf "$TMPDIR" |
| 45 | fi |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 46 | trap "" EXIT |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 47 | exit $1 |
| 48 | } |
| 49 | |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 50 | # Ensure clean exit on Ctrl-C or normal exit. |
| 51 | trap "clean_exit 1" INT HUP QUIT TERM |
| 52 | trap "clean_exit \$?" EXIT |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 53 | |
| 54 | panic () { |
| 55 | echo "ERROR: $@" >&2 |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 56 | exit 1 |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 57 | } |
| 58 | |
| 59 | fail_panic () { |
| 60 | if [ $? != 0 ]; then panic "$@"; fi |
| 61 | } |
| 62 | |
| 63 | log () { |
| 64 | if [ "$VERBOSE" -gt 0 ]; then |
| 65 | echo "$@" |
| 66 | fi |
| 67 | } |
| 68 | |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 69 | DEFAULT_PULL_LIBS_DIR="/tmp/adb-gdb-support-$USER" |
| 70 | IDE_DIR="$DEFAULT_PULL_LIBS_DIR" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 71 | |
| 72 | # NOTE: Allow wrapper scripts to set various default through ADB_GDB_XXX |
| 73 | # environment variables. This is only for cosmetic reasons, i.e. to |
| 74 | # display proper |
| 75 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 76 | # Allow wrapper scripts to set the program name through ADB_GDB_PROGNAME |
| 77 | PROGNAME=${ADB_GDB_PROGNAME:-$(basename "$0")} |
| 78 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 79 | ADB= |
| 80 | ANNOTATE= |
sakal | a4dfc338 | 2017-06-19 15:03:44 | [diff] [blame] | 81 | CGDB= |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 82 | GDBINIT= |
| 83 | GDBSERVER= |
| 84 | HELP= |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 85 | IDE= |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 86 | NDK_DIR= |
| 87 | NO_PULL_LIBS= |
| 88 | PACKAGE_NAME= |
| 89 | PID= |
lfg | a1639ebf | 2015-05-08 16:24:54 | [diff] [blame] | 90 | PORT= |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 91 | PROGRAM_NAME="activity" |
| 92 | PULL_LIBS= |
| 93 | PULL_LIBS_DIR= |
watk | ae429d0 | 2016-02-01 20:19:39 | [diff] [blame] | 94 | ATTACH_DELAY=1 |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 95 | SU_PREFIX= |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 96 | SYMBOL_DIR= |
| 97 | TARGET_ARCH= |
| 98 | TOOLCHAIN= |
| 99 | VERBOSE=0 |
| 100 | |
| 101 | for opt; do |
| 102 | optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') |
| 103 | case $opt in |
| 104 | --adb=*) |
| 105 | ADB=$optarg |
| 106 | ;; |
agrieve | cd4e139 | 2016-03-18 18:56:06 | [diff] [blame] | 107 | --device=*) |
| 108 | export ANDROID_SERIAL=$optarg |
| 109 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 110 | --annotate=3) |
| 111 | ANNOTATE=$optarg |
| 112 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 113 | --gdbserver=*) |
| 114 | GDBSERVER=$optarg |
| 115 | ;; |
[email protected] | fca5dd8 | 2013-10-02 18:56:35 | [diff] [blame] | 116 | --gdb=*) |
| 117 | GDB=$optarg |
| 118 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 119 | --help|-h|-?) |
| 120 | HELP=true |
| 121 | ;; |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 122 | --ide) |
| 123 | IDE=true |
| 124 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 125 | --ndk-dir=*) |
| 126 | NDK_DIR=$optarg |
| 127 | ;; |
| 128 | --no-pull-libs) |
| 129 | NO_PULL_LIBS=true |
| 130 | ;; |
| 131 | --package-name=*) |
| 132 | PACKAGE_NAME=$optarg |
| 133 | ;; |
| 134 | --pid=*) |
| 135 | PID=$optarg |
| 136 | ;; |
lfg | a1639ebf | 2015-05-08 16:24:54 | [diff] [blame] | 137 | --port=*) |
| 138 | PORT=$optarg |
| 139 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 140 | --program-name=*) |
| 141 | PROGRAM_NAME=$optarg |
| 142 | ;; |
| 143 | --pull-libs) |
| 144 | PULL_LIBS=true |
| 145 | ;; |
| 146 | --pull-libs-dir=*) |
| 147 | PULL_LIBS_DIR=$optarg |
| 148 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 149 | --script=*) |
| 150 | GDBINIT=$optarg |
| 151 | ;; |
watk | ae429d0 | 2016-02-01 20:19:39 | [diff] [blame] | 152 | --attach-delay=*) |
| 153 | ATTACH_DELAY=$optarg |
| 154 | ;; |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 155 | --su-prefix=*) |
| 156 | SU_PREFIX=$optarg |
| 157 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 158 | --symbol-dir=*) |
| 159 | SYMBOL_DIR=$optarg |
| 160 | ;; |
agrieve | 1b3c3263 | 2016-02-04 19:16:55 | [diff] [blame] | 161 | --output-directory=*) |
agrieve | 0f29ea46 | 2016-01-08 02:50:20 | [diff] [blame] | 162 | CHROMIUM_OUTPUT_DIR=$optarg |
| 163 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 164 | --target-arch=*) |
| 165 | TARGET_ARCH=$optarg |
| 166 | ;; |
| 167 | --toolchain=*) |
| 168 | TOOLCHAIN=$optarg |
| 169 | ;; |
sakal | a4dfc338 | 2017-06-19 15:03:44 | [diff] [blame] | 170 | --cgdb) |
| 171 | CGDB=cgdb |
| 172 | ;; |
| 173 | --cgdb=*) |
| 174 | CGDB=$optarg |
| 175 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 176 | --verbose) |
| 177 | VERBOSE=$(( $VERBOSE + 1 )) |
| 178 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 179 | -*) |
watk | ae429d0 | 2016-02-01 20:19:39 | [diff] [blame] | 180 | panic "Unknown option $opt, see --help." >&2 |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 181 | ;; |
| 182 | *) |
| 183 | if [ "$PACKAGE_NAME" ]; then |
| 184 | panic "You can only provide a single package name as argument!\ |
| 185 | See --help." |
| 186 | fi |
| 187 | PACKAGE_NAME=$opt |
| 188 | ;; |
| 189 | esac |
| 190 | done |
| 191 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 192 | if [ "$HELP" ]; then |
| 193 | if [ "$ADB_GDB_PROGNAME" ]; then |
| 194 | # Assume wrapper scripts all provide a default package name. |
| 195 | cat <<EOF |
| 196 | Usage: $PROGNAME [options] |
| 197 | |
| 198 | Attach gdb to a running Android $PROGRAM_NAME process. |
| 199 | EOF |
| 200 | else |
| 201 | # Assume this is a direct call to adb_gdb |
| 202 | cat <<EOF |
| 203 | Usage: $PROGNAME [options] [<package-name>] |
| 204 | |
| 205 | Attach gdb to a running Android $PROGRAM_NAME process. |
| 206 | |
| 207 | If provided, <package-name> must be the name of the Android application's |
| 208 | package name to be debugged. You can also use --package-name=<name> to |
| 209 | specify it. |
| 210 | EOF |
| 211 | fi |
| 212 | |
| 213 | cat <<EOF |
| 214 | |
| 215 | This script is used to debug a running $PROGRAM_NAME process. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 216 | |
| 217 | This script needs several things to work properly. It will try to pick |
| 218 | them up automatically for you though: |
| 219 | |
| 220 | - target gdbserver binary |
| 221 | - host gdb client (e.g. arm-linux-androideabi-gdb) |
| 222 | - directory with symbolic version of $PROGRAM_NAME's shared libraries. |
| 223 | |
[email protected] | 725926d | 2014-04-03 16:13:37 | [diff] [blame] | 224 | You can also use --ndk-dir=<path> to specify an alternative NDK installation |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 225 | directory. |
| 226 | |
| 227 | The script tries to find the most recent version of the debug version of |
| 228 | shared libraries under one of the following directories: |
| 229 | |
agrieve | 0f29ea46 | 2016-01-08 02:50:20 | [diff] [blame] | 230 | \$CHROMIUM_SRC/<out>/lib/ (used by GYP builds) |
| 231 | \$CHROMIUM_SRC/<out>/lib.unstripped/ (used by GN builds) |
[email protected] | 2b7a0e9e | 2013-11-27 14:34:36 | [diff] [blame] | 232 | |
agrieve | 2ac20d3 | 2016-02-12 19:55:51 | [diff] [blame] | 233 | Where <out> is determined by CHROMIUM_OUTPUT_DIR, or --output-directory. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 234 | |
agrieve | 2ac20d3 | 2016-02-12 19:55:51 | [diff] [blame] | 235 | You can set the path manually via --symbol-dir. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 236 | |
halton.huo | 2d15907 | 2015-01-13 08:07:06 | [diff] [blame] | 237 | The script tries to extract the target architecture from your target device, |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 238 | but if this fails, will default to 'arm'. Use --target-arch=<name> to force |
| 239 | its value. |
| 240 | |
| 241 | Otherwise, the script will complain, but you can use the --gdbserver, |
| 242 | --gdb and --symbol-lib options to specify everything manually. |
| 243 | |
| 244 | An alternative to --gdb=<file> is to use --toollchain=<path> to specify |
| 245 | the path to the host target-specific cross-toolchain. |
| 246 | |
| 247 | You will also need the 'adb' tool in your path. Otherwise, use the --adb |
| 248 | option. The script will complain if there is more than one device connected |
agrieve | cd4e139 | 2016-03-18 18:56:06 | [diff] [blame] | 249 | and a device is not specified with either --device or ANDROID_SERIAL). |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 250 | |
| 251 | The first time you use it on a device, the script will pull many system |
| 252 | libraries required by the process into a temporary directory. This |
| 253 | is done to strongly improve the debugging experience, like allowing |
| 254 | readable thread stacks and more. The libraries are copied to the following |
| 255 | directory by default: |
| 256 | |
| 257 | $DEFAULT_PULL_LIBS_DIR/ |
| 258 | |
| 259 | But you can use the --pull-libs-dir=<path> option to specify an |
| 260 | alternative. The script can detect when you change the connected device, |
| 261 | and will re-pull the libraries only in this case. You can however force it |
| 262 | with the --pull-libs option. |
| 263 | |
| 264 | Any local .gdbinit script will be ignored, but it is possible to pass a |
| 265 | gdb command script with the --script=<file> option. Note that its commands |
| 266 | will be passed to gdb after the remote connection and library symbol |
| 267 | loading have completed. |
| 268 | |
| 269 | Valid options: |
| 270 | --help|-h|-? Print this message. |
| 271 | --verbose Increase verbosity. |
| 272 | |
sakal | a4dfc338 | 2017-06-19 15:03:44 | [diff] [blame] | 273 | --cgdb[=<file>] Use cgdb (an interface for gdb that shows the code). |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 274 | --symbol-dir=<path> Specify directory with symbol shared libraries. |
agrieve | 1b3c3263 | 2016-02-04 19:16:55 | [diff] [blame] | 275 | --output-directory=<path> Specify the output directory (e.g. "out/Debug"). |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 276 | --package-name=<name> Specify package name (alternative to 1st argument). |
| 277 | --program-name=<name> Specify program name (cosmetic only). |
| 278 | --pid=<pid> Specify application process pid. |
watk | ae429d0 | 2016-02-01 20:19:39 | [diff] [blame] | 279 | --attach-delay=<num> Seconds to wait for gdbserver to attach to the |
| 280 | remote process before starting gdb. Default 1. |
| 281 | <num> may be a float if your sleep(1) supports it. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 282 | --annotate=<num> Enable gdb annotation. |
| 283 | --script=<file> Specify extra GDB init script. |
| 284 | |
[email protected] | fca5dd8 | 2013-10-02 18:56:35 | [diff] [blame] | 285 | --gdbserver=<file> Specify target gdbserver binary. |
| 286 | --gdb=<file> Specify host gdb client binary. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 287 | --target-arch=<name> Specify NDK target arch. |
[email protected] | fca5dd8 | 2013-10-02 18:56:35 | [diff] [blame] | 288 | --adb=<file> Specify host ADB binary. |
agrieve | cd4e139 | 2016-03-18 18:56:06 | [diff] [blame] | 289 | --device=<file> ADB device serial to use (-s flag). |
lfg | a1639ebf | 2015-05-08 16:24:54 | [diff] [blame] | 290 | --port=<port> Specify the tcp port to use. |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 291 | --ide Forward gdb port, but do not enter gdb console. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 292 | |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 293 | --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are |
| 294 | run by this script. This can be useful to use |
| 295 | the 'su' program on rooted production devices. |
[email protected] | 9222e6b | 2014-06-06 20:17:53 | [diff] [blame] | 296 | e.g. --su-prefix="su -c" |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 297 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 298 | --pull-libs Force system libraries extraction. |
| 299 | --no-pull-libs Do not extract any system library. |
| 300 | --libs-dir=<path> Specify system libraries extraction directory. |
| 301 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 302 | EOF |
| 303 | exit 0 |
| 304 | fi |
| 305 | |
| 306 | if [ -z "$PACKAGE_NAME" ]; then |
| 307 | panic "Please specify a package name on the command line. See --help." |
| 308 | fi |
| 309 | |
agrieve | 2e65b753 | 2016-03-21 17:36:13 | [diff] [blame] | 310 | if [[ -z "$SYMBOL_DIR" && -z "$CHROMIUM_OUTPUT_DIR" ]]; then |
agrieve | 1b3c3263 | 2016-02-04 19:16:55 | [diff] [blame] | 311 | if [[ -e "build.ninja" ]]; then |
| 312 | CHROMIUM_OUTPUT_DIR=$PWD |
| 313 | else |
| 314 | panic "Please specify an output directory by using one of: |
| 315 | --output-directory=out/Debug |
agrieve | 1b3c3263 | 2016-02-04 19:16:55 | [diff] [blame] | 316 | CHROMIUM_OUTPUT_DIR=out/Debug |
agrieve | 1b3c3263 | 2016-02-04 19:16:55 | [diff] [blame] | 317 | Setting working directory to an output directory. |
| 318 | See --help." |
| 319 | fi |
| 320 | fi |
| 321 | |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 322 | if ls *.so >/dev/null 2>&1; then |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 323 | panic ".so files found in your working directory. These will conflict with" \ |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 324 | "library lookup logic. Change your working directory and try again." |
| 325 | fi |
| 326 | |
agrieve | 2e65b753 | 2016-03-21 17:36:13 | [diff] [blame] | 327 | # Detect the build type and symbol directory. This is done by finding |
| 328 | # the most recent sub-directory containing debug shared libraries under |
| 329 | # $CHROMIUM_OUTPUT_DIR. |
| 330 | # |
| 331 | # Out: nothing, but this sets SYMBOL_DIR |
| 332 | # |
| 333 | detect_symbol_dir () { |
| 334 | # GYP places unstripped libraries under out/lib |
| 335 | # GN places them under out/lib.unstripped |
| 336 | local PARENT_DIR="$CHROMIUM_OUTPUT_DIR" |
| 337 | if [[ ! -e "$PARENT_DIR" ]]; then |
| 338 | PARENT_DIR="$CHROMIUM_SRC/$PARENT_DIR" |
| 339 | fi |
| 340 | SYMBOL_DIR="$PARENT_DIR/lib.unstripped" |
| 341 | if [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then |
| 342 | SYMBOL_DIR="$PARENT_DIR/lib" |
| 343 | if [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then |
| 344 | panic "Could not find any symbols under \ |
| 345 | $PARENT_DIR/lib{.unstripped}. Please build the program first!" |
| 346 | fi |
| 347 | fi |
| 348 | log "Auto-config: --symbol-dir=$SYMBOL_DIR" |
| 349 | } |
| 350 | |
| 351 | if [ -z "$SYMBOL_DIR" ]; then |
| 352 | detect_symbol_dir |
| 353 | elif [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then |
| 354 | panic "Could not find any symbols under $SYMBOL_DIR" |
| 355 | fi |
| 356 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 357 | if [ -z "$NDK_DIR" ]; then |
Javier Castro | 099977b | 2022-08-29 21:53:25 | [diff] [blame] | 358 | ANDROID_NDK_ROOT=$(PYTHONPATH=$CHROMIUM_SRC/build/android python3 -c \ |
| 359 | 'from pylib.constants import ANDROID_NDK_ROOT; print(ANDROID_NDK_ROOT,)') |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 360 | else |
| 361 | if [ ! -d "$NDK_DIR" ]; then |
| 362 | panic "Invalid directory: $NDK_DIR" |
| 363 | fi |
| 364 | if [ ! -f "$NDK_DIR/ndk-build" ]; then |
| 365 | panic "Not a valid NDK directory: $NDK_DIR" |
| 366 | fi |
| 367 | ANDROID_NDK_ROOT=$NDK_DIR |
| 368 | fi |
| 369 | |
| 370 | if [ "$GDBINIT" -a ! -f "$GDBINIT" ]; then |
| 371 | panic "Unknown --script file: $GDBINIT" |
| 372 | fi |
| 373 | |
halton.huo | 2d15907 | 2015-01-13 08:07:06 | [diff] [blame] | 374 | # Check that ADB is in our path |
| 375 | if [ -z "$ADB" ]; then |
| 376 | ADB=$(which adb 2>/dev/null) |
| 377 | if [ -z "$ADB" ]; then |
| 378 | panic "Can't find 'adb' tool in your path. Install it or use \ |
| 379 | --adb=<file>" |
| 380 | fi |
| 381 | log "Auto-config: --adb=$ADB" |
| 382 | fi |
| 383 | |
| 384 | # Check that it works minimally |
| 385 | ADB_VERSION=$($ADB version 2>/dev/null) |
| 386 | echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge" |
| 387 | if [ $? != 0 ]; then |
| 388 | panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \ |
| 389 | different one: $ADB" |
| 390 | fi |
| 391 | |
| 392 | # If there are more than one device connected, and ANDROID_SERIAL is not |
| 393 | # defined, print an error message. |
| 394 | NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l) |
agrieve | cd4e139 | 2016-03-18 18:56:06 | [diff] [blame] | 395 | if [ "$NUM_DEVICES_PLUS2" -gt 3 -a -z "$ANDROID_SERIAL" ]; then |
halton.huo | 2d15907 | 2015-01-13 08:07:06 | [diff] [blame] | 396 | echo "ERROR: There is more than one Android device connected to ADB." |
| 397 | echo "Please define ANDROID_SERIAL to specify which one to use." |
| 398 | exit 1 |
| 399 | fi |
| 400 | |
| 401 | # Run a command through adb shell, strip the extra \r from the output |
| 402 | # and return the correct status code to detect failures. This assumes |
| 403 | # that the adb shell command prints a final \n to stdout. |
| 404 | # $1+: command to run |
| 405 | # Out: command's stdout |
| 406 | # Return: command's status |
| 407 | # Note: the command's stderr is lost |
| 408 | adb_shell () { |
| 409 | local TMPOUT="$(mktemp)" |
| 410 | local LASTLINE RET |
| 411 | local ADB=${ADB:-adb} |
| 412 | |
| 413 | # The weird sed rule is to strip the final \r on each output line |
| 414 | # Since 'adb shell' never returns the command's proper exit/status code, |
| 415 | # we force it to print it as '%%<status>' in the temporary output file, |
| 416 | # which we will later strip from it. |
| 417 | $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \ |
| 418 | sed -e 's![[:cntrl:]]!!g' > $TMPOUT |
| 419 | # Get last line in log, which contains the exit code from the command |
| 420 | LASTLINE=$(sed -e '$!d' $TMPOUT) |
| 421 | # Extract the status code from the end of the line, which must |
| 422 | # be '%%<code>'. |
| 423 | RET=$(echo "$LASTLINE" | \ |
| 424 | awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }') |
| 425 | # Remove the status code from the last line. Note that this may result |
| 426 | # in an empty line. |
| 427 | LASTLINE=$(echo "$LASTLINE" | \ |
| 428 | awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }') |
| 429 | # The output itself: all lines except the status code. |
| 430 | sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE" |
| 431 | # Remove temp file. |
| 432 | rm -f $TMPOUT |
| 433 | # Exit with the appropriate status. |
| 434 | return $RET |
| 435 | } |
| 436 | |
agrieve | 2e65b753 | 2016-03-21 17:36:13 | [diff] [blame] | 437 | # Find the target architecture from a local shared library. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 438 | # This returns an NDK-compatible architecture name. |
| 439 | # out: NDK Architecture name, or empty string. |
| 440 | get_gyp_target_arch () { |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 441 | # ls prints a broken pipe error when there are a lot of libs. |
| 442 | local RANDOM_LIB=$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null| head -n1) |
agrieve | 2e65b753 | 2016-03-21 17:36:13 | [diff] [blame] | 443 | local SO_DESC=$(file $RANDOM_LIB) |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 444 | case $ARCH in |
agrieve | 2e65b753 | 2016-03-21 17:36:13 | [diff] [blame] | 445 | *32-bit*ARM,*) echo "arm";; |
| 446 | *64-bit*ARM,*) echo "arm64";; |
| 447 | *32-bit*Intel,*) echo "x86";; |
| 448 | *x86-64,*) echo "x86_64";; |
| 449 | *32-bit*MIPS,*) echo "mips";; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 450 | *) echo ""; |
| 451 | esac |
| 452 | } |
| 453 | |
| 454 | if [ -z "$TARGET_ARCH" ]; then |
| 455 | TARGET_ARCH=$(get_gyp_target_arch) |
| 456 | if [ -z "$TARGET_ARCH" ]; then |
| 457 | TARGET_ARCH=arm |
| 458 | fi |
| 459 | else |
| 460 | # Nit: accept Chromium's 'ia32' as a valid target architecture. This |
| 461 | # script prefers the NDK 'x86' name instead because it uses it to find |
| 462 | # NDK-specific files (host gdb) with it. |
| 463 | if [ "$TARGET_ARCH" = "ia32" ]; then |
| 464 | TARGET_ARCH=x86 |
| 465 | log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)" |
| 466 | fi |
| 467 | fi |
| 468 | |
[email protected] | f6e62e7 | 2013-05-16 16:19:41 | [diff] [blame] | 469 | # Detect the NDK system name, i.e. the name used to identify the host. |
| 470 | # out: NDK system name (e.g. 'linux' or 'darwin') |
| 471 | get_ndk_host_system () { |
| 472 | local HOST_OS |
| 473 | if [ -z "$NDK_HOST_SYSTEM" ]; then |
| 474 | HOST_OS=$(uname -s) |
| 475 | case $HOST_OS in |
| 476 | Linux) NDK_HOST_SYSTEM=linux;; |
| 477 | Darwin) NDK_HOST_SYSTEM=darwin;; |
| 478 | *) panic "You can't run this script on this system: $HOST_OS";; |
| 479 | esac |
| 480 | fi |
| 481 | echo "$NDK_HOST_SYSTEM" |
| 482 | } |
| 483 | |
| 484 | # Detect the NDK host architecture name. |
| 485 | # out: NDK arch name (e.g. 'x86' or 'x86_64') |
| 486 | get_ndk_host_arch () { |
| 487 | local HOST_ARCH HOST_OS |
| 488 | if [ -z "$NDK_HOST_ARCH" ]; then |
| 489 | HOST_OS=$(get_ndk_host_system) |
| 490 | HOST_ARCH=$(uname -p) |
Dmitry Skiba | e600d04 | 2018-02-12 17:02:47 | [diff] [blame] | 491 | if [ "$HOST_ARCH" = "unknown" ]; then |
| 492 | # In case where "-p" returns "unknown" just use "-m" (machine hardware |
| 493 | # name). According to this patch from Fedora "-p" is equivalent to "-m" |
| 494 | # anyway: https://goo.gl/Pd47x3 |
| 495 | HOST_ARCH=$(uname -m) |
| 496 | fi |
[email protected] | f6e62e7 | 2013-05-16 16:19:41 | [diff] [blame] | 497 | case $HOST_ARCH in |
| 498 | i?86) NDK_HOST_ARCH=x86;; |
| 499 | x86_64|amd64) NDK_HOST_ARCH=x86_64;; |
| 500 | *) panic "You can't run this script on this host architecture: $HOST_ARCH";; |
| 501 | esac |
| 502 | # Darwin trick: "uname -p" always returns i386 on 64-bit installations. |
| 503 | if [ "$HOST_OS" = darwin -a "$NDK_HOST_ARCH" = "x86" ]; then |
| 504 | # Use '/usr/bin/file', not just 'file' to avoid buggy MacPorts |
| 505 | # implementations of the tool. See http://b.android.com/53769 |
| 506 | HOST_64BITS=$(/usr/bin/file -L "$SHELL" | grep -e "x86[_-]64") |
| 507 | if [ "$HOST_64BITS" ]; then |
| 508 | NDK_HOST_ARCH=x86_64 |
| 509 | fi |
| 510 | fi |
| 511 | fi |
| 512 | echo "$NDK_HOST_ARCH" |
| 513 | } |
| 514 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 515 | # Convert an NDK architecture name into a GNU configure triplet. |
| 516 | # $1: NDK architecture name (e.g. 'arm') |
| 517 | # Out: Android GNU configure triplet (e.g. 'arm-linux-androideabi') |
| 518 | get_arch_gnu_config () { |
| 519 | case $1 in |
| 520 | arm) |
| 521 | echo "arm-linux-androideabi" |
| 522 | ;; |
[email protected] | 4479d83 | 2014-05-13 13:35:34 | [diff] [blame] | 523 | arm64) |
| 524 | echo "aarch64-linux-android" |
| 525 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 526 | x86) |
| 527 | echo "i686-linux-android" |
| 528 | ;; |
[email protected] | 4479d83 | 2014-05-13 13:35:34 | [diff] [blame] | 529 | x86_64) |
| 530 | echo "x86_64-linux-android" |
| 531 | ;; |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 532 | mips) |
| 533 | echo "mipsel-linux-android" |
| 534 | ;; |
| 535 | *) |
| 536 | echo "$ARCH-linux-android" |
| 537 | ;; |
| 538 | esac |
| 539 | } |
| 540 | |
| 541 | # Convert an NDK architecture name into a toolchain name prefix |
| 542 | # $1: NDK architecture name (e.g. 'arm') |
| 543 | # Out: NDK toolchain name prefix (e.g. 'arm-linux-androideabi') |
| 544 | get_arch_toolchain_prefix () { |
thakis | 3e0451c | 2016-11-11 16:52:59 | [diff] [blame] | 545 | # Return the configure triplet, except for x86 and x86_64! |
| 546 | if [ "$1" = "x86" -o "$1" = "x86_64" ]; then |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 547 | echo "$1" |
| 548 | else |
| 549 | get_arch_gnu_config $1 |
| 550 | fi |
| 551 | } |
| 552 | |
| 553 | # Find a NDK toolchain prebuilt file or sub-directory. |
| 554 | # This will probe the various arch-specific toolchain directories |
| 555 | # in the NDK for the needed file. |
| 556 | # $1: NDK install path |
| 557 | # $2: NDK architecture name |
| 558 | # $3: prebuilt sub-path to look for. |
| 559 | # Out: file path, or empty if none is found. |
| 560 | get_ndk_toolchain_prebuilt () { |
| 561 | local NDK_DIR="${1%/}" |
| 562 | local ARCH="$2" |
| 563 | local SUBPATH="$3" |
| 564 | local NAME="$(get_arch_toolchain_prefix $ARCH)" |
| 565 | local FILE TARGET |
fdegans | 6b76713 | 2014-09-09 10:09:29 | [diff] [blame] | 566 | FILE=$NDK_DIR/toolchains/$NAME-4.9/prebuilt/$SUBPATH |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 567 | if [ ! -f "$FILE" ]; then |
fdegans | 6b76713 | 2014-09-09 10:09:29 | [diff] [blame] | 568 | FILE=$NDK_DIR/toolchains/$NAME-4.8/prebuilt/$SUBPATH |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 569 | if [ ! -f "$FILE" ]; then |
fdegans | 6b76713 | 2014-09-09 10:09:29 | [diff] [blame] | 570 | FILE= |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 571 | fi |
| 572 | fi |
| 573 | echo "$FILE" |
| 574 | } |
| 575 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 576 | # $1: NDK install path |
jbudorick | e6932bfd | 2016-09-07 02:09:22 | [diff] [blame] | 577 | get_ndk_host_gdb_client() { |
| 578 | local NDK_DIR="$1" |
| 579 | local HOST_OS HOST_ARCH |
| 580 | |
| 581 | HOST_OS=$(get_ndk_host_system) |
| 582 | HOST_ARCH=$(get_ndk_host_arch) |
| 583 | echo "$NDK_DIR/prebuilt/$HOST_OS-$HOST_ARCH/bin/gdb" |
| 584 | } |
| 585 | |
| 586 | # $1: NDK install path |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 587 | # $2: target architecture. |
| 588 | get_ndk_gdbserver () { |
| 589 | local NDK_DIR="$1" |
| 590 | local ARCH=$2 |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 591 | local BINARY |
| 592 | |
| 593 | # The location has moved after NDK r8 |
| 594 | BINARY=$NDK_DIR/prebuilt/android-$ARCH/gdbserver/gdbserver |
| 595 | if [ ! -f "$BINARY" ]; then |
| 596 | BINARY=$(get_ndk_toolchain_prebuilt "$NDK_DIR" "$ARCH" gdbserver) |
| 597 | fi |
| 598 | echo "$BINARY" |
| 599 | } |
| 600 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 601 | # Find host GDB client binary |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 602 | if [ -z "$GDB" ]; then |
jbudorick | e6932bfd | 2016-09-07 02:09:22 | [diff] [blame] | 603 | GDB=$(get_ndk_host_gdb_client "$ANDROID_NDK_ROOT") |
[email protected] | ddf4eec | 2013-10-07 20:50:49 | [diff] [blame] | 604 | if [ -z "$GDB" ]; then |
[email protected] | fca5dd8 | 2013-10-02 18:56:35 | [diff] [blame] | 605 | panic "Can't find Android gdb client in your path, check your \ |
| 606 | --toolchain or --gdb path." |
| 607 | fi |
| 608 | log "Host gdb client: $GDB" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 609 | fi |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 610 | |
| 611 | # Find gdbserver binary, we will later push it to /data/local/tmp |
| 612 | # This ensures that both gdbserver and $GDB talk the same binary protocol, |
| 613 | # otherwise weird problems will appear. |
| 614 | # |
| 615 | if [ -z "$GDBSERVER" ]; then |
| 616 | GDBSERVER=$(get_ndk_gdbserver "$ANDROID_NDK_ROOT" "$TARGET_ARCH") |
| 617 | if [ -z "$GDBSERVER" ]; then |
| 618 | panic "Can't find NDK gdbserver binary. use --gdbserver to specify \ |
| 619 | valid one!" |
| 620 | fi |
| 621 | log "Auto-config: --gdbserver=$GDBSERVER" |
| 622 | fi |
| 623 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 624 | # A unique ID for this script's session. This needs to be the same in all |
| 625 | # sub-shell commands we're going to launch, so take the PID of the launcher |
| 626 | # process. |
| 627 | TMP_ID=$$ |
| 628 | |
| 629 | # Temporary directory, will get cleaned up on exit. |
| 630 | TMPDIR=/tmp/$USER-adb-gdb-tmp-$TMP_ID |
| 631 | mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/* |
| 632 | |
| 633 | GDBSERVER_PIDFILE="$TMPDIR"/gdbserver-$TMP_ID.pid |
| 634 | |
watk | 206b2b3 | 2015-10-12 17:49:25 | [diff] [blame] | 635 | # Return the timestamp of a given file, as number of seconds since epoch. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 636 | # $1: file path |
| 637 | # Out: file timestamp |
| 638 | get_file_timestamp () { |
| 639 | stat -c %Y "$1" 2>/dev/null |
| 640 | } |
| 641 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 642 | # Allow several concurrent debugging sessions |
Peter Kotwicz | 9109749 | 2017-07-26 14:30:34 | [diff] [blame] | 643 | APP_DATA_DIR=$(adb_shell run-as $PACKAGE_NAME /system/bin/sh -c pwd) |
Dmitry Skiba | 7fb06bc | 2017-11-20 18:58:54 | [diff] [blame] | 644 | fail_panic "Failed to run-as $PACKAGE_NAME, is the app debuggable?" |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 645 | TARGET_GDBSERVER="$APP_DATA_DIR/gdbserver-adb-gdb-$TMP_ID" |
jimmym | b5b0414 | 2015-01-29 18:18:19 | [diff] [blame] | 646 | TMP_TARGET_GDBSERVER=/data/local/tmp/gdbserver-adb-gdb-$TMP_ID |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 647 | |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 648 | # Select correct app_process for architecture. |
| 649 | case $TARGET_ARCH in |
| 650 | arm|x86|mips) GDBEXEC=app_process32;; |
| 651 | arm64|x86_64) GDBEXEC=app_process64; SUFFIX_64_BIT=64;; |
| 652 | *) panic "Unknown app_process for architecture!";; |
| 653 | esac |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 654 | |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 655 | # Default to app_process if bit-width specific process isn't found. |
| 656 | adb_shell ls /system/bin/$GDBEXEC > /dev/null |
| 657 | if [ $? != 0 ]; then |
| 658 | GDBEXEC=app_process |
| 659 | fi |
| 660 | |
| 661 | # Detect AddressSanitizer setup on the device. In that case app_process is a |
| 662 | # script, and the real executable is app_process.real. |
| 663 | GDBEXEC_ASAN=app_process.real |
| 664 | adb_shell ls /system/bin/$GDBEXEC_ASAN > /dev/null |
| 665 | if [ $? == 0 ]; then |
| 666 | GDBEXEC=$GDBEXEC_ASAN |
| 667 | fi |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 668 | |
| 669 | ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 670 | if [[ -n "$ANDROID_SERIAL" ]]; then |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 671 | DEFAULT_PULL_LIBS_DIR="$DEFAULT_PULL_LIBS_DIR/$ANDROID_SERIAL-$SUFFIX_64_BIT" |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 672 | fi |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 673 | PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR} |
| 674 | |
| 675 | HOST_FINGERPRINT= |
| 676 | DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) |
watk | 206b2b3 | 2015-10-12 17:49:25 | [diff] [blame] | 677 | [[ "$DEVICE_FINGERPRINT" ]] || panic "Failed to get the device fingerprint" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 678 | log "Device build fingerprint: $DEVICE_FINGERPRINT" |
| 679 | |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 680 | if [ ! -f "$PULL_LIBS_DIR/build.fingerprint" ]; then |
| 681 | log "Auto-config: --pull-libs (no cached libraries)" |
| 682 | PULL_LIBS=true |
| 683 | else |
| 684 | HOST_FINGERPRINT=$(< "$PULL_LIBS_DIR/build.fingerprint") |
| 685 | log "Host build fingerprint: $HOST_FINGERPRINT" |
| 686 | if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then |
| 687 | log "Auto-config: --no-pull-libs (fingerprint match)" |
| 688 | NO_PULL_LIBS=true |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 689 | else |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 690 | log "Auto-config: --pull-libs (fingerprint mismatch)" |
| 691 | PULL_LIBS=true |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 692 | fi |
| 693 | fi |
| 694 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 695 | # If requested, work for M-x gdb. The gdb indirections make it |
| 696 | # difficult to pass --annotate=3 to the gdb binary itself. |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 697 | if [ "$ANNOTATE" ]; then |
| 698 | GDB_ARGS=$GDB_ARGS" --annotate=$ANNOTATE" |
| 699 | fi |
| 700 | |
| 701 | # Get the PID from the first argument or else find the PID of the |
| 702 | # browser process. |
| 703 | if [ -z "$PID" ]; then |
| 704 | PROCESSNAME=$PACKAGE_NAME |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 705 | if [ -z "$PID" ]; then |
| 706 | PID=$(adb_shell ps | \ |
| 707 | awk '$9 == "'$PROCESSNAME'" { print $2; }' | head -1) |
| 708 | fi |
| 709 | if [ -z "$PID" ]; then |
Andrew Grieve | 0febf292 | 2017-10-25 17:17:56 | [diff] [blame] | 710 | panic "Can't find application process PID." |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 711 | fi |
| 712 | log "Found process PID: $PID" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 713 | fi |
| 714 | |
| 715 | # Determine if 'adb shell' runs as root or not. |
| 716 | # If so, we can launch gdbserver directly, otherwise, we have to |
| 717 | # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable. |
| 718 | # |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 719 | if [ "$SU_PREFIX" ]; then |
| 720 | # Need to check that this works properly. |
| 721 | SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log |
ripp | 8fe7481 | 2015-01-23 14:51:48 | [diff] [blame] | 722 | adb_shell $SU_PREFIX \"echo "foo"\" > $SU_PREFIX_TEST_LOG 2>&1 |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 723 | if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then |
| 724 | echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:" |
ripp | e86f141f | 2015-01-29 07:24:59 | [diff] [blame] | 725 | echo "$ adb shell $SU_PREFIX \"echo foo\"" |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 726 | cat $SU_PREFIX_TEST_LOG |
| 727 | exit 1 |
| 728 | fi |
ripp | e86f141f | 2015-01-29 07:24:59 | [diff] [blame] | 729 | COMMAND_PREFIX="$SU_PREFIX \"" |
| 730 | COMMAND_SUFFIX="\"" |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 731 | else |
thakis | bab8bd0 | 2016-11-11 16:52:02 | [diff] [blame] | 732 | SHELL_UID=$("$ADB" shell cat /proc/self/status | \ |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 733 | awk '$1 == "Uid:" { print $2; }') |
| 734 | log "Shell UID: $SHELL_UID" |
| 735 | if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then |
| 736 | COMMAND_PREFIX="run-as $PACKAGE_NAME" |
ripp | e86f141f | 2015-01-29 07:24:59 | [diff] [blame] | 737 | COMMAND_SUFFIX= |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 738 | else |
| 739 | COMMAND_PREFIX= |
ripp | e86f141f | 2015-01-29 07:24:59 | [diff] [blame] | 740 | COMMAND_SUFFIX= |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 741 | fi |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 742 | fi |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 743 | log "Command prefix: '$COMMAND_PREFIX'" |
ripp | e86f141f | 2015-01-29 07:24:59 | [diff] [blame] | 744 | log "Command suffix: '$COMMAND_SUFFIX'" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 745 | |
Andrew Grieve | a9a7cec | 2017-08-09 20:12:50 | [diff] [blame] | 746 | mkdir -p "$PULL_LIBS_DIR" |
| 747 | fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR" |
| 748 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 749 | # Pull device's system libraries that are mapped by our process. |
| 750 | # Pulling all system libraries is too long, so determine which ones |
| 751 | # we need by looking at /proc/$PID/maps instead |
| 752 | if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then |
| 753 | echo "Extracting system libraries into: $PULL_LIBS_DIR" |
ripp | e86f141f | 2015-01-29 07:24:59 | [diff] [blame] | 754 | MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps $COMMAND_SUFFIX) |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 755 | if [ $? != 0 ]; then |
| 756 | echo "ERROR: Could not list process's memory mappings." |
| 757 | if [ "$SU_PREFIX" ]; then |
| 758 | panic "Are you sure your --su-prefix is correct?" |
| 759 | else |
| 760 | panic "Use --su-prefix if the application is not debuggable." |
| 761 | fi |
| 762 | fi |
watk | 206b2b3 | 2015-10-12 17:49:25 | [diff] [blame] | 763 | # Remove the fingerprint file in case pulling one of the libs fails. |
| 764 | rm -f "$PULL_LIBS_DIR/build.fingerprint" |
[email protected] | fc43840 | 2013-06-18 14:24:42 | [diff] [blame] | 765 | SYSTEM_LIBS=$(echo "$MAPPINGS" | \ |
Paul Thomson | d300eea | 2020-12-04 10:19:29 | [diff] [blame] | 766 | awk '$6 ~ /\/(system|apex|vendor)\/.*\.so$/ { print $6; }' | sort -u) |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 767 | for SYSLIB in /system/bin/linker$SUFFIX_64_BIT $SYSTEM_LIBS; do |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 768 | echo "Pulling from device: $SYSLIB" |
| 769 | DST_FILE=$PULL_LIBS_DIR$SYSLIB |
| 770 | DST_DIR=$(dirname "$DST_FILE") |
thakis | bab8bd0 | 2016-11-11 16:52:02 | [diff] [blame] | 771 | mkdir -p "$DST_DIR" && "$ADB" pull $SYSLIB "$DST_FILE" 2>/dev/null |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 772 | fail_panic "Could not pull $SYSLIB from device !?" |
| 773 | done |
watk | 206b2b3 | 2015-10-12 17:49:25 | [diff] [blame] | 774 | echo "Writing the device fingerprint" |
| 775 | echo "$DEVICE_FINGERPRINT" > "$PULL_LIBS_DIR/build.fingerprint" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 776 | fi |
| 777 | |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 778 | # Pull the app_process binary from the device. |
| 779 | log "Pulling $GDBEXEC from device" |
| 780 | "$ADB" pull /system/bin/$GDBEXEC "$TMPDIR"/$GDBEXEC &>/dev/null |
| 781 | fail_panic "Could not retrieve $GDBEXEC from the device!" |
| 782 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 783 | # Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4 |
| 784 | # so we can add them to solib-search-path later. |
| 785 | SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \ |
| 786 | grep -v "^$" | tr '\n' ':') |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 787 | SOLIB_DIRS=${SOLIB_DIRS%:} # Strip trailing : |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 788 | |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 789 | # Applications with minSdkVersion >= 24 will have their data directories |
| 790 | # created with rwx------ permissions, preventing adbd from forwarding to |
| 791 | # the gdbserver socket. |
| 792 | adb_shell $COMMAND_PREFIX chmod a+x $APP_DATA_DIR $COMMAND_SUFFIX |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 793 | |
| 794 | # Push gdbserver to the device |
[email protected] | fca5dd8 | 2013-10-02 18:56:35 | [diff] [blame] | 795 | log "Pushing gdbserver $GDBSERVER to $TARGET_GDBSERVER" |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 796 | "$ADB" push $GDBSERVER $TMP_TARGET_GDBSERVER >/dev/null && \ |
| 797 | adb_shell $COMMAND_PREFIX cp $TMP_TARGET_GDBSERVER $TARGET_GDBSERVER $COMMAND_SUFFIX && \ |
| 798 | adb_shell rm $TMP_TARGET_GDBSERVER |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 799 | fail_panic "Could not copy gdbserver to the device!" |
| 800 | |
lfg | a1639ebf | 2015-05-08 16:24:54 | [diff] [blame] | 801 | if [ -z "$PORT" ]; then |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 802 | # Random port to allow multiple concurrent sessions. |
| 803 | PORT=$(( $RANDOM % 1000 + 5039 )) |
lfg | a1639ebf | 2015-05-08 16:24:54 | [diff] [blame] | 804 | fi |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 805 | HOST_PORT=$PORT |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 806 | TARGET_DOMAIN_SOCKET=$APP_DATA_DIR/gdb-socket-$HOST_PORT |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 807 | |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 808 | # Setup network redirection |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 809 | log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_DOMAIN_SOCKET)" |
| 810 | "$ADB" forward tcp:$HOST_PORT localfilesystem:$TARGET_DOMAIN_SOCKET |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 811 | fail_panic "Could not setup network redirection from \ |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 812 | host:localhost:$HOST_PORT to device:$TARGET_DOMAIN_SOCKET" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 813 | |
| 814 | # Start gdbserver in the background |
| 815 | # Note that using run-as requires the package to be debuggable. |
| 816 | # |
| 817 | # If not, this will fail horribly. The alternative is to run the |
| 818 | # program as root, which requires of course root privileges. |
| 819 | # Maybe we should add a --root option to enable this? |
| 820 | # |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 821 | |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 822 | for i in 1 2; do |
| 823 | log "Starting gdbserver in the background:" |
| 824 | GDBSERVER_LOG=$TMPDIR/gdbserver-$TMP_ID.log |
| 825 | log "adb shell $COMMAND_PREFIX $TARGET_GDBSERVER \ |
| 826 | --once +$TARGET_DOMAIN_SOCKET \ |
| 827 | --attach $PID $COMMAND_SUFFIX" |
| 828 | "$ADB" shell $COMMAND_PREFIX $TARGET_GDBSERVER \ |
| 829 | --once +$TARGET_DOMAIN_SOCKET \ |
| 830 | --attach $PID $COMMAND_SUFFIX > $GDBSERVER_LOG 2>&1 & |
| 831 | GDBSERVER_PID=$! |
| 832 | echo "$GDBSERVER_PID" > $GDBSERVER_PIDFILE |
| 833 | log "background job pid: $GDBSERVER_PID" |
| 834 | |
| 835 | # Sleep to allow gdbserver to attach to the remote process and be |
| 836 | # ready to connect to. |
| 837 | log "Sleeping ${ATTACH_DELAY}s to ensure gdbserver is alive" |
| 838 | sleep "$ATTACH_DELAY" |
| 839 | log "Job control: $(jobs -l)" |
| 840 | STATE=$(jobs -l | awk '$2 == "'$GDBSERVER_PID'" { print $3; }') |
| 841 | if [ "$STATE" != "Running" ]; then |
| 842 | pid_msg=$(grep "is already traced by process" $GDBSERVER_LOG 2>/dev/null) |
| 843 | if [[ -n "$pid_msg" ]]; then |
| 844 | old_pid=${pid_msg##* } |
| 845 | old_pid=${old_pid//[$'\r\n']} # Trim trailing \r. |
| 846 | echo "Killing previous gdb server process (pid=$old_pid)" |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 847 | adb_shell $COMMAND_PREFIX kill -9 $old_pid $COMMAND_SUFFIX |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 848 | continue |
| 849 | fi |
| 850 | echo "ERROR: GDBServer either failed to run or attach to PID $PID!" |
| 851 | echo "Here is the output from gdbserver (also try --verbose for more):" |
| 852 | echo "===== gdbserver.log start =====" |
| 853 | cat $GDBSERVER_LOG |
| 854 | echo ="===== gdbserver.log end ======" |
| 855 | exit 1 |
| 856 | fi |
| 857 | break |
| 858 | done |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 859 | |
| 860 | # Generate a file containing useful GDB initialization commands |
| 861 | readonly COMMANDS=$TMPDIR/gdb.init |
| 862 | log "Generating GDB initialization commands file: $COMMANDS" |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 863 | cat > "$COMMANDS" <<EOF |
Andrew Grieve | d11fdb1 | 2018-07-16 13:59:51 | [diff] [blame] | 864 | set osabi GNU/Linux # Copied from ndk-gdb.py. |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 865 | set print pretty 1 |
| 866 | python |
| 867 | import sys |
| 868 | sys.path.insert(0, '$CHROMIUM_SRC/tools/gdb/') |
| 869 | try: |
| 870 | import gdb_chrome |
| 871 | finally: |
| 872 | sys.path.pop(0) |
| 873 | end |
| 874 | file $TMPDIR/$GDBEXEC |
Andrew Grieve | 4b85796 | 2018-10-03 15:06:31 | [diff] [blame] | 875 | directory $CHROMIUM_OUTPUT_DIR |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 876 | set solib-absolute-prefix $PULL_LIBS_DIR |
| 877 | set solib-search-path $SOLIB_DIRS:$PULL_LIBS_DIR:$SYMBOL_DIR |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 878 | |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 879 | python |
| 880 | # Copied from ndk-gdb.py: |
| 881 | def target_remote_with_retry(target, timeout_seconds): |
| 882 | import time |
| 883 | end_time = time.time() + timeout_seconds |
| 884 | while True: |
| 885 | try: |
Victor Vianna | b92383b | 2023-06-09 19:32:54 | [diff] [blame] | 886 | gdb.execute('target remote ' + target, True) |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 887 | return True |
| 888 | except gdb.error as e: |
| 889 | time_left = end_time - time.time() |
| 890 | if time_left < 0 or time_left > timeout_seconds: |
| 891 | print("Error: unable to connect to device.") |
| 892 | print(e) |
| 893 | return False |
| 894 | time.sleep(min(0.25, time_left)) |
| 895 | |
Andrew Grieve | 4b85796 | 2018-10-03 15:06:31 | [diff] [blame] | 896 | print("Connecting to :$HOST_PORT...") |
| 897 | if target_remote_with_retry(':$HOST_PORT', 5): |
| 898 | print("Attached! Reading symbols (takes ~30 seconds).") |
Andrew Grieve | 1ab3850 | 2017-07-19 14:56:56 | [diff] [blame] | 899 | end |
| 900 | EOF |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 901 | |
| 902 | if [ "$GDBINIT" ]; then |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 903 | cat "$GDBINIT" >> "$COMMANDS" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 904 | fi |
| 905 | |
| 906 | if [ "$VERBOSE" -gt 0 ]; then |
| 907 | echo "### START $COMMANDS" |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 908 | cat "$COMMANDS" |
[email protected] | 1c25946b9 | 2012-10-18 14:53:26 | [diff] [blame] | 909 | echo "### END $COMMANDS" |
| 910 | fi |
| 911 | |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 912 | if [ "$IDE" ]; then |
| 913 | mkdir -p "$IDE_DIR" |
| 914 | SYM_GDB="$IDE_DIR/gdb" |
| 915 | SYM_EXE="$IDE_DIR/app_process" |
| 916 | SYM_INIT="$IDE_DIR/gdbinit" |
| 917 | ln -sf "$TMPDIR/$GDBEXEC" "$SYM_EXE" |
| 918 | ln -sf "$COMMANDS" "$SYM_INIT" |
| 919 | # gdb doesn't work when symlinked, so create a wrapper. |
| 920 | echo |
| 921 | cat > $SYM_GDB <<EOF |
| 922 | #!/bin/sh |
| 923 | exec $GDB "\$@" |
| 924 | EOF |
| 925 | chmod u+x $SYM_GDB |
| 926 | |
| 927 | echo "GDB server listening on: localhost:$PORT" |
| 928 | echo "GDB wrapper script: $SYM_GDB" |
| 929 | echo "App executable: $SYM_EXE" |
| 930 | echo "gdbinit: $SYM_INIT" |
John Palmer | 58f5d9f | 2021-05-19 18:58:29 | [diff] [blame] | 931 | echo "Connect with vscode: https://chromium.googlesource.com/chromium/src/+/main/docs/vscode.md#Launch-Commands" |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 932 | echo "Showing gdbserver logs. Press Ctrl-C to disconnect." |
| 933 | tail -f "$GDBSERVER_LOG" |
sakal | a4dfc338 | 2017-06-19 15:03:44 | [diff] [blame] | 934 | else |
Andrew Grieve | 4f48dc97 | 2018-07-10 03:34:53 | [diff] [blame] | 935 | log "Launching gdb client: $GDB $GDB_ARGS -x $COMMANDS" |
| 936 | echo "Server log: $GDBSERVER_LOG" |
| 937 | if [ "$CGDB" ]; then |
| 938 | $CGDB -d $GDB -- $GDB_ARGS -x "$COMMANDS" |
| 939 | else |
| 940 | $GDB $GDB_ARGS -x "$COMMANDS" |
| 941 | fi |
sakal | a4dfc338 | 2017-06-19 15:03:44 | [diff] [blame] | 942 | fi |