1#!/bin/bash 2# 3# Copyright 2023 The Chromium Authors 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 debug it. 9# Most users should not use this directly, but one of the wrapper scripts like 10# connect_lldb.sh_content_shell 11# 12# Use --help to print full usage instructions. 13# 14 15PROGNAME=$(basename "$0") 16PROGDIR=$(dirname "$0") 17 18# Force locale to C to allow recognizing output from subprocesses. 19LC_ALL=C 20 21# Location of Chromium-top-level sources. 22CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null) 23 24TMPDIR= 25LLDB_SERVER_JOB_PIDFILE= 26LLDB_SERVER_PID= 27TARGET_LLDB_SERVER= 28COMMAND_PREFIX= 29COMMAND_SUFFIX= 30 31clean_exit () { 32 if [ "$TMPDIR" ]; then 33 LLDB_SERVER_JOB_PID=$(cat $LLDB_SERVER_JOB_PIDFILE 2>/dev/null) 34 if [ "$LLDB_SERVER_PID" ]; then 35 log "Killing lldb-server process on-device: $LLDB_SERVER_PID" 36 adb_shell kill $LLDB_SERVER_PID 37 fi 38 if [ "$LLDB_SERVER_JOB_PID" ]; then 39 log "Killing background lldb-server process: $LLDB_SERVER_JOB_PID" 40 kill -9 $LLDB_SERVER_JOB_PID >/dev/null 2>&1 41 rm -f "$LLDB_SERVER_JOB_PIDFILE" 42 fi 43 if [ "$TARGET_LLDB_SERVER" ]; then 44 log "Removing target lldb-server binary: $TARGET_LLDB_SERVER." 45 "$ADB" shell "$COMMAND_PREFIX" rm "$TARGET_LLDB_SERVER" \ 46 "$TARGET_DOMAIN_SOCKET" "$COMMAND_SUFFIX" >/dev/null 2>&1 47 fi 48 log "Cleaning up: $TMPDIR" 49 rm -rf "$TMPDIR" 50 fi 51 trap "" EXIT 52 exit $1 53} 54 55# Ensure clean exit on Ctrl-C or normal exit. 56trap "clean_exit 1" INT HUP QUIT TERM 57trap "clean_exit \$?" EXIT 58 59panic () { 60 echo "ERROR: $@" >&2 61 exit 1 62} 63 64fail_panic () { 65 if [ $? != 0 ]; then panic "$@"; fi 66} 67 68log () { 69 if [ "$VERBOSE" -gt 0 ]; then 70 echo "$@" 71 fi 72} 73 74DEFAULT_PULL_LIBS_DIR="/tmp/adb-lldb-support-$USER" 75 76# NOTE: Allow wrapper scripts to set various default through ADB_LLDB_XXX 77# environment variables. This is only for cosmetic reasons, i.e. to 78# display proper default in the --help output. 79 80# Allow wrapper scripts to set the program name through ADB_LLDB_PROGNAME 81PROGNAME=${ADB_LLDB_PROGNAME:-$(basename "$0")} 82 83ADB= 84ATTACH_DELAY=1 85HELP= 86LLDB_INIT= 87LLDB_SERVER= 88NDK_DIR= 89NO_PULL_LIBS= 90PACKAGE_NAME= 91PID= 92PORT= 93PROCESS_NAME= 94PROGRAM_NAME="activity" 95PULL_LIBS= 96PULL_LIBS_DIR= 97SU_PREFIX= 98SYMBOL_DIR= 99TARGET_ARCH= 100TOOLCHAIN= 101VERBOSE=0 102 103for opt; do 104 optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)') 105 case $opt in 106 --adb=*) ADB=$optarg ;; 107 --attach-delay=*) ATTACH_DELAY=$optarg ;; 108 --device=*) export ANDROID_SERIAL=$optarg ;; 109 --help|-h|-?) HELP=true ;; 110 --lldb=*) LLDB=$optarg ;; 111 --lldb-server=*) LLDB_SERVER=$optarg ;; 112 --ndk-dir=*) NDK_DIR=$optarg ;; 113 --no-pull-libs) NO_PULL_LIBS=true ;; 114 --output-directory=*) CHROMIUM_OUTPUT_DIR=$optarg ;; 115 --package-name=*) PACKAGE_NAME=$optarg ;; 116 --pid=*) PID=$optarg ;; 117 --port=*) PORT=$optarg ;; 118 --process-name=*) PROCESS_NAME=$optarg ;; 119 --program-name=*) PROGRAM_NAME=$optarg ;; 120 --pull-libs) PULL_LIBS=true ;; 121 --pull-libs-dir=*) PULL_LIBS_DIR=$optarg ;; 122 --source=*) LLDB_INIT=$optarg ;; 123 --su-prefix=*) SU_PREFIX=$optarg ;; 124 --symbol-dir=*) SYMBOL_DIR=$optarg ;; 125 --target-arch=*) TARGET_ARCH=$optarg ;; 126 --toolchain=*) TOOLCHAIN=$optarg ;; 127 --verbose) VERBOSE=$(( $VERBOSE + 1 )) ;; 128 -*) 129 panic "Unknown option $opt, see --help." >&2 130 ;; 131 *) 132 if [ "$PACKAGE_NAME" ]; then 133 panic "You can only provide a single package name as argument!\ 134 See --help." 135 fi 136 PACKAGE_NAME=$opt 137 ;; 138 esac 139done 140 141if [ "$HELP" ]; then 142 if [ "$ADB_LLDB_PROGNAME" ]; then 143 # Assume wrapper scripts all provide a default package name. 144 cat <<EOF 145Usage: $PROGNAME [options] 146 147Attach lldb to a running Android $PROGRAM_NAME process. 148EOF 149 else 150 # Assume this is a direct call to connect_lldb.sh 151 cat <<EOF 152Usage: $PROGNAME [options] [<package-name>] 153 154Attach lldb to a running Android $PROGRAM_NAME process. 155 156If provided, <package-name> must be the name of the Android application's 157package name to be debugged. You can also use --package-name=<name> to 158specify it. 159EOF 160 fi 161 162 cat <<EOF 163 164This script is used to debug a running $PROGRAM_NAME process. 165 166This script needs several things to work properly. It will try to pick 167them up automatically for you though: 168 169 - target lldb-server binary 170 - host lldb client, possibly a wrapper (e.g. lldb.sh) 171 - directory with symbolic version of $PROGRAM_NAME's shared libraries. 172 173You can also use --ndk-dir=<path> to specify an alternative NDK installation 174directory. 175 176The script tries to find the most recent version of the debug version of 177shared libraries under one of the following directories: 178 179 \$CHROMIUM_SRC/<out>/lib.unstripped/ (used by GN builds) 180 181Where <out> is determined by CHROMIUM_OUTPUT_DIR, or --output-directory. 182 183You can set the path manually via --symbol-dir. 184 185The script tries to extract the target architecture from your target device, 186but if this fails, will default to 'arm'. Use --target-arch=<name> to force 187its value. 188 189Otherwise, the script will complain, but you can use the --lldb-server, 190--lldb and --symbol-lib options to specify everything manually. 191 192An alternative to --lldb=<file> is to use --toolchain=<path> to specify 193the path to the host target-specific cross-toolchain. 194 195You will also need the 'adb' tool in your path. Otherwise, use the --adb 196option. The script will complain if there is more than one device connected 197and a device is not specified with either --device or ANDROID_SERIAL). 198 199The first time you use it on a device, the script will pull many system 200libraries required by the process into a temporary directory. This 201is done to strongly improve the debugging experience, like allowing 202readable thread stacks and more. The libraries are copied to the following 203directory by default: 204 205 $DEFAULT_PULL_LIBS_DIR/ 206 207But you can use the --pull-libs-dir=<path> option to specify an 208alternative. The script can detect when you change the connected device, 209and will re-pull the libraries only in this case. You can however force it 210with the --pull-libs option. 211 212Any local .lldb-init script will be ignored, but it is possible to pass a 213lldb command script with the --source=<file> option. Note that its commands 214will be passed to lldb after the remote connection and library symbol 215loading have completed. 216 217Valid options: 218 --help|-h|-? Print this message. 219 --verbose Increase verbosity. 220 221 --symbol-dir=<path> Specify directory with symbol shared libraries. 222 --output-directory=<path> Specify the output directory (e.g. "out/Debug"). 223 --package-name=<name> Specify package name (alternative to 1st argument). 224 --program-name=<name> Specify program name (cosmetic only). 225 --process-name=<name> Specify process name to attach to (uses package-name 226 if not passsed). 227 --pid=<pid> Specify application process pid. 228 --attach-delay=<num> Seconds to wait for lldb-server to attach to the 229 remote process before starting lldb. Default 1. 230 <num> may be a float if your sleep(1) supports it. 231 --source=<file> Specify extra LLDB init script. 232 233 --lldb-server=<file> Specify target lldb-server binary. 234 --lldb=<file> Specify host lldb client binary. 235 --target-arch=<name> Specify NDK target arch. 236 --adb=<file> Specify host ADB binary. 237 --device=<file> ADB device serial to use (-s flag). 238 --port=<port> Specify the tcp port to use. 239 240 --su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are 241 run by this script. This can be useful to use 242 the 'su' program on rooted production devices. 243 e.g. --su-prefix="su -c" 244 245 --pull-libs Force system libraries extraction. 246 --no-pull-libs Do not extract any system library. 247 --libs-dir=<path> Specify system libraries extraction directory. 248 249EOF 250 exit 0 251fi 252 253if [ -z "$PACKAGE_NAME" ]; then 254 panic "Please specify a package name on the command line. See --help." 255fi 256 257if [[ -z "$SYMBOL_DIR" && -z "$CHROMIUM_OUTPUT_DIR" ]]; then 258 if [[ -e "build.ninja" ]]; then 259 CHROMIUM_OUTPUT_DIR=$PWD 260 else 261 panic "Please specify an output directory by using one of: 262 --output-directory=out/Debug 263 CHROMIUM_OUTPUT_DIR=out/Debug 264 Setting working directory to an output directory. 265 See --help." 266 fi 267fi 268 269if ls *.so >/dev/null 2>&1; then 270 panic ".so files found in your working directory. These will conflict with" \ 271 "library lookup logic. Change your working directory and try again." 272fi 273 274# Detects the build type and symbol directory. This is done by finding 275# the most recent sub-directory containing debug shared libraries under 276# $CHROMIUM_OUTPUT_DIR. 277# Out: nothing, but this sets SYMBOL_DIR 278detect_symbol_dir () { 279 # GN places unstripped libraries under out/lib.unstripped 280 local PARENT_DIR="$CHROMIUM_OUTPUT_DIR" 281 if [[ ! -e "$PARENT_DIR" ]]; then 282 PARENT_DIR="$CHROMIUM_SRC/$PARENT_DIR" 283 fi 284 SYMBOL_DIR="$PARENT_DIR/lib.unstripped" 285 if [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then 286 SYMBOL_DIR="$PARENT_DIR/lib" 287 if [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then 288 panic "Could not find any symbols under \ 289$PARENT_DIR/lib{.unstripped}. Please build the program first!" 290 fi 291 fi 292 log "Auto-config: --symbol-dir=$SYMBOL_DIR" 293} 294 295if [ -z "$SYMBOL_DIR" ]; then 296 detect_symbol_dir 297elif [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then 298 panic "Could not find any symbols under $SYMBOL_DIR" 299fi 300 301if [ -z "$NDK_DIR" ]; then 302 ANDROID_NDK_ROOT=$(PYTHONPATH=$CHROMIUM_SRC/build/android python3 -c \ 303 'from pylib.constants import ANDROID_NDK_ROOT; print(ANDROID_NDK_ROOT,)') 304else 305 if [ ! -d "$NDK_DIR" ]; then 306 panic "Invalid directory: $NDK_DIR" 307 fi 308 if [ ! -d "$NDK_DIR/toolchains" ]; then 309 panic "Not a valid NDK directory: $NDK_DIR" 310 fi 311 ANDROID_NDK_ROOT=$NDK_DIR 312fi 313 314if [ "$LLDB_INIT" -a ! -f "$LLDB_INIT" ]; then 315 panic "Unknown --source file: $LLDB_INIT" 316fi 317 318# Checks that ADB is in our path 319if [ -z "$ADB" ]; then 320 ADB=$(which adb 2>/dev/null) 321 if [ -z "$ADB" ]; then 322 panic "Can't find 'adb' tool in your path. Install it or use \ 323--adb=<file>" 324 fi 325 log "Auto-config: --adb=$ADB" 326fi 327 328# Checks that it works minimally 329ADB_VERSION=$($ADB version 2>/dev/null) 330echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge" 331if [ $? != 0 ]; then 332 panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \ 333different one: $ADB" 334fi 335 336# If there are more than one device connected, and ANDROID_SERIAL is not 337# defined, prints an error message. 338NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l) 339if [ "$NUM_DEVICES_PLUS2" -gt 3 -a -z "$ANDROID_SERIAL" ]; then 340 echo "ERROR: There is more than one Android device connected to ADB." 341 echo "Please define ANDROID_SERIAL to specify which one to use." 342 exit 1 343fi 344 345# Runs a command through adb shell, strip the extra \r from the output 346# and return the correct status code to detect failures. This assumes 347# that the adb shell command prints a final \n to stdout. 348# $1+: command to run 349# Out: command's stdout 350# Return: command's status 351# Note: the command's stderr is lost 352# Info: In Python would be done via DeviceUtils.RunShellCommand(). 353adb_shell () { 354 local TMPOUT="$(mktemp)" 355 local LASTLINE RET 356 local ADB=${ADB:-adb} 357 358 # The weird sed rule is to strip the final \r on each output line 359 # Since 'adb shell' never returns the command's proper exit/status code, 360 # we force it to print it as '%%<status>' in the temporary output file, 361 # which we will later strip from it. 362 $ADB shell $@ ";" echo "%%\$?" 2>/dev/null | \ 363 sed -e 's![[:cntrl:]]!!g' > $TMPOUT 364 # Get last line in log, which contains the exit code from the command 365 LASTLINE=$(sed -e '$!d' $TMPOUT) 366 # Extract the status code from the end of the line, which must 367 # be '%%<code>'. 368 RET=$(echo "$LASTLINE" | \ 369 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }') 370 # Remove the status code from the last line. Note that this may result 371 # in an empty line. 372 LASTLINE=$(echo "$LASTLINE" | \ 373 awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }') 374 # The output itself: all lines except the status code. 375 sed -e '$d' $TMPOUT && printf "%s" "$LASTLINE" 376 # Remove temp file. 377 rm -f $TMPOUT 378 # Exit with the appropriate status. 379 return $RET 380} 381 382# Finds the target architecture from a local shared library. 383# This returns an NDK-compatible architecture name. 384# Out: NDK Architecture name, or empty string. 385get_gn_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 $SO_DESC in 390 *32-bit*ARM,*) echo "arm";; 391 *64-bit*ARM,*) echo "arm64";; 392 *64-bit*aarch64,*) echo "arm64";; 393 *32-bit*Intel,*) echo "x86";; 394 *x86-64,*) echo "x86_64";; 395 *32-bit*MIPS,*) echo "mips";; 396 *) echo ""; 397 esac 398} 399 400if [ -z "$TARGET_ARCH" ]; then 401 TARGET_ARCH=$(get_gn_target_arch) 402 if [ -z "$TARGET_ARCH" ]; then 403 TARGET_ARCH=arm 404 fi 405 log "Auto-config: --arch=$TARGET_ARCH" 406else 407 # Nit: accept Chromium's 'ia32' as a valid target architecture. This 408 # script prefers the NDK 'x86' name instead because it uses it to find 409 # NDK-specific files (host lldb) with it. 410 if [ "$TARGET_ARCH" = "ia32" ]; then 411 TARGET_ARCH=x86 412 log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)" 413 fi 414fi 415 416# Translates GN target architecure to NDK subdirectory name. 417# $1: GN target architecture. 418# Out: NDK subdirectory name. 419get_ndk_arch_dir () { 420 case "$1" in 421 arm64) echo "aarch64";; 422 x86) echo "i386";; 423 *) echo "$1"; 424 esac 425} 426 427# Detects the NDK system name, i.e. the name used to identify the host. 428# out: NDK system name (e.g. 'linux' or 'darwin') 429get_ndk_host_system () { 430 local HOST_OS 431 if [ -z "$NDK_HOST_SYSTEM" ]; then 432 HOST_OS=$(uname -s) 433 case $HOST_OS in 434 Linux) NDK_HOST_SYSTEM=linux;; 435 Darwin) NDK_HOST_SYSTEM=darwin;; 436 *) panic "You can't run this script on this system: $HOST_OS";; 437 esac 438 fi 439 echo "$NDK_HOST_SYSTEM" 440} 441 442# Detects the NDK host architecture name. 443# out: NDK arch name (e.g. 'x86_64') 444get_ndk_host_arch () { 445 echo "x86_64" 446} 447 448# $1: NDK install path. 449get_ndk_host_lldb_client() { 450 local NDK_DIR="$1" 451 local HOST_OS=$(get_ndk_host_system) 452 local HOST_ARCH=$(get_ndk_host_arch) 453 echo "$NDK_DIR/toolchains/llvm/prebuilt/$HOST_OS-$HOST_ARCH/bin/lldb.sh" 454} 455 456# $1: NDK install path. 457# $2: target architecture. 458get_ndk_lldb_server () { 459 local NDK_DIR="$1" 460 local ARCH=$2 461 local HOST_OS=$(get_ndk_host_system) 462 local HOST_ARCH=$(get_ndk_host_arch) 463 local NDK_ARCH_DIR=$(get_ndk_arch_dir "$ARCH") 464 local i 465 # For lldb-server is under lib64/ for r25, and lib/ for r26+. 466 for i in "lib64" "lib"; do 467 local RET=$(realpath -m $NDK_DIR/toolchains/llvm/prebuilt/$HOST_OS-$HOST_ARCH/$i/clang/*/lib/linux/$NDK_ARCH_DIR/lldb-server) 468 if [ -e "$RET" ]; then 469 echo $RET 470 return 0 471 fi 472 done 473 return 1 474} 475 476# Find host LLDB client binary 477if [ -z "$LLDB" ]; then 478 LLDB=$(get_ndk_host_lldb_client "$ANDROID_NDK_ROOT") 479 if [ -z "$LLDB" ]; then 480 panic "Can't find Android lldb client in your path, check your \ 481--toolchain or --lldb path." 482 fi 483 log "Host lldb client: $LLDB" 484fi 485 486# Find lldb-server binary, we will later push it to /data/local/tmp 487# This ensures that both lldb-server and $LLDB talk the same binary protocol, 488# otherwise weird problems will appear. 489if [ -z "$LLDB_SERVER" ]; then 490 LLDB_SERVER=$(get_ndk_lldb_server "$ANDROID_NDK_ROOT" "$TARGET_ARCH") 491 if [ -z "$LLDB_SERVER" ]; then 492 panic "Can't find NDK lldb-server binary. use --lldb-server to specify \ 493valid one!" 494 fi 495 log "Auto-config: --lldb-server=$LLDB_SERVER" 496fi 497 498# A unique ID for this script's session. This needs to be the same in all 499# sub-shell commands we're going to launch, so take the PID of the launcher 500# process. 501TMP_ID=$$ 502 503# Temporary directory, will get cleaned up on exit. 504TMPDIR=/tmp/$USER-adb-lldb-tmp-$TMP_ID 505mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/* 506 507LLDB_SERVER_JOB_PIDFILE="$TMPDIR"/lldb-server-$TMP_ID.pid 508 509# Returns the timestamp of a given file, as number of seconds since epoch. 510# $1: file path 511# Out: file timestamp 512get_file_timestamp () { 513 stat -c %Y "$1" 2>/dev/null 514} 515 516# Allow several concurrent debugging sessions 517APP_DATA_DIR=$(adb_shell run-as $PACKAGE_NAME /system/bin/sh -c pwd) 518if [ $? != 0 ]; then 519 echo "Failed to run-as $PACKAGE_NAME, is the app debuggable?" 520 APP_DATA_DIR=$(adb_shell dumpsys package $PACKAGE_NAME | \ 521 sed -ne 's/^ \+dataDir=//p' | head -n1) 522fi 523log "App data dir: $APP_DATA_DIR" 524TARGET_LLDB_SERVER="$APP_DATA_DIR/lldb-server-adb-lldb-$TMP_ID" 525TMP_TARGET_LLDB_SERVER=/data/local/tmp/lldb-server-adb-lldb-$TMP_ID 526 527# Select correct app_process for architecture. 528case $TARGET_ARCH in 529 arm|x86|mips) LLDBEXEC=app_process32;; 530 arm64|x86_64) LLDBEXEC=app_process64; SUFFIX_64_BIT=64;; 531 *) panic "Unknown app_process for architecture!";; 532esac 533 534# Default to app_process if bit-width specific process isn't found. 535adb_shell ls /system/bin/$LLDBEXEC > /dev/null 536if [ $? != 0 ]; then 537 LLDBEXEC=app_process 538fi 539 540# Detect AddressSanitizer setup on the device. In that case app_process is a 541# script, and the real executable is app_process.real. 542LLDBEXEC_ASAN=app_process.real 543adb_shell ls /system/bin/$LLDBEXEC_ASAN > /dev/null 544if [ $? == 0 ]; then 545 LLDBEXEC=$LLDBEXEC_ASAN 546fi 547 548ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR 549if [[ -n "$ANDROID_SERIAL" ]]; then 550 DEFAULT_PULL_LIBS_DIR="$DEFAULT_PULL_LIBS_DIR/$ANDROID_SERIAL-$SUFFIX_64_BIT" 551fi 552PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR} 553 554HOST_FINGERPRINT= 555DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint) 556[[ "$DEVICE_FINGERPRINT" ]] || panic "Failed to get the device fingerprint" 557log "Device build fingerprint: $DEVICE_FINGERPRINT" 558 559if [ ! -f "$PULL_LIBS_DIR/build.fingerprint" ]; then 560 log "Auto-config: --pull-libs (no cached libraries)" 561 PULL_LIBS=true 562else 563 HOST_FINGERPRINT=$(< "$PULL_LIBS_DIR/build.fingerprint") 564 log "Host build fingerprint: $HOST_FINGERPRINT" 565 if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then 566 log "Auto-config: --no-pull-libs (fingerprint match)" 567 NO_PULL_LIBS=true 568 else 569 log "Auto-config: --pull-libs (fingerprint mismatch)" 570 PULL_LIBS=true 571 fi 572fi 573 574# Get the PID from the first argument or else find the PID of the 575# browser process (or the process named by $PROCESS_NAME). 576if [ -z "$PID" ]; then 577 if [ -z "$PROCESS_NAME" ]; then 578 PROCESS_NAME=$PACKAGE_NAME 579 fi 580 if [ -z "$PID" ]; then 581 PID=$(adb_shell ps | \ 582 awk '$9 == "'$PROCESS_NAME'" { print $2; }' | head -1) 583 fi 584 if [ -z "$PID" ]; then 585 panic "Can't find application process PID." 586 fi 587 log "Found process PID: $PID" 588fi 589 590# Determine if 'adb shell' runs as root or not. 591# If so, we can launch lldb-server directly, otherwise, we have to 592# use run-as $PACKAGE_NAME ..., which requires the package to be debuggable. 593# 594if [ "$SU_PREFIX" ]; then 595 # Need to check that this works properly. 596 SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log 597 adb_shell $SU_PREFIX \"echo "foo"\" > $SU_PREFIX_TEST_LOG 2>&1 598 if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then 599 echo "ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:" 600 echo "$ adb shell $SU_PREFIX \"echo foo\"" 601 cat $SU_PREFIX_TEST_LOG 602 exit 1 603 fi 604 COMMAND_PREFIX="$SU_PREFIX \"" 605 COMMAND_SUFFIX="\"" 606else 607 SHELL_UID=$("$ADB" shell cat /proc/self/status | \ 608 awk '$1 == "Uid:" { print $2; }') 609 log "Shell UID: $SHELL_UID" 610 if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then 611 COMMAND_PREFIX="run-as $PACKAGE_NAME" 612 COMMAND_SUFFIX= 613 else 614 COMMAND_PREFIX= 615 COMMAND_SUFFIX= 616 fi 617fi 618log "Command prefix: '$COMMAND_PREFIX'" 619log "Command suffix: '$COMMAND_SUFFIX'" 620 621mkdir -p "$PULL_LIBS_DIR" 622fail_panic "Can't create --libs-dir directory: $PULL_LIBS_DIR" 623 624# Pull device's system libraries that are mapped by our process. 625# Pulling all system libraries is too long, so determine which ones 626# we need by looking at /proc/$PID/maps instead 627if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then 628 echo "Extracting system libraries into: $PULL_LIBS_DIR" 629 MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps $COMMAND_SUFFIX) 630 if [ $? != 0 ]; then 631 echo "ERROR: Could not list process's memory mappings." 632 if [ "$SU_PREFIX" ]; then 633 panic "Are you sure your --su-prefix is correct?" 634 else 635 panic "Use --su-prefix if the application is not debuggable." 636 fi 637 fi 638 # Remove the fingerprint file in case pulling one of the libs fails. 639 rm -f "$PULL_LIBS_DIR/build.fingerprint" 640 SYSTEM_LIBS=$(echo "$MAPPINGS" | \ 641 awk '$6 ~ /\/(system|apex|vendor)\/.*\.so$/ { print $6; }' | sort -u) 642 for SYSLIB in /system/bin/linker$SUFFIX_64_BIT $SYSTEM_LIBS; do 643 echo "Pulling from device: $SYSLIB" 644 DST_FILE=$PULL_LIBS_DIR$SYSLIB 645 DST_DIR=$(dirname "$DST_FILE") 646 mkdir -p "$DST_DIR" && "$ADB" pull $SYSLIB "$DST_FILE" 2>/dev/null 647 fail_panic "Could not pull $SYSLIB from device !?" 648 done 649 echo "Writing the device fingerprint" 650 echo "$DEVICE_FINGERPRINT" > "$PULL_LIBS_DIR/build.fingerprint" 651fi 652 653# Pull the app_process binary from the device. 654log "Pulling $LLDBEXEC from device" 655"$ADB" pull /system/bin/$LLDBEXEC "$TMPDIR"/$LLDBEXEC &>/dev/null 656fail_panic "Could not retrieve $LLDBEXEC from the device!" 657 658# Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4 659# so we can add them to target.exec-search-paths later. 660SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \ 661 grep -v "^$" | tr '\n' ' ') 662 663# Applications with minSdkVersion >= 24 will have their data directories 664# created with rwx------ permissions, preventing adbd from forwarding to 665# the lldb-server socket. 666adb_shell $COMMAND_PREFIX chmod a+x $APP_DATA_DIR $COMMAND_SUFFIX 667 668# Push lldb-server to the device 669log "Pushing lldb-server $LLDB_SERVER to $TARGET_LLDB_SERVER" 670"$ADB" push $LLDB_SERVER $TMP_TARGET_LLDB_SERVER >/dev/null && \ 671 adb_shell $COMMAND_PREFIX cp $TMP_TARGET_LLDB_SERVER $TARGET_LLDB_SERVER $COMMAND_SUFFIX && \ 672 adb_shell rm $TMP_TARGET_LLDB_SERVER 673fail_panic "Could not copy lldb-server to the device!" 674 675if [ -z "$PORT" ]; then 676 # Random port to allow multiple concurrent sessions. 677 PORT=$(( $RANDOM % 1000 + 5039 )) 678fi 679HOST_PORT=$PORT 680TARGET_DOMAIN_SOCKET=$APP_DATA_DIR/lldb-socket-$HOST_PORT 681 682# Setup network redirection 683log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_DOMAIN_SOCKET)" 684"$ADB" forward tcp:$HOST_PORT localfilesystem:$TARGET_DOMAIN_SOCKET 685fail_panic "Could not setup network redirection from \ 686host:localhost:$HOST_PORT to device:$TARGET_DOMAIN_SOCKET" 687 688# Start lldb-server in the background 689# Note that using run-as requires the package to be debuggable. 690# 691# If not, this will fail horribly. The alternative is to run the 692# program as root, which requires of course root privileges. 693# Maybe we should add a --root option to enable this? 694 695for i in 1 2; do 696 log "Starting lldb-server in the background:" 697 LLDB_SERVER_LOG=$TMPDIR/lldb-server-$TMP_ID.log 698 log "adb shell $COMMAND_PREFIX $TARGET_LLDB_SERVER g \ 699 $TARGET_DOMAIN_SOCKET \ 700 --attach $PID $COMMAND_SUFFIX" 701 "$ADB" shell $COMMAND_PREFIX $TARGET_LLDB_SERVER g \ 702 $TARGET_DOMAIN_SOCKET \ 703 --attach $PID $COMMAND_SUFFIX > $LLDB_SERVER_LOG 2>&1 & 704 LLDB_SERVER_JOB_PID=$! 705 LLDB_SERVER_PID=$(adb_shell $COMMAND_PREFIX pidof $(basename $TARGET_LLDB_SERVER)) 706 echo "$LLDB_SERVER_JOB_PID" > $LLDB_SERVER_JOB_PIDFILE 707 log "background job pid: $LLDB_SERVER_JOB_PID" 708 709 # Sleep to allow lldb-server to attach to the remote process and be 710 # ready to connect to. 711 log "Sleeping ${ATTACH_DELAY}s to ensure lldb-server is alive" 712 sleep "$ATTACH_DELAY" 713 log "Job control: $(jobs -l)" 714 STATE=$(jobs -l | awk '$2 == "'$LLDB_SERVER_JOB_PID'" { print $3; }') 715 if [ "$STATE" != "Running" ]; then 716 pid_msg=$(grep "is already traced by process" $LLDB_SERVER_LOG 2>/dev/null) 717 if [[ -n "$pid_msg" ]]; then 718 old_pid=${pid_msg##* } 719 old_pid=${old_pid//[$'\r\n']} # Trim trailing \r. 720 echo "Killing previous lldb-server process (pid=$old_pid)" 721 adb_shell $COMMAND_PREFIX kill -9 $old_pid $COMMAND_SUFFIX 722 continue 723 fi 724 echo "ERROR: lldb-server either failed to run or attach to PID $PID!" 725 echo "Here is the output from lldb-server (also try --verbose for more):" 726 echo "===== lldb-server.log start =====" 727 cat $LLDB_SERVER_LOG 728 echo ="===== lldb-server.log end ======" 729 exit 1 730 fi 731 break 732done 733 734# Generate a file containing useful LLDB initialization commands 735readonly COMMANDS=$TMPDIR/lldb.init 736log "Generating LLDB initialization commands file: $COMMANDS" 737cat > "$COMMANDS" <<EOF 738settings append target.exec-search-paths $SYMBOL_DIR $SOLIB_DIRS $PULL_LIBS_DIR 739settings set target.source-map ../.. $CHROMIUM_SRC 740target create '$TMPDIR/$LLDBEXEC' 741target modules search-paths add / $TMPDIR/$LLDBEXEC/ 742script print("Connecting to :$HOST_PORT... (symbol load can take a while)") 743gdb-remote $HOST_PORT 744EOF 745 746if [ "$LLDB_INIT" ]; then 747 cat "$LLDB_INIT" >> "$COMMANDS" 748fi 749 750if [ "$VERBOSE" -gt 0 ]; then 751 echo "### START $COMMANDS" 752 cat "$COMMANDS" 753 echo "### END $COMMANDS" 754fi 755 756log "Launching lldb client: $LLDB $LLDB_ARGS --source $COMMANDS" 757echo "Server log: $LLDB_SERVER_LOG" 758$LLDB $LLDB_ARGS --source "$COMMANDS" 759