adb_gdb 30 KB

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