#!/bin/bash # # Copyright 2023 The Chromium Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. #
# A generic script used to attach to a running Chromium process and debug it. # Most users should not use this directly, but one of the wrapper scripts like # connect_lldb.sh_content_shell # # Use --help to print full usage instructions. #
PROGNAME=$(basename "$0")
PROGDIR=$(dirname "$0")
# Force locale to C to allow recognizing output from subprocesses.
LC_ALL=C
# NOTE: Allow wrapper scripts to set various default through ADB_LLDB_XXX # environment variables. This is only for cosmetic reasons, i.e. to # display proper default in the --help output.
# Allow wrapper scripts to set the program name through ADB_LLDB_PROGNAME
PROGNAME=${ADB_LLDB_PROGNAME:-$(basename "$0")}
for opt; do
optarg=$(expr "x$opt" : 'x[^=]*=\(.*\)')
case $opt in
--adb=*) ADB=$optarg ;;
--attach-delay=*) ATTACH_DELAY=$optarg ;;
--device=*) export ANDROID_SERIAL=$optarg ;;
--help|-h|-?) HELP=true ;;
--lldb=*) LLDB=$optarg ;;
--lldb-server=*) LLDB_SERVER=$optarg ;;
--ndk-dir=*) NDK_DIR=$optarg ;;
--no-pull-libs) NO_PULL_LIBS=true ;;
--output-directory=*) CHROMIUM_OUTPUT_DIR=$optarg ;;
--package-name=*) PACKAGE_NAME=$optarg ;;
--pid=*) PID=$optarg ;;
--port=*) PORT=$optarg ;;
--process-name=*) PROCESS_NAME=$optarg ;;
--program-name=*) PROGRAM_NAME=$optarg ;;
--pull-libs) PULL_LIBS=true ;;
--pull-libs-dir=*) PULL_LIBS_DIR=$optarg ;;
--source=*) LLDB_INIT=$optarg ;;
--su-prefix=*) SU_PREFIX=$optarg ;;
--symbol-dir=*) SYMBOL_DIR=$optarg ;;
--target-arch=*) TARGET_ARCH=$optarg ;;
--toolchain=*) TOOLCHAIN=$optarg ;;
--verbose) VERBOSE=$(( $VERBOSE + 1 )) ;;
-*)
panic "Unknown option $opt, see --help." >&2
;;
*) if [ "$PACKAGE_NAME" ]; then
panic "You can only provide a single package name as argument!\
See --help." fi
PACKAGE_NAME=$opt
;;
esac done
if [ "$HELP" ]; then if [ "$ADB_LLDB_PROGNAME" ]; then # Assume wrapper scripts all provide a default package name. cat <<EOF
Usage: $PROGNAME [options]
Attach lldb to a running Android $PROGRAM_NAME process.
EOF else # Assume this is a direct call to connect_lldb.sh cat <<EOF
Usage: $PROGNAME [options] [<package-name>]
Attach lldb to a running Android $PROGRAM_NAME process.
If provided, <package-name> must be the name of the Android application's
package name to be debugged. You can also use --package-name=<name> to
specify it.
EOF fi
cat <<EOF
This script is used to debug a running $PROGRAM_NAME process.
This script needs several things to work properly. It will try to pick
them up automatically for you though:
- target lldb-server binary
- host lldb client, possibly a wrapper (e.g. lldb.sh)
- directory with symbolic version of $PROGRAM_NAME's shared libraries.
You can also use --ndk-dir=<path> to specify an alternative NDK installation
directory.
The script tries to find the most recent version of the debug version of
shared libraries under one of the following directories:
\$CHROMIUM_SRC/<out>/lib.unstripped/ (used by GN builds)
Where <out> is determined by CHROMIUM_OUTPUT_DIR, or --output-directory.
You can set the path manually via --symbol-dir.
The script tries to extract the target architecture from your target device,
but if this fails, will default to 'arm'. Use --target-arch=<name> to force
its value.
Otherwise, the script will complain, but you can use the --lldb-server,
--lldb and --symbol-lib options to specify everything manually.
An alternative to --lldb=<file> is to use --toolchain=<path> to specify
the path to the host target-specific cross-toolchain.
You will also need the 'adb' tool in your path. Otherwise, use the --adb
option. The script will complain if there is more than one device connected
and a device is not specified with either --device or ANDROID_SERIAL).
The first time you use it on a device, the script will pull many system
libraries required by the process into a temporary directory. This
is done to strongly improve the debugging experience, like allowing
readable thread stacks and more. The libraries are copied to the following
directory by default:
$DEFAULT_PULL_LIBS_DIR/
But you can use the --pull-libs-dir=<path> option to specify an
alternative. The script can detect when you change the connected device,
and will re-pull the libraries only in this case. You can however force it
with the --pull-libs option.
Any local .lldb-init script will be ignored, but it is possible to pass a
lldb command script with the --source=<file> option. Note that its commands
will be passed to lldb after the remote connection and library symbol
loading have completed.
Valid options:
--help|-h|-? Print this message.
--verbose Increase verbosity.
--symbol-dir=<path> Specify directory with symbol shared libraries.
--output-directory=<path> Specify the output directory (e.g. "out/Debug").
--package-name=<name> Specify package name (alternative to 1st argument).
--program-name=<name> Specify program name (cosmetic only).
--process-name=<name> Specify process name to attach to (uses package-name if not passsed).
--pid=<pid> Specify application process pid.
--attach-delay=<num> Seconds to wait for lldb-server to attach to the
remote process before starting lldb. Default 1.
<num> may be a float if your sleep(1) supports it.
--source=<file> Specify extra LLDB init script.
--lldb-server=<file> Specify target lldb-server binary.
--lldb=<file> Specify host lldb client binary.
--target-arch=<name> Specify NDK target arch.
--adb=<file> Specify host ADB binary.
--device=<file> ADB device serial to use (-s flag).
--port=<port> Specify the tcp port to use.
--su-prefix=<prefix> Prepend <prefix> to 'adb shell' commands that are
run by this script. This can be useful to use
the 'su' program on rooted production devices.
e.g. --su-prefix="su -c"
--pull-libs Force system libraries extraction.
--no-pull-libs Do not extract any system library.
--libs-dir=<path> Specify system libraries extraction directory.
EOF
exit 0 fi
if [ -z "$PACKAGE_NAME" ]; then
panic "Please specify a package name on the command line. See --help." fi
if [[ -z "$SYMBOL_DIR" && -z "$CHROMIUM_OUTPUT_DIR" ]]; then if [[ -e "build.ninja" ]]; then
CHROMIUM_OUTPUT_DIR=$PWD else
panic "Please specify an output directory by using one of:
--output-directory=out/Debug
CHROMIUM_OUTPUT_DIR=out/Debug
Setting working directory to an output directory.
See --help." fi fi
if ls *.so >/dev/null 2>&1; then
panic ".so files found in your working directory. These will conflict with" \ "library lookup logic. Change your working directory and try again." fi
# Detects the build type and symbol directory. This is done by finding # the most recent sub-directory containing debug shared libraries under # $CHROMIUM_OUTPUT_DIR. # Out: nothing, but this sets SYMBOL_DIR
detect_symbol_dir () { # GN places unstripped libraries under out/lib.unstripped
local PARENT_DIR="$CHROMIUM_OUTPUT_DIR" if [[ ! -e "$PARENT_DIR" ]]; then
PARENT_DIR="$CHROMIUM_SRC/$PARENT_DIR" fi
SYMBOL_DIR="$PARENT_DIR/lib.unstripped" if [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then
SYMBOL_DIR="$PARENT_DIR/lib" if [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then
panic "Could not find any symbols under \
$PARENT_DIR/lib{.unstripped}. Please build the program first!" fi fi
log "Auto-config: --symbol-dir=$SYMBOL_DIR"
}
if [ -z "$SYMBOL_DIR" ]; then
detect_symbol_dir elif [[ -z "$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null)" ]]; then
panic "Could not find any symbols under $SYMBOL_DIR" fi
if [ -z "$NDK_DIR" ]; then
ANDROID_NDK_ROOT=$(PYTHONPATH=$CHROMIUM_SRC/build/android python3 -c \ 'from pylib.constants import ANDROID_NDK_ROOT; print(ANDROID_NDK_ROOT,)') else if [ ! -d "$NDK_DIR" ]; then
panic "Invalid directory: $NDK_DIR" fi if [ ! -d "$NDK_DIR/toolchains" ]; then
panic "Not a valid NDK directory: $NDK_DIR" fi
ANDROID_NDK_ROOT=$NDK_DIR fi
if [ "$LLDB_INIT" -a ! -f "$LLDB_INIT" ]; then
panic "Unknown --source file: $LLDB_INIT" fi
# Checks that ADB is in our path if [ -z "$ADB" ]; then
ADB=$(which adb 2>/dev/null) if [ -z "$ADB" ]; then
panic "Can't find 'adb' tool in your path. Install it or use \
--adb=<file>" fi
log "Auto-config: --adb=$ADB" fi
# Checks that it works minimally
ADB_VERSION=$($ADB version 2>/dev/null) echo"$ADB_VERSION" | fgrep -q -e "Android Debug Bridge" if [ $? != 0 ]; then
panic "Your 'adb' tool seems invalid, use --adb=<file> to specify a \
different one: $ADB" fi
# If there are more than one device connected, and ANDROID_SERIAL is not # defined, prints an error message.
NUM_DEVICES_PLUS2=$($ADB devices 2>/dev/null | wc -l) if [ "$NUM_DEVICES_PLUS2" -gt 3 -a -z "$ANDROID_SERIAL" ]; then echo"ERROR: There is more than one Android device connected to ADB." echo"Please define ANDROID_SERIAL to specify which one to use."
exit 1 fi
# Runs a command through adb shell, strip the extra \r from the output # and return the correct status code to detect failures. This assumes # that the adb shell command prints a final \n to stdout. # $1+: command to run # Out: command's stdout # Return: command's status # Note: the command's stderr is lost # Info: In Python would be done via DeviceUtils.RunShellCommand().
adb_shell () {
local TMPOUT="$(mktemp)"
local LASTLINE RET
local ADB=${ADB:-adb}
# The weird sed rule is to strip the final \r on each output line # Since 'adb shell' never returns the command's proper exit/status code, # we force it to print it as '%%<status>' in the temporary output file, # which we will later strip from it.
$ADB shell $@ ";"echo"%%\$?"2>/dev/null | \
sed -e 's![[:cntrl:]]!!g' > $TMPOUT # Get last line in log, which contains the exit code from the command
LASTLINE=$(sed -e '$!d' $TMPOUT) # Extract the status code from the end of the line, which must # be '%%<code>'.
RET=$(echo"$LASTLINE" | \
awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,RSTART+2); } }') # Remove the status code from the last line. Note that this may result # in an empty line.
LASTLINE=$(echo"$LASTLINE" | \
awk '{ if (match($0, "%%[0-9]+$")) { print substr($0,1,RSTART-1); } }') # The output itself: all lines except the status code.
sed -e '$d' $TMPOUT && printf "%s""$LASTLINE" # Remove temp file. rm -f $TMPOUT # Exit with the appropriate status.
return $RET
}
# Finds the target architecture from a local shared library. # This returns an NDK-compatible architecture name. # Out: NDK Architecture name, or empty string.
get_gn_target_arch () { # ls prints a broken pipe error when there are a lot of libs.
local RANDOM_LIB=$(ls "$SYMBOL_DIR"/lib*.so 2>/dev/null| head -n1)
local SO_DESC=$(file $RANDOM_LIB)
case $SO_DESC in
*32-bit*ARM,*) echo"arm";;
*64-bit*ARM,*) echo"arm64";;
*64-bit*aarch64,*) echo"arm64";;
*32-bit*Intel,*) echo"x86";;
*x86-64,*) echo"x86_64";;
*32-bit*MIPS,*) echo"mips";;
*) echo"";
esac
}
if [ -z "$TARGET_ARCH" ]; then
TARGET_ARCH=$(get_gn_target_arch) if [ -z "$TARGET_ARCH" ]; then
TARGET_ARCH=arm fi
log "Auto-config: --arch=$TARGET_ARCH" else # Nit: accept Chromium's 'ia32' as a valid target architecture. This # script prefers the NDK 'x86' name instead because it uses it to find # NDK-specific files (host lldb) with it. if [ "$TARGET_ARCH" = "ia32" ]; then
TARGET_ARCH=x86
log "Auto-config: --arch=$TARGET_ARCH (equivalent to ia32)" fi fi
# Translates GN target architecure to NDK subdirectory name. # $1: GN target architecture. # Out: NDK subdirectory name.
get_ndk_arch_dir () {
case "$1" in
arm64) echo"aarch64";;
x86) echo"i386";;
*) echo"$1";
esac
}
# Detects the NDK system name, i.e. the name used to identify the host. # out: NDK system name (e.g. 'linux' or 'darwin')
get_ndk_host_system () {
local HOST_OS if [ -z "$NDK_HOST_SYSTEM" ]; then
HOST_OS=$(uname -s)
case $HOST_OS in
Linux) NDK_HOST_SYSTEM=linux;;
Darwin) NDK_HOST_SYSTEM=darwin;;
*) panic "You can't run this script on this system: $HOST_OS";;
esac fi echo"$NDK_HOST_SYSTEM"
}
# Detects the NDK host architecture name. # out: NDK arch name (e.g. 'x86_64')
get_ndk_host_arch () { echo"x86_64"
}
# $1: NDK install path.
get_ndk_host_lldb_client() {
local NDK_DIR="$1"
local HOST_OS=$(get_ndk_host_system)
local HOST_ARCH=$(get_ndk_host_arch) echo"$NDK_DIR/toolchains/llvm/prebuilt/$HOST_OS-$HOST_ARCH/bin/lldb.sh"
}
# $1: NDK install path. # $2: target architecture.
get_ndk_lldb_server () {
local NDK_DIR="$1"
local ARCH=$2
local HOST_OS=$(get_ndk_host_system)
local HOST_ARCH=$(get_ndk_host_arch)
local NDK_ARCH_DIR=$(get_ndk_arch_dir "$ARCH")
local i # For lldb-server is under lib64/ for r25, and lib/ for r26+. for i in "lib64""lib"; do
local RET=$(realpath -m $NDK_DIR/toolchains/llvm/prebuilt/$HOST_OS-$HOST_ARCH/$i/clang/*/lib/linux/$NDK_ARCH_DIR/lldb-server) if [ -e "$RET" ]; then echo $RET
return 0 fi done
return 1
}
# Find host LLDB client binary if [ -z "$LLDB" ]; then
LLDB=$(get_ndk_host_lldb_client "$ANDROID_NDK_ROOT") if [ -z "$LLDB" ]; then
panic "Can't find Android lldb client in your path, check your \
--toolchain or --lldb path." fi
log "Host lldb client: $LLDB" fi
# Find lldb-server binary, we will later push it to /data/local/tmp # This ensures that both lldb-server and $LLDB talk the same binary protocol, # otherwise weird problems will appear. if [ -z "$LLDB_SERVER" ]; then
LLDB_SERVER=$(get_ndk_lldb_server "$ANDROID_NDK_ROOT""$TARGET_ARCH") if [ -z "$LLDB_SERVER" ]; then
panic "Can't find NDK lldb-server binary. use --lldb-server to specify \
valid one!" fi
log "Auto-config: --lldb-server=$LLDB_SERVER" fi
# A unique ID for this script's session. This needs to be the same in all # sub-shell commands we're going to launch, so take the PID of the launcher # process.
TMP_ID=$$
# Temporary directory, will get cleaned up on exit.
TMPDIR=/tmp/$USER-adb-lldb-tmp-$TMP_ID
mkdir -p "$TMPDIR" && rm -rf "$TMPDIR"/*
# Returns the timestamp of a given file, as number of seconds since epoch. # $1: file path # Out: file timestamp
get_file_timestamp () {
stat -c %Y "$1"2>/dev/null
}
# Allow several concurrent debugging sessions
APP_DATA_DIR=$(adb_shell run-as $PACKAGE_NAME /system/bin/sh -c pwd) if [ $? != 0 ]; then echo"Failed to run-as $PACKAGE_NAME, is the app debuggable?"
APP_DATA_DIR=$(adb_shell dumpsys package $PACKAGE_NAME | \
sed -ne 's/^ \+dataDir=//p' | head -n1) fi
log "App data dir: $APP_DATA_DIR"
TARGET_LLDB_SERVER="$APP_DATA_DIR/lldb-server-adb-lldb-$TMP_ID"
TMP_TARGET_LLDB_SERVER=/data/local/tmp/lldb-server-adb-lldb-$TMP_ID
# Select correct app_process for architecture.
case $TARGET_ARCH in
arm|x86|mips) LLDBEXEC=app_process32;;
arm64|x86_64) LLDBEXEC=app_process64; SUFFIX_64_BIT=64;;
*) panic "Unknown app_process for architecture!";;
esac
# Default to app_process if bit-width specific process isn't found.
adb_shell ls /system/bin/$LLDBEXEC > /dev/null if [ $? != 0 ]; then
LLDBEXEC=app_process fi
# Detect AddressSanitizer setup on the device. In that case app_process is a # script, and the real executable is app_process.real.
LLDBEXEC_ASAN=app_process.real
adb_shell ls /system/bin/$LLDBEXEC_ASAN > /dev/null if [ $? == 0 ]; then
LLDBEXEC=$LLDBEXEC_ASAN fi
ORG_PULL_LIBS_DIR=$PULL_LIBS_DIR if [[ -n "$ANDROID_SERIAL" ]]; then
DEFAULT_PULL_LIBS_DIR="$DEFAULT_PULL_LIBS_DIR/$ANDROID_SERIAL-$SUFFIX_64_BIT" fi
PULL_LIBS_DIR=${PULL_LIBS_DIR:-$DEFAULT_PULL_LIBS_DIR}
HOST_FINGERPRINT=
DEVICE_FINGERPRINT=$(adb_shell getprop ro.build.fingerprint)
[[ "$DEVICE_FINGERPRINT" ]] || panic "Failed to get the device fingerprint"
log "Device build fingerprint: $DEVICE_FINGERPRINT"
if [ ! -f "$PULL_LIBS_DIR/build.fingerprint" ]; then
log "Auto-config: --pull-libs (no cached libraries)"
PULL_LIBS=true else
HOST_FINGERPRINT=$(< "$PULL_LIBS_DIR/build.fingerprint")
log "Host build fingerprint: $HOST_FINGERPRINT" if [ "$HOST_FINGERPRINT" == "$DEVICE_FINGERPRINT" ]; then
log "Auto-config: --no-pull-libs (fingerprint match)"
NO_PULL_LIBS=true else
log "Auto-config: --pull-libs (fingerprint mismatch)"
PULL_LIBS=true fi fi
# Get the PID from the first argument or else find the PID of the # browser process (or the process named by $PROCESS_NAME). if [ -z "$PID" ]; then if [ -z "$PROCESS_NAME" ]; then
PROCESS_NAME=$PACKAGE_NAME fi if [ -z "$PID" ]; then
PID=$(adb_shell ps | \
awk '$9 == "'$PROCESS_NAME'" { print $2; }' | head -1) fi if [ -z "$PID" ]; then
panic "Can't find application process PID." fi
log "Found process PID: $PID" fi
# Determine if 'adb shell' runs as root or not. # If so, we can launch lldb-server directly, otherwise, we have to # use run-as $PACKAGE_NAME ..., which requires the package to be debuggable. # if [ "$SU_PREFIX" ]; then # Need to check that this works properly.
SU_PREFIX_TEST_LOG=$TMPDIR/su-prefix.log
adb_shell $SU_PREFIX \"echo "foo"\" > $SU_PREFIX_TEST_LOG 2>&1 if [ $? != 0 -o "$(cat $SU_PREFIX_TEST_LOG)" != "foo" ]; then echo"ERROR: Cannot use '$SU_PREFIX' as a valid su prefix:" echo"$ adb shell $SU_PREFIX \"echo foo\"" cat $SU_PREFIX_TEST_LOG
exit 1 fi
COMMAND_PREFIX="$SU_PREFIX \""
COMMAND_SUFFIX="\"" else
SHELL_UID=$("$ADB" shell cat /proc/self/status | \
awk '$1 == "Uid:" { print $2; }')
log "Shell UID: $SHELL_UID" if [ "$SHELL_UID" != 0 -o -n "$NO_ROOT" ]; then
COMMAND_PREFIX="run-as $PACKAGE_NAME"
COMMAND_SUFFIX= else
COMMAND_PREFIX=
COMMAND_SUFFIX= fi fi
log "Command prefix: '$COMMAND_PREFIX'"
log "Command suffix: '$COMMAND_SUFFIX'"
# Pull device's system libraries that are mapped by our process. # Pulling all system libraries is too long, so determine which ones # we need by looking at /proc/$PID/maps instead if [ "$PULL_LIBS" -a -z "$NO_PULL_LIBS" ]; then echo"Extracting system libraries into: $PULL_LIBS_DIR"
MAPPINGS=$(adb_shell $COMMAND_PREFIX cat /proc/$PID/maps $COMMAND_SUFFIX) if [ $? != 0 ]; then echo"ERROR: Could not list process's memory mappings." if [ "$SU_PREFIX" ]; then
panic "Are you sure your --su-prefix is correct?" else
panic "Use --su-prefix if the application is not debuggable." fi fi # Remove the fingerprint file in case pulling one of the libs fails. rm -f "$PULL_LIBS_DIR/build.fingerprint"
SYSTEM_LIBS=$(echo"$MAPPINGS" | \
awk '$6 ~ /\/(system|apex|vendor)\/.*\.so$/ { print $6; }' | sort -u) for SYSLIB in /system/bin/linker$SUFFIX_64_BIT $SYSTEM_LIBS; do echo"Pulling from device: $SYSLIB"
DST_FILE=$PULL_LIBS_DIR$SYSLIB
DST_DIR=$(dirname "$DST_FILE")
mkdir -p "$DST_DIR" && "$ADB" pull $SYSLIB "$DST_FILE"2>/dev/null
fail_panic "Could not pull $SYSLIB from device !?" done echo"Writing the device fingerprint" echo"$DEVICE_FINGERPRINT" > "$PULL_LIBS_DIR/build.fingerprint" fi
# Pull the app_process binary from the device.
log "Pulling $LLDBEXEC from device" "$ADB" pull /system/bin/$LLDBEXEC "$TMPDIR"/$LLDBEXEC &>/dev/null
fail_panic "Could not retrieve $LLDBEXEC from the device!"
# Find all the sub-directories of $PULL_LIBS_DIR, up to depth 4 # so we can add them to target.exec-search-paths later.
SOLIB_DIRS=$(find $PULL_LIBS_DIR -mindepth 1 -maxdepth 4 -type d | \
grep -v "^$" | tr '\n'' ')
# Applications with minSdkVersion >= 24 will have their data directories # created with rwx------ permissions, preventing adbd from forwarding to # the lldb-server socket.
adb_shell $COMMAND_PREFIX chmod a+x $APP_DATA_DIR $COMMAND_SUFFIX
# Push lldb-server to the device
log "Pushing lldb-server $LLDB_SERVER to $TARGET_LLDB_SERVER" "$ADB" push $LLDB_SERVER $TMP_TARGET_LLDB_SERVER >/dev/null && \
adb_shell $COMMAND_PREFIX cp $TMP_TARGET_LLDB_SERVER $TARGET_LLDB_SERVER $COMMAND_SUFFIX && \
adb_shell rm $TMP_TARGET_LLDB_SERVER
fail_panic "Could not copy lldb-server to the device!"
if [ -z "$PORT" ]; then # Random port to allow multiple concurrent sessions.
PORT=$(( $RANDOM % 1000 + 5039 )) fi
HOST_PORT=$PORT
TARGET_DOMAIN_SOCKET=$APP_DATA_DIR/lldb-socket-$HOST_PORT
# Setup network redirection
log "Setting network redirection (host:$HOST_PORT -> device:$TARGET_DOMAIN_SOCKET)" "$ADB" forward tcp:$HOST_PORT localfilesystem:$TARGET_DOMAIN_SOCKET
fail_panic "Could not setup network redirection from \
host:localhost:$HOST_PORT to device:$TARGET_DOMAIN_SOCKET"
# Start lldb-server in the background # Note that using run-as requires the package to be debuggable. # # If not, this will fail horribly. The alternative is to run the # program as root, which requires of course root privileges. # Maybe we should add a --root option to enable this?
for i in 12; do
log "Starting lldb-server in the background:"
LLDB_SERVER_LOG=$TMPDIR/lldb-server-$TMP_ID.log
log "adb shell $COMMAND_PREFIX $TARGET_LLDB_SERVER g \
$TARGET_DOMAIN_SOCKET \
--attach $PID $COMMAND_SUFFIX" "$ADB" shell $COMMAND_PREFIX $TARGET_LLDB_SERVER g \
$TARGET_DOMAIN_SOCKET \
--attach $PID $COMMAND_SUFFIX > $LLDB_SERVER_LOG 2>&1 &
LLDB_SERVER_JOB_PID=$!
LLDB_SERVER_PID=$(adb_shell $COMMAND_PREFIX pidof $(basename $TARGET_LLDB_SERVER)) echo"$LLDB_SERVER_JOB_PID" > $LLDB_SERVER_JOB_PIDFILE
log "background job pid: $LLDB_SERVER_JOB_PID"
# Sleep to allow lldb-server to attach to the remote process and be # ready to connect to.
log "Sleeping ${ATTACH_DELAY}s to ensure lldb-server is alive"
sleep "$ATTACH_DELAY"
log "Job control: $(jobs -l)"
STATE=$(jobs -l | awk '$2 == "'$LLDB_SERVER_JOB_PID'" { print $3; }') if [ "$STATE" != "Running" ]; then
pid_msg=$(grep "is already traced by process" $LLDB_SERVER_LOG 2>/dev/null) if [[ -n "$pid_msg" ]]; then
old_pid=${pid_msg##* }
old_pid=${old_pid//[$'\r\n']} # Trim trailing \r. echo"Killing previous lldb-server process (pid=$old_pid)"
adb_shell $COMMAND_PREFIX kill -9 $old_pid $COMMAND_SUFFIX
continue fi echo"ERROR: lldb-server either failed to run or attach to PID $PID!" echo"Here is the output from lldb-server (also try --verbose for more):" echo"===== lldb-server.log start =====" cat $LLDB_SERVER_LOG echo ="===== lldb-server.log end ======"
exit 1 fi
break done
# Generate a file containing useful LLDB initialization commands
readonly COMMANDS=$TMPDIR/lldb.init
log "Generating LLDB initialization commands file: $COMMANDS" cat > "$COMMANDS" <<EOF
settings append target.exec-search-paths $SYMBOL_DIR $SOLIB_DIRS $PULL_LIBS_DIR
settings set target.source-map ../.. $CHROMIUM_SRC
target create '$TMPDIR/$LLDBEXEC'
target modules search-paths add / $TMPDIR/$LLDBEXEC/
script print("Connecting to :$HOST_PORT... (symbol load can take a while)")
gdb-remote $HOST_PORT
EOF
if [ "$LLDB_INIT" ]; then cat"$LLDB_INIT" >> "$COMMANDS" fi
if [ "$VERBOSE" -gt 0 ]; then echo"### START $COMMANDS" cat"$COMMANDS" echo"### END $COMMANDS" fi
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.