blob: 9db9575512d0ac0000e3f44728f94bad18a3df4f [file] [log] [blame]
#!/bin/bash
# Copyright 2019 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#### CATEGORY=Run, inspect and debug
### run fidlcat on given target.
## Runs fidlcat in the given configuration; currently, fidlcat logs all FIDL
## chatter from the given target executable. Starts the debug agent on the
## proposed target, and closes the debug agent on exit.
##
## CAUTION: This support is experimental, and invocation strategy is likely to
## change. The component launching configuration is *especially* likely to go
## away over time.
##
## TROUBLESHOOTING TIPS:
##
## - Remember to use "fx set-device" when working with multiple devices.
## - This scripts by default will mute the SSH connection stdout/stderr, so any
## errors triggered by it won't appear. Use the --debug-mode flag to see
## the debug log's from the debug agent and fidlcat.
## - This scripts uses the tool "nc" for testing TCP connections. Check that it
## is in $PATH and that it works.
##
## Usage: fx fidlcat [--port=<port>] [--with-symbol-server] [--debug-mode]
## [--symbol-path=<path>] [--fidl-ir-path=<path>] [--gdb]
## [--from=<source>] [--to=<path>] [--format=<output>]
## [--with-process-info] [--stack=<value>]
## [--syscalls=<regexp>] [--exclude-syscalls=<regexp>]
## [--messages=<regexp>] [--exclude-messages=<regexp>] [--trigger=<regexp>]
## [--dump-messages]
## [--verbose=<value> | --quiet=<value>] [--log-file <path>] [--stay-alive]
## [--remote-pid=<pid>] [--remote-name=<name>] [--extra-name=<name>]
## [run <component specification>]
##
## System options:
## --port Port the debug agent will be listening on. Will use 2345 by default.
## --with-symbol-server Connect to the symbol server. The first time you use this option,
## fidlcat will give you a link to an authentication page.
## You then have to use the generated key to authenticate.
## --debug-mode Whether the debug agent's debug logs should be shown.
## --symbol-path=<path> An extra location where fidlcat can find debug symbols.
## --fidl-ir-path=<path> An extra location where fidlcat can find FIDL compiled files.
## --gdb Launch fidlcat using gdb. This is only useful to be able to debug
## fidlcat. When this option is used, the string you have to type within
## gdb to launch fidlcat is printed and then, gdb is launched.
## This option only works if you have the unstripped version of fidlcat.
##
## Input options:
## --from=<source> This option must be used at most once.
## Source can be:
## --from=device This is the default input. The input comes from the live
## monitoring of one or several processes.
## At least one of '--remote-pid', '--remote-name', 'run' must
## be specified.
## --from=<path> The input comes from a previously recorded session (protobuf
## format). Path gives the name of the file to read. If path is
## '-' then the standard input is used.
##
## Session save option:
## --to=<path> The session is saved to the specified file (binary protobuf format).
## When a session is saved, you can replay it using "--from=<path>".
## The raw data is saved. That means that the data saved is independent from what is
## displayed.
##
## Format (output) options:
## --format=<output> You can use one of this output formats:
## --format=pretty The session is pretty printed (with colors).
## This is the default output if --with is not used.
## --format=json The session is printed using a json format.
## --format=textproto The session is printed using a text protobuf format.
## --format= Nothing is displayed on the standard output (this option
## only makes sense when used with --to=<path> or with
## --with).
## When there is no output, fidlcat is much faster (this is
## better when you want to monitor real time components).
## This is the default output is --with is used.
##
## Extra generation:
## These options can be used several times.
## --with=summary At the end of the session, a summary of the session is displayed on the
## standard output.
## --with=summary=<path> Like --with=summary but the result is stored into the file specified by
## <path>.
## --with=top At the end of the session, generate a view that groups the output by
## process, protocol, and method. The groups are sorted by number of
## events, so groups with more associated events are listed earlier.
## --with=top=<path> Like --with=top but the result is stored into the file specified by
## <path>.
##
## Display options:
## --with-process-info Display the process name, process id and thread id on
## each line (useful for grep).
## --stack=<value> Define the amount of stack frame to display
## 0: none (default value)
## 1: call site (1 to 4 levels)
## 2: full stack frame (adds some overhead)
## --syscalls=<regexp> A regular expression which selects the syscalls to decode and
## display.
## Can be passed multiple times.
## By default, only zx_channel_.* syscalls are displayed.
## To display all the syscalls, use: --syscalls ".*"
## --exclude-syscalls=<regexp> A regular expression which selects the syscalls to not decode and
## display.
## Can be passed multiple times.
## To be displayed, a syscall must verify --syscalls and not verify
## --exclude-syscalls.
## To display all the syscalls but the zx_handle syscalls, use:
## --syscalls ".*" --exclude-syscalls "zx_handle_.*"
## --messages=<regexp> A regular expression which selects the messages to display.
## To display a message, the method name must satisfy the regexp.
## This option can be specified multiple times.
## Message filtering works on the method's fully qualified name.
## --exclude-messages=<regexp> A regular expression which selects the messages to not display.
## If a message method name satisfy the regexp, the message is not
## displayed (even if it satisfies --messages).
## This option can be specified multiple times.
## Message filtering works on the method's fully qualified name.
## --trigger=<regexp> Start displaying messages and syscalls only when a message for
## which the method name satisfies the filter is found.
## This option can be specified multiple times.
## Message filtering works on the method's fully qualified name.
## --dump-messages Always does a hexadecimal dump of the messages even if we can
## decode them.
##
## Logging options:
## --verbose=<value> The log verbosity. Legal values are "info", "warning", "error", "fatal",
## or a number, starting from 0. Extra verbosity comes with higher levels.
## --quiet=<value> The log verbosity. Legal values are "info", "warning", "error", "fatal",
## or a number, starting from 0. Extra verbosity comes with lower levels.
## --log-file=<path> The log file destination.
## --stay-alive Don't quit fidlcat when all the monitored processes have ended. This allows
## to keep monitoring upcoming process. At the end you have to use control-c
## to quit fidlcat. This is useful when you monitor a process and restart this
## process.
##
## Monitoring options:
## --remote-pid=<pid> The koid of the remote process to trace.
## --remote-name=<name> A set of comma-separated regexes. Fidlcat will monitor all existing
## and future processes whose names match one of the regexes.
## Can be provided multiple times for multiple regexes.
## --extra-name=<name> Like --remote-name, it monitors some processes. However, for these
## processes, monitoring starts only when one of of the "--remote-name"
## process is launched. Also, fidlcat stops when the last "--remote-name"
## process stops (even if some "--extra-name" processes are still
## monitored).
## run <component spec> A token indicating that you want to invoke and trace the following
## component. The component is specified with either a bash regex that
## matches a component URL known to the build, or a full component URL not
## known to your build, but available to your target.
##
## Flags after -- are parsed by fidlcat.
##
## Example usage:
##
## # Attaches to the process with the given pid on the target:
## fx fidlcat --remote-pid=4755
##
## # Launches the echo client, and monitors its FIDL chatter:
## fx fidlcat run fuchsia-pkg://fuchsia.com/echo_client_cpp#meta/echo_client_cpp.cmx
##
## # Also launches the echo client, and monitors its FIDL chatter:
## fx fidlcat run echo_client_cpp.cmx
##
## # Will trace existing and future processes whose name contains "echo_client"
## fx fidlcat --remote-name=echo_client
##
## All options --remote-pid, --remote-name, --extra-name and, run can be used together.
## However, run must always be the last one.
## When --remote-name and run are used together, only processes which match --remote-name are
## monitored.
##
## Examples (echo_server is launched by echo_client):
##
## # run and monitor echo_client.
## fx fidlcat run echo_client_cpp.cmx
##
## # run and monitor echo_client.
## fx fidlcat --remote-name=echo_client run echo_client_cpp.cmx
##
## # run echo_client and monitor echo_server.
## fx fidlcat --remote-name=echo_server run echo_client_cpp.cmx
##
## # run echo_client and monitor echo_client and echo_server.
## fx fidlcat --remote-name=echo run echo_client_cpp.cmx
##
## # run echo_client and monitor echo_client and echo_server.
## fx fidlcat --remote-name=echo_client --remote-name=echo_server run echo_client_cpp.cmx
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/../lib/vars.sh || exit $?
fx-config-read
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/debug-agent.sh || exit $?
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)"/lib/symbol-index.sh || exit $?
launch_agent=1
action=
arguments=("--symbol-server=gs://fuchsia-artifacts-release/debug")
use_gdb=0
equal_argument() {
if [[ $1 != "$2"* ]]; then
return 1
fi
if [[ $1 != "$2="* ]]; then
echo "Flag $2 must be followed by an equal sign: $2=$3"
exit 1
fi
return 0
}
# Options for the zxdb client.
agent_out="/dev/null"
debug_mode=
while [[ $# -gt 0 ]]; do
if [[ $1 == "--help" || $1 == "-h" ]]; then
fx-command-help
exit 0
elif equal_argument $1 "--port" "<port>"; then
port=$(echo $1 | cut -c 8-)
echo $port
elif [[ $1 == "--with-symbol-server" ]]; then
echo "--with-symbol-server option is now implicit. You don't need it anymore."
elif [[ $1 == "--debug-mode" ]]; then
agent_out="/dev/stdout"
debug_mode="--debug-mode"
elif equal_argument $1 "--symbol-path" "<path>"; then
arguments+=("$1")
elif equal_argument $1 "--fidl-ir-path" "<path>"; then
arguments+=("$1")
elif [[ $1 == "--gdb" ]]; then
use_gdb=1
elif [[ $1 == "--from=device" ]]; then
arguments+=("$1")
elif equal_argument $1 "--from" "<source>"; then
arguments+=("$1")
launch_agent=0
elif equal_argument $1 "--to" "<path>"; then
arguments+=("$1")
elif [[ $1 == "--format=" ]]; then
arguments+=("--format=none")
elif equal_argument $1 "--format" "<output>"; then
arguments+=("$1")
elif equal_argument $1 "--with" "<option>"; then
arguments+=("$1")
elif [[ $1 == "--with-process-info" ]]; then
arguments+=("$1")
elif equal_argument $1 "--stack" "<value>"; then
arguments+=("$1")
elif equal_argument $1 "--syscalls" "<regexp>"; then
arguments+=("$1")
elif equal_argument $1 "--exclude-syscalls" "<regexp>"; then
arguments+=("$1")
elif equal_argument $1 "--messages" "<regexp>"; then
arguments+=("$1")
elif equal_argument $1 "--exclude-messages" "<regexp>"; then
arguments+=("$1")
elif equal_argument $1 "--trigger" "<regexp>"; then
arguments+=("$1")
elif [[ $1 == "--dump-messages" ]]; then
arguments+=("$1")
elif equal_argument $1 "--verbose" "<value>"; then
arguments+=("$1")
elif equal_argument $1 "--quiet" "<value>"; then
arguments+=("$1")
elif equal_argument $1 "--log-file" "<path>"; then
arguments+=("$1")
elif [[ $1 == "--stay-alive" ]]; then
arguments+=("$1")
elif equal_argument $1 "--remote-pid" "<pid>"; then
arguments+=("$1")
elif equal_argument $1 "--remote-name" "<name>"; then
arguments+=("$1")
elif equal_argument $1 "--extra-name" "<name>"; then
arguments+=("$1")
elif [[ $1 == "run" ]]; then
action="$1"
shift
break # Remaining flags are passed to fidlcat, with processing below
elif [[ $1 == "--" ]]; then
shift
break # Remaining flags are passed to fidlcat
else
echo "Invalid flag $1"
exit 1
fi
shift
done
# Infer the package URL from a regex-specified name.
package_file="${FUCHSIA_BUILD_DIR}/component_index_metadata"
if [[ "${action}" == "run" ]]; then
component=$1
components=()
all_pkgs="$(cat "${package_file}")"
if [[ -n "${all_pkgs}" ]]; then
for pkg in ${all_pkgs}; do
if [[ "${pkg}" =~ ${component} ]]; then
components+=("${pkg}")
fi
done
else
# If there aren't any packages in the component_index_metadata file, then
# assume the users know what they are doing. fidlcat should complain.
components+=("${component}")
fi
if [[ ${#components[@]} = 0 ]]; then
fx-error "Package $component is not known to the current build configuration."
fx-error "Check \`fx list-packages\` for the correct name,"
fx-error "or adjust the build configuration with \`fx set\`."
exit 1
elif [[ ${#components[@]} -gt 1 ]]; then
fx-error "Ambiguous match: $component matches the following ${#components[@]} packages:"
for component in "${components[@]}"; do
fx-error " $component"
done
exit 1
fi
component="${components[0]}"
shift
# We have now removed "run <partial component URL regex>" from the remaining
# positional parameters. The following set command replaces them with "run
# <full component URL>".
set - "$@" "run" "${component}"
fi
if [[ -z "${port}" ]]; then
port=2345
fi
ensure-symbol-index-registered || echo "Failed to register ${FUCHSIA_DIR} in symbol-index!"
if [[ ${launch_agent} -eq 1 ]]; then
if launch_debug_agent "${port}" "" "${agent_out}"; then
arguments+=("--connect" "$(get-device-addr-resource):${port}")
arguments+=("--fidl-ir-path" @"${FUCHSIA_BUILD_DIR}"/all_fidl_json.txt)
arguments+=("--quit-agent-on-exit")
arguments+=("$@")
if [[ ${use_gdb} -eq 1 ]]; then
# Starts gdb.
gdb --args ${FUCHSIA_BUILD_DIR}/host_x64/exe.unstripped/fidlcat ${arguments[@]}
else
# Now that the debug agent is launched, starts fidlcat.
"${FUCHSIA_BUILD_DIR}/host-tools/fidlcat" ${arguments[@]}
fi
# --quit-agent-on-exit should quit the debug_agent so we just need to wait for ssh to terminate.
wait
else
fx-error "Could not launch debug agent. Exiting. Make sure you're running 'fx serve'."
exit 1
fi
else
arguments+=("--fidl-ir-path" @"${FUCHSIA_BUILD_DIR}"/all_fidl_json.txt)
arguments+=("$@")
if [[ ${use_gdb} -eq 1 ]]; then
# Starts gdb.
gdb --args ${FUCHSIA_BUILD_DIR}/host_x64/exe.unstripped/fidlcat ${arguments[@]}
else
# Now that the debug agent is launched, starts fidlcat.
"${FUCHSIA_BUILD_DIR}/host-tools/fidlcat" ${arguments[@]}
fi
fi