tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

connect_lldb.sh (25542B)


      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 
     15 PROGNAME=$(basename "$0")
     16 PROGDIR=$(dirname "$0")
     17 
     18 # Force locale to C to allow recognizing output from subprocesses.
     19 LC_ALL=C
     20 
     21 # Location of Chromium-top-level sources.
     22 CHROMIUM_SRC=$(cd "$PROGDIR"/../.. >/dev/null && pwd 2>/dev/null)
     23 
     24 TMPDIR=
     25 LLDB_SERVER_JOB_PIDFILE=
     26 LLDB_SERVER_PID=
     27 TARGET_LLDB_SERVER=
     28 COMMAND_PREFIX=
     29 COMMAND_SUFFIX=
     30 
     31 clean_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.
     56 trap "clean_exit 1" INT HUP QUIT TERM
     57 trap "clean_exit \$?" EXIT
     58 
     59 panic () {
     60  echo "ERROR: $@" >&2
     61  exit 1
     62 }
     63 
     64 fail_panic () {
     65  if [ $? != 0 ]; then panic "$@"; fi
     66 }
     67 
     68 log () {
     69  if [ "$VERBOSE" -gt 0 ]; then
     70    echo "$@"
     71  fi
     72 }
     73 
     74 DEFAULT_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
     81 PROGNAME=${ADB_LLDB_PROGNAME:-$(basename "$0")}
     82 
     83 ADB=
     84 ATTACH_DELAY=1
     85 HELP=
     86 LLDB_INIT=
     87 LLDB_SERVER=
     88 NDK_DIR=
     89 NO_PULL_LIBS=
     90 PACKAGE_NAME=
     91 PID=
     92 PORT=
     93 PROCESS_NAME=
     94 PROGRAM_NAME="activity"
     95 PULL_LIBS=
     96 PULL_LIBS_DIR=
     97 SU_PREFIX=
     98 SYMBOL_DIR=
     99 TARGET_ARCH=
    100 TOOLCHAIN=
    101 VERBOSE=0
    102 
    103 for 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
    139 done
    140 
    141 if [ "$HELP" ]; then
    142  if [ "$ADB_LLDB_PROGNAME" ]; then
    143    # Assume wrapper scripts all provide a default package name.
    144    cat <<EOF
    145 Usage: $PROGNAME [options]
    146 
    147 Attach lldb to a running Android $PROGRAM_NAME process.
    148 EOF
    149  else
    150    # Assume this is a direct call to connect_lldb.sh
    151  cat <<EOF
    152 Usage: $PROGNAME [options] [<package-name>]
    153 
    154 Attach lldb to a running Android $PROGRAM_NAME process.
    155 
    156 If provided, <package-name> must be the name of the Android application's
    157 package name to be debugged. You can also use --package-name=<name> to
    158 specify it.
    159 EOF
    160  fi
    161 
    162  cat <<EOF
    163 
    164 This script is used to debug a running $PROGRAM_NAME process.
    165 
    166 This script needs several things to work properly. It will try to pick
    167 them 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 
    173 You can also use --ndk-dir=<path> to specify an alternative NDK installation
    174 directory.
    175 
    176 The script tries to find the most recent version of the debug version of
    177 shared libraries under one of the following directories:
    178 
    179  \$CHROMIUM_SRC/<out>/lib.unstripped/     (used by GN builds)
    180 
    181 Where <out> is determined by CHROMIUM_OUTPUT_DIR, or --output-directory.
    182 
    183 You can set the path manually via --symbol-dir.
    184 
    185 The script tries to extract the target architecture from your target device,
    186 but if this fails, will default to 'arm'. Use --target-arch=<name> to force
    187 its value.
    188 
    189 Otherwise, the script will complain, but you can use the --lldb-server,
    190 --lldb and --symbol-lib options to specify everything manually.
    191 
    192 An alternative to --lldb=<file> is to use --toolchain=<path> to specify
    193 the path to the host target-specific cross-toolchain.
    194 
    195 You will also need the 'adb' tool in your path. Otherwise, use the --adb
    196 option. The script will complain if there is more than one device connected
    197 and a device is not specified with either --device or ANDROID_SERIAL).
    198 
    199 The first time you use it on a device, the script will pull many system
    200 libraries required by the process into a temporary directory. This
    201 is done to strongly improve the debugging experience, like allowing
    202 readable thread stacks and more. The libraries are copied to the following
    203 directory by default:
    204 
    205  $DEFAULT_PULL_LIBS_DIR/
    206 
    207 But you can use the --pull-libs-dir=<path> option to specify an
    208 alternative. The script can detect when you change the connected device,
    209 and will re-pull the libraries only in this case. You can however force it
    210 with the --pull-libs option.
    211 
    212 Any local .lldb-init script will be ignored, but it is possible to pass a
    213 lldb command script with the --source=<file> option. Note that its commands
    214 will be passed to lldb after the remote connection and library symbol
    215 loading have completed.
    216 
    217 Valid 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 
    249 EOF
    250  exit 0
    251 fi
    252 
    253 if [ -z "$PACKAGE_NAME" ]; then
    254  panic "Please specify a package name on the command line. See --help."
    255 fi
    256 
    257 if [[ -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
    267 fi
    268 
    269 if 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."
    272 fi
    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
    278 detect_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 
    295 if [ -z "$SYMBOL_DIR" ]; then
    296  detect_symbol_dir
    297 elif [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then
    298  panic "Could not find any symbols under $SYMBOL_DIR"
    299 fi
    300 
    301 if [ -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,)')
    304 else
    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
    312 fi
    313 
    314 if [ "$LLDB_INIT" -a ! -f "$LLDB_INIT" ]; then
    315  panic "Unknown --source file: $LLDB_INIT"
    316 fi
    317 
    318 # Checks that ADB is in our path
    319 if [ -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"
    326 fi
    327 
    328 # Checks that it works minimally
    329 ADB_VERSION=$($ADB version 2>/dev/null)
    330 echo "$ADB_VERSION" | fgrep -q -e "Android Debug Bridge"
    331 if [ $? != 0 ]; then
    332  panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
    333 different one: $ADB"
    334 fi
    335 
    336 # If there are more than one device connected, and ANDROID_SERIAL is not
    337 # defined, prints an error message.
    338 NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l)
    339 if [ "$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
    343 fi
    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().
    353 adb_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.
    385 get_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 
    400 if [ -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"
    406 else
    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
    414 fi
    415 
    416 # Translates GN target architecure to NDK subdirectory name.
    417 # $1: GN target architecture.
    418 # Out: NDK subdirectory name.
    419 get_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')
    429 get_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')
    444 get_ndk_host_arch () {
    445  echo "x86_64"
    446 }
    447 
    448 # $1: NDK install path.
    449 get_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.
    458 get_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
    477 if [ -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"
    484 fi
    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.
    489 if [ -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 \
    493 valid one!"
    494  fi
    495  log "Auto-config: --lldb-server=$LLDB_SERVER"
    496 fi
    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.
    501 TMP_ID=$$
    502 
    503 # Temporary directory, will get cleaned up on exit.
    504 TMPDIR=/tmp/$USER-adb-lldb-tmp-$TMP_ID
    505 mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/*
    506 
    507 LLDB_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
    512 get_file_timestamp () {
    513  stat -c %Y "$1" 2>/dev/null
    514 }
    515 
    516 # Allow several concurrent debugging sessions
    517 APP_DATA_DIR=$(adb_shell run-as $PACKAGE_NAME /system/bin/sh -c pwd)
    518 if [ $? != 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)
    522 fi
    523 log "App data dir: $APP_DATA_DIR"
    524 TARGET_LLDB_SERVER="$APP_DATA_DIR/lldb-server-adb-lldb-$TMP_ID"
    525 TMP_TARGET_LLDB_SERVER=/data/local/tmp/lldb-server-adb-lldb-$TMP_ID
    526 
    527 # Select correct app_process for architecture.
    528 case $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!";;
    532 esac
    533 
    534 # Default to app_process if bit-width specific process isn't found.
    535 adb_shell ls /system/bin/$LLDBEXEC > /dev/null
    536 if [ $? != 0 ]; then
    537    LLDBEXEC=app_process
    538 fi
    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.
    542 LLDBEXEC_ASAN=app_process.real
    543 adb_shell ls /system/bin/$LLDBEXEC_ASAN > /dev/null
    544 if [ $? == 0 ]; then
    545    LLDBEXEC=$LLDBEXEC_ASAN
    546 fi
    547 
    548 ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR
    549 if [[ -n "$ANDROID_SERIAL" ]]; then
    550  DEFAULT_PULL_LIBS_DIR="$DEFAULT_PULL_LIBS_DIR/$ANDROID_SERIAL-$SUFFIX_64_BIT"
    551 fi
    552 PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
    553 
    554 HOST_FINGERPRINT=
    555 DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
    556 [[ "$DEVICE_FINGERPRINT" ]] || panic "Failed to get the device fingerprint"
    557 log "Device build fingerprint: $DEVICE_FINGERPRINT"
    558 
    559 if [ ! -f "$PULL_LIBS_DIR/build.fingerprint" ]; then
    560  log "Auto-config: --pull-libs  (no cached libraries)"
    561  PULL_LIBS=true
    562 else
    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
    572 fi
    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).
    576 if [ -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"
    588 fi
    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 #
    594 if [ "$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="\""
    606 else
    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
    617 fi
    618 log "Command prefix: '$COMMAND_PREFIX'"
    619 log "Command suffix: '$COMMAND_SUFFIX'"
    620 
    621 mkdir -p "$PULL_LIBS_DIR"
    622 fail_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
    627 if [ "$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"
    651 fi
    652 
    653 # Pull the app_process binary from the device.
    654 log "Pulling $LLDBEXEC from device"
    655 "$ADB" pull /system/bin/$LLDBEXEC "$TMPDIR"/$LLDBEXEC &>/dev/null
    656 fail_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.
    660 SOLIB_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.
    666 adb_shell $COMMAND_PREFIX chmod a+x $APP_DATA_DIR $COMMAND_SUFFIX
    667 
    668 # Push lldb-server to the device
    669 log "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
    673 fail_panic "Could not copy lldb-server to the device!"
    674 
    675 if [ -z "$PORT" ]; then
    676  # Random port to allow multiple concurrent sessions.
    677  PORT=$(( $RANDOM % 1000 + 5039 ))
    678 fi
    679 HOST_PORT=$PORT
    680 TARGET_DOMAIN_SOCKET=$APP_DATA_DIR/lldb-socket-$HOST_PORT
    681 
    682 # Setup network redirection
    683 log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_DOMAIN_SOCKET)"
    684 "$ADB" forward tcp:$HOST_PORT localfilesystem:$TARGET_DOMAIN_SOCKET
    685 fail_panic "Could not setup network redirection from \
    686 host: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 
    695 for 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
    732 done
    733 
    734 # Generate a file containing useful LLDB initialization commands
    735 readonly COMMANDS=$TMPDIR/lldb.init
    736 log "Generating LLDB initialization commands file: $COMMANDS"
    737 cat > "$COMMANDS" <<EOF
    738 settings append target.exec-search-paths $SYMBOL_DIR $SOLIB_DIRS $PULL_LIBS_DIR
    739 settings set target.source-map ../.. $CHROMIUM_SRC
    740 target create '$TMPDIR/$LLDBEXEC'
    741 target modules search-paths add / $TMPDIR/$LLDBEXEC/
    742 script print("Connecting to :$HOST_PORT... (symbol load can take a while)")
    743 gdb-remote $HOST_PORT
    744 EOF
    745 
    746 if [ "$LLDB_INIT" ]; then
    747  cat "$LLDB_INIT" >> "$COMMANDS"
    748 fi
    749 
    750 if [ "$VERBOSE" -gt 0 ]; then
    751  echo "### START $COMMANDS"
    752  cat "$COMMANDS"
    753  echo "### END $COMMANDS"
    754 fi
    755 
    756 log "Launching lldb client: $LLDB $LLDB_ARGS --source $COMMANDS"
    757 echo "Server log: $LLDB_SERVER_LOG"
    758 $LLDB $LLDB_ARGS --source "$COMMANDS"