|  | #!/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|-p) <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>] | 
|  | ##                   [--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. | 
|  | ## | 
|  | ## 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=() | 
|  |  | 
|  | use_gdb=0 | 
|  |  | 
|  | # Options for the zxdb client. | 
|  | agent_out="/dev/null" | 
|  | debug_mode= | 
|  |  | 
|  | while [[ $# -gt 0 ]]; do | 
|  | case "$1" in | 
|  | --help|-h) | 
|  | fx-command-help | 
|  | exit 0 | 
|  | ;; | 
|  | --port|-p) | 
|  | shift | 
|  | port="$1" | 
|  | ;; | 
|  | --with-symbol-server) | 
|  | arguments+=("--symbol-server") | 
|  | arguments+=("gs://fuchsia-artifacts-release/debug") | 
|  | ;; | 
|  | --debug-mode) | 
|  | agent_out="/dev/stdout" | 
|  | debug_mode="--debug-mode" | 
|  | ;; | 
|  | --symbol-path=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --fidl-ir-path=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --gdb) | 
|  | use_gdb=1 | 
|  | ;; | 
|  | --from=device) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --from=*) | 
|  | arguments+=("$1") | 
|  | launch_agent=0 | 
|  | ;; | 
|  | --to=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --format=) | 
|  | arguments+=("--format=none") | 
|  | ;; | 
|  | --format=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --with=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --with-process-info) | 
|  | arguments+=("--with-process-info") | 
|  | ;; | 
|  | --stack=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --syscalls=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --exclude-syscalls=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --messages=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --exclude-messages=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --trigger=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --dump-messages) | 
|  | arguments+=("--dump-messages") | 
|  | ;; | 
|  | --verbose=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --quiet=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --log-file=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --remote-pid=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --remote-name=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | --extra-name=*) | 
|  | arguments+=("$1") | 
|  | ;; | 
|  | run) | 
|  | action="$1" | 
|  | shift | 
|  | break # Remaining flags are passed to fidlcat, with processing below | 
|  | ;; | 
|  | --) | 
|  | shift | 
|  | break # Remaining flags are passed to fidlcat | 
|  | ;; | 
|  | *) | 
|  | echo "Invalid flag $1" | 
|  | exit 1 | 
|  | esac | 
|  | 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+=("$@") | 
|  |  | 
|  | 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 | 
|  |  | 
|  | # launch_debug_agent starts an agent in the background. Note: killing | 
|  | # the ssh session as below generally won't terminate the agent, but | 
|  | # it prevents us ending up with a zobmie on the host. | 
|  | pids=$(jobs -p) | 
|  | if [[ -n "${pids}" ]]; then | 
|  | kill "${pids}" > /dev/null >&2 | 
|  | wait | 
|  | fi | 
|  | 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 |