| // Copyright 2020 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. |
| @available(added=16) |
| library fuchsia.debugger; |
| |
| using fuchsia.component; |
| using zx; |
| |
| @available(added=HEAD) |
| closed protocol AttachedProcessIterator { |
| strict GetNext() -> (struct { |
| process_names vector<string:zx.MAX_NAME_LEN>:MAX; |
| }); |
| }; |
| |
| @available(added=HEAD) |
| type ThreadDetailsInterest = table { |
| /// Produce a backtrace in symbolizer markup format for each thread. |
| /// If this is unspecified, no backtrace will be included in the |
| /// ThreadDetails yielded by ProcessInfoIterator. |
| 1: backtrace bool; |
| }; |
| |
| /// Details about a particular thread. The fields will be included as per the |
| /// ThreadDetailsInterest supplied when creating the ProcessInfoIterator via |
| /// |GetProcessInfo|. |
| @available(added=HEAD) |
| type ThreadDetails = table { |
| /// A stack trace from the current thread in symbolizer markup format. |
| 1: backtrace string:MAX; |
| }; |
| |
| @available(added=HEAD) |
| type ProcessInfo = struct { |
| process zx.Koid; |
| moniker string:fuchsia.component.MAX_MONIKER_LENGTH; |
| |
| /// The koid of the thread that produced the information in |details|. |
| thread zx.Koid; |
| |
| /// Details about the thread with |koid|, as specified in the |
| /// ThreadDetailsInterest given to |GetProcessInfo|. |
| details ThreadDetails; |
| }; |
| |
| @available(added=HEAD) |
| type ProcessInfoError = flexible enum { |
| /// There were no attached processes to iterate over. |
| NO_PROCESSES = 1; |
| /// A process has died such that the iterator is invalid. |
| PROCESS_GONE = 2; |
| /// A process's threads have been mutated such that the iterator is invalid. |
| THREAD_GONE = 3; |
| }; |
| |
| /// Collects details from all threads of all attached processes. The exact |
| /// details that are yielded from the iterator are controlled via |
| /// ThreadDetailsInterest passed to |GetProcessInfo|. The iterator will yield an |
| /// empty vector after all attached process' threads have been iterated. It is |
| /// an error if there are no processes supplied to this iterator, which could be |
| /// from too restrictive of a filter passed to |GetProcessInfo| or DebugAgent is |
| /// not attached to anything. |
| /// |
| /// This iteration is inherently racy, there is no way for DebugAgent to prevent |
| /// other system entities from causing a process or thread to disappear while we |
| /// are traversing them, so it's possible for this iterator to return errors |
| /// when those threads or processes have been destroyed. These are not fatal |
| /// errors, but can happen multiple times in one iteration. |
| /// |
| /// For example, take this process structure, and assume DebugAgent is attached |
| /// to everything: |
| /// |
| /// pr: "process-1" 1234 |
| /// t: "pr1234-t1" 1 |
| /// t: "pr1234-t2" 2 |
| /// pr: "process-2" 2345 |
| /// t: "pr2345-t1" 3 |
| /// |
| /// If "process-1" is killed after "pr1234-t1" is yielded, but before |
| /// "pr1234-t2" is yielded, a THREAD_GONE error will be returned on the next |
| /// |GetNext| call. Calling |GetNext| again will yield "pr2345-t1". |
| @available(added=HEAD) |
| closed protocol ProcessInfoIterator { |
| /// Collects information about the next attached thread. There is no |
| /// guarantee of order of processes, but all threads from a given process |
| /// will be iterated before another process's threads. |
| strict GetNext() -> (struct { |
| info vector<ProcessInfo>:MAX; |
| }) error ProcessInfoError; |
| }; |
| |
| @available(added=HEAD) |
| type FilterError = flexible enum { |
| /// Indicates that there was no pattern given in the filter. |
| NO_PATTERN = 1; |
| /// FilterType was either unspecified or an otherwise unknown type to this agent. |
| UNKNOWN_TYPE = 2; |
| }; |
| |
| @available(added=HEAD) |
| type FilterType = flexible enum : uint8 { |
| /// Performs an exact match against a component's URL, sans hash values. |
| /// e.g. pattern fuchsia-pkg://fuchsia.com/package#meta/component.cm will |
| /// match fuchsia-pkg://fuchsia.com/package?hash=1234abcd#meta/component.cm. |
| URL = 0; |
| /// Performs an exact match against a component's full moniker. |
| MONIKER = 1; |
| /// Matches any component moniker that includes the pattern as a prefix. |
| MONIKER_PREFIX = 2; |
| /// Matches any component moniker that includes the pattern as a suffix. |
| MONIKER_SUFFIX = 3; |
| }; |
| |
| @available(added=HEAD) |
| type FilterOptions = table { |
| /// Whether or not to also match all child components in the matching |
| /// component's realm. When true, the matching component's full moniker will |
| /// be assumed to be the root of the realm, and all children components will |
| /// be launched within this realm. |
| 1: recursive bool; |
| }; |
| |
| /// A filter that will apply to processes and components running now and in the |
| /// future. Any component or process that matches the given pattern and type |
| /// will be attached, thereafter allowing clients to query information about the |
| /// program(s). A valid filter will always contain a non-empty pattern string, |
| /// and a FilterType to discern what to compare the pattern against. Additional |
| /// options may be specified via FilterOptions. |
| @available(added=HEAD) |
| type Filter = struct { |
| /// A string pattern to be matched against the given |type|. An empty |
| /// pattern will result in a NO_PATTERN error. |
| pattern string:MAX; |
| |
| /// How to interpret |pattern|. See FilterType. |
| type FilterType; |
| |
| /// Additional options for this filter. See FilterOptions. |
| options FilterOptions; |
| }; |
| |
| @available(added=HEAD) |
| type GetProcessInfoOptions = table { |
| /// A filter that will reduce the number of processes that are iterated |
| /// over. This will not install any new filters and will not cause new |
| /// processes to be attached. Instead, this filter will be applied to |
| /// already attached processes, which can be useful if there are many |
| /// processes currently attached. |
| 1: filter Filter; |
| |
| /// Clients should specify the data they are interested in being yielded |
| /// from the iterator here. Any unspecified fields will be assumed to be |
| /// false. See ThreadDetailsInterest for descriptions of possible data. |
| 2: interest ThreadDetailsInterest; |
| }; |
| |
| @discoverable |
| open protocol DebugAgent { |
| /// Hand the DebugAgent a socket that connects it to the debugger. This |
| /// will return ZX_ERR_ALREADY_BOUND if a connection already exists. When |
| /// the socket is closed, the DebugAgent will exit. |
| flexible Connect(resource struct { |
| socket zx.Handle:SOCKET; |
| }) -> () error zx.Status; |
| |
| /// Iterator over all processes that this agent is attached to. Note this is |
| /// not the same as the set of installed filters, but rather the set of |
| /// filters that matched and were later successfully attached. |
| @available(added=HEAD) |
| flexible GetAttachedProcesses(resource struct { |
| iterator server_end:AttachedProcessIterator; |
| }); |
| |
| /// Use the given filter to attach to any existing or subsequently created |
| /// components. This method will return the number of matches that were |
| /// present at the time of calling this method. All attached processes will |
| /// be detached when this agent is destroyed. |
| /// |
| /// |filter| will be inspected for validity, with corresponding errors |
| /// returned. If the filter is invalid, no attaches will occur. |
| /// |
| /// |num_matches| will contain the number of matches that were found |
| /// immediately upon filter installation if there was no error, that is, the |
| /// number of processes immediately within (or recursively in this realm, if |
| /// the option is specified) this component's corresponding job. Note that |
| /// filters may be installed _before_ any components are actually resolved |
| /// and matched, so this number may be 0. This return value may be safely |
| /// ignored. |
| /// |
| /// Invalid filters will return an error, see Filter above for details on |
| /// how to construct a filter. |
| @available(added=HEAD) |
| flexible AttachTo(Filter) -> (struct { |
| num_matches uint32; |
| }) error FilterError; |
| |
| /// The given server_end of the iterator will iterate over all threads, of |
| /// all attached processes. The options parameter may be passed to filter |
| /// the already attached processes and to express interest in what should be |
| /// yielded by the iterator. Including a filter is recommended if DebugAgent |
| /// is attached to a large number of processes. Note that this filter will |
| /// not cause any new processes to be attached and will not be saved after |
| /// this method returns. It is purely to reduce the bounds of the iterator. |
| /// The threads will be suspended for the duration of information capture, |
| /// which could be interrupted by other system processes, see |
| /// |ProcessInfoIterator| for an example. |
| @available(added=HEAD) |
| flexible GetProcessInfo(resource struct { |
| options GetProcessInfoOptions; |
| iterator server_end:ProcessInfoIterator; |
| }) -> () error FilterError; |
| |
| /// Report exceptions to clients. If no debug_ipc clients are connected, the |
| /// exception will be immediately released, which may result in the process |
| /// crashing. |
| @available(added=HEAD) |
| flexible -> OnFatalException(table { |
| /// The faulting thread's koid. |
| 1: thread zx.Koid; |
| /// A stack trace from the faulting thread in symbolizer markup format. |
| 2: backtrace string:MAX; |
| }); |
| }; |
| |
| @available(added=HEAD) |
| type Agent = resource struct { |
| name fuchsia.component.child_name; |
| client_end client_end:DebugAgent; |
| }; |
| |
| @available(added=HEAD) |
| closed protocol AgentIterator { |
| strict GetNext() -> (resource struct { |
| agents vector<Agent>:MAX; |
| }); |
| }; |
| |
| @discoverable |
| @available(added=HEAD) |
| open protocol Launcher { |
| /// Launch a new instance of DebugAgent listening on |agent|. The DebugAgent |
| /// will exit upon closing the corresponding client_end of this channel. |
| /// Clients must not close the channel until the debugging session is |
| /// completed. |
| flexible Launch(resource struct { |
| agent server_end:DebugAgent; |
| }) -> () error zx.Status; |
| |
| /// Iterator over all DebugAgent instances. |
| flexible GetAgents(resource struct { |
| iterator server_end:AgentIterator; |
| }); |
| }; |