| #!/bin/bash |
| # Copyright 2018 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 the debug agent on target and connect to it with zxdb |
| |
| ## Starts the debug agent on the proposed target and automatically connect zxdb |
| ## to it. Will close the debug agent on exit. |
| ## |
| ## 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 --verbose-agent flag to see |
| ## the output. |
| ## - This scripts uses the tool "nc" for testing TCP connections. Check that it |
| ## is in $PATH and that it works. |
| ## |
| ## Usage: fx debug [(--core|-c) <CORE>] [--no-agent] [(--port|-p) <PORT>] |
| ## [--unwind=(aosp|ng)] [(--verbose-agent|-va)] |
| ## |
| ## --core Load a minidump file into zxdb. |
| ## --no-agent Don't start a Debug Agent. |
| ## --port Port the debug agent will be listening on. |
| ## Will use 2345 by default. |
| ## --target-core Look on the target for a minidump file taken by |
| ## crashpad, download it and load it into zxdb. |
| ## --unwind Choose the unwinder to use. Options are "ng" for "ngunwind" (Fuchsia's |
| ## fork of libunwind), or "aosp" (Android's unwinder). Defaults to "aosp". |
| ## --verbose-agent Whether the debug agent's stdout/stderr should be shown. |
| ## Useful for debugging the debugger. Yo' dawg. |
| ## |
| ## Flags after -- are parsed by zxdb. See zxdb's documentation for more |
| ## details. |
| |
| 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 $? |
| |
| # Defaults. |
| port= |
| core= |
| unwind_flag= |
| agent_out="/dev/null" |
| no_agent= |
| target_core= |
| |
| # Flag parsing. |
| while [[ $# -gt 0 ]]; do |
| case "$1" in |
| --help|-h) |
| fx-command-help |
| exit 0 |
| ;; |
| --no-agent) |
| no_agent=true |
| ;; |
| --port|-p) |
| shift |
| port="$1" |
| ;; |
| --port=*) |
| port="${1:7}" |
| ;; |
| --verbose-agent|-va) |
| agent_out="/dev/stdout" |
| ;; |
| --core|-c) |
| arg=$1 |
| shift |
| core="$1" |
| if [[ -z "${core}" ]]; then |
| echo "${arg} takes an argument" |
| exit 1 |
| fi |
| no_agent=true |
| ;; |
| --core=*) |
| core="${1:7}" |
| no_agent=true |
| ;; |
| --target-core) |
| target_core=true |
| no_agent=true |
| ;; |
| --unwind) |
| shift |
| unwind_flag="--unwind=$1" |
| ;; |
| --unwind=*) |
| unwind_flag="--unwind=${1:9}" |
| ;; |
| --) |
| shift |
| break # Remaining flags are passed to zxdb |
| ;; |
| *) |
| echo "Invalid flag $1" |
| exit 1 |
| esac |
| shift |
| done |
| |
| if [[ -n "${port}" && -n "${core}" ]]; then |
| echo "Specifying both a port and a core doesn't make sense" |
| exit 1 |
| fi |
| |
| if [[ -n "${target_core}" && -n "${core}" ]]; then |
| echo "Cannot specify a core file when fetching a core from the target" |
| exit 1; |
| fi |
| |
| if [[ -n "${port}" && -n "${target_core}" ]]; then |
| echo "Cannot specify a port file when fetching a core from the target" |
| exit 1 |
| fi |
| |
| if [[ -z "${port}" ]]; then |
| port=2345 |
| fi |
| |
| if [[ -n "${target_core}" ]]; then |
| crash_reports_cache_dir=`fx-command-run shell ls /data/cache/r/sys | grep crash_reports` |
| crash_reports_tmp_dir=`fx-command-run shell ls /tmp/r/sys | grep crash_reports` |
| if [[ -z "${crash_reports_tmp_dir}" ]] || [[ -z "${crash_reports_cache_dir}" ]]; then |
| fx-error "Could not find crash reports directory on target" |
| exit 1 |
| fi |
| |
| cache_core_names=`fx-command-run shell \ |
| "cd /data/cache/r/sys/${crash_reports_cache_dir}/reports 2>/dev/null && find . -name minidump.dmp -type f"` |
| tmp_core_names=`fx-command-run shell \ |
| "cd /tmp/r/sys/${crash_reports_tmp_dir}/reports 2>/dev/null && find . -name minidump.dmp -type f"` |
| |
| core_name="$echo "${cache_core_names[@]}" "${tmp_core_names[@]}"" |
| |
| if [[ -z "${core_name}" ]]; then |
| fx-error "No cores available on device" |
| exit 1 |
| fi |
| |
| if [[ "$(echo "${core_name}" | wc -l)" -ge 2 ]]; then |
| echo "Which core would you like to analyze?" |
| select choice in ${core_name}; do |
| core_name=${choice} |
| break |
| done |
| fi |
| |
| core="/tmp/zxdb_fetched_core.dmp" |
| if [[ " ${cache_core_names[*]} " == *"$core_name"* ]]; then |
| fx-command-run "cp" "--to-host" \ |
| "/data/cache/r/sys/${crash_reports_cache_dir}/reports/${core_name}" \ |
| "${core}" |
| else |
| fx-command-run "cp" "--to-host" \ |
| "/tmp/r/sys/${crash_reports_tmp_dir}/reports/${core_name}" \ |
| "${core}" |
| fi |
| fi |
| |
| if [[ -n "${core}" && ! -f "${core}" ]]; then |
| echo "Cannot find file ${core}" |
| exit 1 |
| fi |
| |
| connect_ops=() |
| |
| if [[ ! -z "${core}" ]]; then |
| connect_ops=("--core" "${core}") |
| elif [[ ! -z "${no_agent}" ]]; then |
| echo "Not starting a debug agent." |
| else |
| if launch_debug_agent "${port}" "${unwind_flag}" "${agent_out}"; then |
| connect_ops=("--connect" "$(get-device-addr-resource):${port}" "--quit-agent-on-exit") |
| else |
| fx-error "Could not launch debug agent. Exiting. Make sure you're running 'fx serve'." |
| exit 1 |
| fi |
| fi |
| |
| ensure-symbol-index-registered || fx-warn "Failed to register ${FUCHSIA_DIR} in symbol-index!" |
| |
| "${FUCHSIA_BUILD_DIR}/host-tools/zxdb" \ |
| ${connect_ops[@]} \ |
| "--symbol-server" "gs://fuchsia-artifacts-release/debug" \ |
| "$@" |
| |
| # launch_debug_agent starts the agent in a subprocess, which zxdb will |
| # terminate by --quit-agent-on-exit, we want to wait that process however. |
| wait |