GP-740: Updated documentation of TargetObject

This commit is contained in:
Dan 2021-03-05 09:03:14 -05:00
parent c1d5a86b39
commit 2fb2f1fa26

View file

@ -47,22 +47,22 @@ import ghidra.lifecycle.Internal;
* root object, may implement any number of interfaces extending {@link TargetObject}. These * root object, may implement any number of interfaces extending {@link TargetObject}. These
* interfaces comprise the type and behavior of the object. An object's children comprise its * interfaces comprise the type and behavior of the object. An object's children comprise its
* elements (for collection-like objects) and attributes. Every object in the directory has a path. * elements (for collection-like objects) and attributes. Every object in the directory has a path.
* Each element in the path identifies an index (if the child is an element) or a name (if the child * Each element ("key") in the path identifies an index (if the child is an element) or a name (if
* is an attribute). It is the implementation's responsibility to ensure each object's path * the child is an attribute). It is the implementation's responsibility to ensure each object's
* correctly identifies that same object in the model directory. The root has the empty path. Every * path correctly identifies that same object in the model directory. The root has the empty path.
* object must have a unique path; thus, every object must have a unique name among its sibling. * Every object must have a unique path; thus, every object must have a unique key among its
* sibling.
* *
* <p> * <p>
* The objects are arranged in a directory with links permitted. Links come in the form of * The objects are arranged in a directory with links permitted. Links come in the form of
* object-valued attributes where the attribute path is not its value's path. Thus, the overall * object-valued attributes or elements where the path does not match the object value's path. Thus,
* structure remains a tree, but by resolving links, the model may be treated as a directed graph, * the overall structure remains a tree, but by resolving links, the model may be treated as a
* likely containing cycles. See {@link PathUtils#isLink(List, String, List)}. * directed graph, likely containing cycles. See {@link PathUtils#isLink(List, String, List)}.
* *
* <p> * <p>
* The implementation must guarantee that distinct {@link TargetObject}s from the same model do not * The implementation must guarantee that distinct {@link TargetObject}s from the same model do not
* refer to the same path. That is, checking for object identity is sufficient to check that two * share the same path. That is, checking for object identity is sufficient to check that two
* variables refer to the same object. It is recommended that client-side implementations use a * variables refer to the same object.
* weak-valued map of paths to cached target objects.
* *
* <p> * <p>
* Various conventions govern where the client/user should search to obtain a given interface in the * Various conventions govern where the client/user should search to obtain a given interface in the
@ -78,7 +78,7 @@ import ghidra.lifecycle.Internal;
* If it does, take it.</li> * If it does, take it.</li>
* <li><b>Aggregate objects:</b> If the object is marked with {@link TargetAggregate}, collect all * <li><b>Aggregate objects:</b> If the object is marked with {@link TargetAggregate}, collect all
* attributes supporting the desired interface. If there are any, take them. This step is applied * attributes supporting the desired interface. If there are any, take them. This step is applied
* recursively if the child attributes are also marked with {@link TargetAggregate}.</li> * recursively if any child attribute is also marked with {@link TargetAggregate}.</li>
* <li><b>Ancestry:</b> Apply these same steps to the object's (canonical) parent, recursively.</li> * <li><b>Ancestry:</b> Apply these same steps to the object's (canonical) parent, recursively.</li>
* </ol> * </ol>
* *
@ -88,8 +88,8 @@ import ghidra.lifecycle.Internal;
* the rules until a sufficient collection of objects is obtained. If an object is in conflict with * the rules until a sufficient collection of objects is obtained. If an object is in conflict with
* another, take the first encountered. This situation may be appropriate if, e.g., multiple target * another, take the first encountered. This situation may be appropriate if, e.g., multiple target
* memories present disjoint regions. There should not be conflicts among sibling. If there are, * memories present disjoint regions. There should not be conflicts among sibling. If there are,
* then either the model or the query is not sound. The order sibling are considered should not * then either the model or the query is not sound. The order siblings considered should not matter.
* matter. These rules are incubating and are implemented in {@link DebugModelConventions}. * These rules are incubating and are implemented in {@link DebugModelConventions}.
* *
* <p> * <p>
* This relatively free structure and corresponding conventions allow for debuggers to present a * This relatively free structure and corresponding conventions allow for debuggers to present a
@ -307,9 +307,13 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* Because interfaces cannot provide default implementations of {@link #equals(Object)}, this * Because interfaces cannot provide default implementations of {@link #equals(Object)}, this
* methods provides a means of quickly implementing it within a class. Because everything that * methods provides a means of quickly implementing it within a class. Because (model, path)
* constitutes target object equality is contained in the reference (model, path), there should * uniquely identifies an object, there should never be a need to perform more comparison than
* never be a need to perform more comparison than is provided here. * is provided here.
*
* <p>
* TODO: Since refs are no longer a thing, is custom equality needed at all? Seems object
* identity would be sufficient.
* *
* @param obj the other object * @param obj the other object
* @return true if they are equal * @return true if they are equal
@ -331,10 +335,14 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* Because interfaces cannot provide default implementations of {@link #hashCode()}, this method * Because interfaces cannot provide default implementations of {@link #hashCode()}, this method
* provides a means of quickly implementing it within a class. Because everything that * provides a means of quickly implementing it within a class. Because (model, path) is
* constitutes target object equality is <em>immutable</em> and contained in the reference * immutable and uniquely identifes an object, this hash should be pre-computed a construction.
* (model, path), this hash should be pre-computed a construction. There should never be a need * There should never be a need to incorporate more fields into the hash than is incorporated
* to incorporate more fields into the hash than is incorporated here. * here.
*
* <p>
* TODO: Since refs are no longer a thing, is custom equality needed at all? Seems object
* identity would be sufficient.
* *
* @return the hash * @return the hash
*/ */
@ -409,8 +417,8 @@ public interface TargetObject extends Comparable<TargetObject> {
* Get the path (i.e., list of names from root to this object). * Get the path (i.e., list of names from root to this object).
* *
* <p> * <p>
* Every object must have a unique path. Parts of the path which are indices, i.e., which * Every object must have a unique path. Keys in the path which are indices, i.e., which
* navigate the elements, are enclosed in brackets @{code []}. Parts which navigate attributes * navigate the elements, are enclosed in brackets @{code []}. Keys which navigate attributes
* are simply the attribute name. * are simply the attribute name.
* *
* <p> * <p>
@ -418,9 +426,6 @@ public interface TargetObject extends Comparable<TargetObject> {
* For example, a {@link TargetMemory} attribute of a process is assumed accessible to every * For example, a {@link TargetMemory} attribute of a process is assumed accessible to every
* thread of that process, since those threads are descendants. * thread of that process, since those threads are descendants.
* *
* @implNote it would be wise to cache the result of this computation. If the object has a
* strict location, then the implementation should just return it directly.
*
* @return the canonical path of the object * @return the canonical path of the object
*/ */
public List<String> getPath(); public List<String> getPath();
@ -430,7 +435,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* Note that no check is applied to guarantee the path separator does not appear in an element * Note that no check is applied to guarantee the path separator does not appear in an element
* name. * name. Conventionally, `.` should be the separator. The separator is omitted before indices.
* *
* @see #getPath() * @see #getPath()
* @param sep the path separator * @param sep the path separator
@ -455,10 +460,10 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get the index for this object * Get the index for this object, omitting the brackets
* *
* @return they index, or {@code null} if this is the root * @return they index, or {@code null} if this is the root
* @throws IllegalArgumentException if this object is not an element of its parent * @throws IllegalArgumentException if this object's key is not an index
*/ */
public default String getIndex() { public default String getIndex() {
return PathUtils.getIndex(getPath()); return PathUtils.getIndex(getPath());
@ -474,26 +479,26 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get a reference to the parent of this reference * Get this object's canonical parent
* *
* @return the parent reference, or {@code null} if this refers to the root * @return the parent or {@code null} if this is the root
*/ */
public TargetObject getParent(); public TargetObject getParent();
/** /**
* Get an informal name identify the type of this object. * Get an informal name identifying the type of this object
* *
* <p> * <p>
* This is an informal notion of type and may only be used for visual styling, logging, or other * This is an informal notion of type and may only be used for visual styling, logging, or other
* informational purposes. Scripts should not rely on this to predict behavior, but instead on * informational purposes. Scripts should not rely on this to predict behavior, but instead on
* {@link #getAs(Class)} or {@link #getInterfaces()}; * {@link #getAs(Class)}, {@link #getInterfaces()}, or {@link #getSchema()}.
* *
* @return an informal name of this object's type * @return an informal name of this object's type
*/ */
public String getTypeHint(); public String getTypeHint();
/** /**
* Get this object's schema. * Get this object's schema
* *
* @return the schema * @return the schema
*/ */
@ -502,7 +507,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get the interfaces this object actually supports, and that the client recognizes. * Get the interfaces this object actually supports, and that the client recognizes
* *
* @implNote Proxy implementations should likely override this method. * @implNote Proxy implementations should likely override this method.
* *
@ -513,7 +518,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get the interface names this object actually supports. * Get the interface names this object actually supports
* *
* <p> * <p>
* When this object is a proxy, this set must include the names of all interfaces reported by * When this object is a proxy, this set must include the names of all interfaces reported by
@ -530,10 +535,10 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* In general, an invalid object should be disposed by the user immediately on discovering it is * In general, an invalid object should be disposed by the user immediately on discovering it is
* invalid. See {@link TargetObjectListener#invalidated(TargetObject)} for a means of reacting * invalid. See {@link DebuggerModelListener#invalidated(TargetObject)} for a means of reacting
* to object invalidation. Nevertheless, it is acceptable to access stale attributes and element * to object invalidation. Nevertheless, it is acceptable to access stale attributes and element
* keys, for informational purposes only. Implementors must reject all commands, including * keys, for informational purposes only. Implementors must reject all commands, including
* non-cached gets, on an invalid object by throwing an {@link IllegalStateException}. * fetches, on an invalid object by throwing an {@link IllegalStateException}.
* *
* @return true if valid, false if invalid * @return true if valid, false if invalid
*/ */
@ -546,12 +551,6 @@ public interface TargetObject extends Comparable<TargetObject> {
* Attributes are usually keyed by a string, and the types are typically not uniform. Some * Attributes are usually keyed by a string, and the types are typically not uniform. Some
* attributes are primitives, while others are other target objects. * attributes are primitives, while others are other target objects.
* *
* <p>
* Note, for objects, {@link TargetObject#getCachedAttributes()} should be sufficient to get an
* up-to-date view of the attributes, since the model should be pushing attribute updates to the
* object automatically. {@code fetchAttributes} should only be invoked on references, or in the
* rare case the client needs to ensure the attributes are fresh.
*
* @param refresh true to invalidate all caches involved in handling this request * @param refresh true to invalidate all caches involved in handling this request
* @return a future which completes with a name-value map of attributes * @return a future which completes with a name-value map of attributes
*/ */
@ -604,18 +603,6 @@ public interface TargetObject extends Comparable<TargetObject> {
/** /**
* Get the cached elements of this object * Get the cached elements of this object
* *
* <p>
* Note these are cached elements, and there's no requirement on the model's part to keep this
* cache up to date (unlike attributes). Thus, the indices (keys) in the returned map may be
* out-of-date.
*
* <p>
* Note that this method is not required to provide objects, but only object references. Local
* implementations, and clients having the appropriate proxies cached may present some, all, or
* none of the entries with actual objects. Users should NEVER depend on this being the case,
* however. Always call {@link TargetObjectRef#fetch()}, or use {@link #fetchElements} instead,
* to guarantee the actual objects are presented.
*
* @return the map of indices to element references * @return the map of indices to element references
*/ */
public Map<String, ? extends TargetObject> getCachedElements(); public Map<String, ? extends TargetObject> getCachedElements();
@ -624,9 +611,9 @@ public interface TargetObject extends Comparable<TargetObject> {
* Fetch all the elements of this object * Fetch all the elements of this object
* *
* <p> * <p>
* Elements are usually keyed numerically, but allows strings for flexibility. They values are * Elements are usually keyed numerically, but allows strings for flexibility. The values are
* target objects, uniform in type, and should generally share the same attributes. The keys * target objects, typically uniform in type, and so generally share the same attributes. The
* must not contain the brackets {@code []}. Implementations should ensure that the elements are * keys must omit the brackets {@code []}. Implementations should ensure that the elements are
* presented in order by key -- not necessarily lexicographically. To ensure clients can easily * presented in order by key -- not necessarily lexicographically. To ensure clients can easily
* maintain correct sorting, the recommendation is to present the keys as follows: Keys should * maintain correct sorting, the recommendation is to present the keys as follows: Keys should
* be the numeric value encoded as strings in base 10 or base 16 as appropriate, using the least * be the numeric value encoded as strings in base 10 or base 16 as appropriate, using the least
@ -654,7 +641,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Fetch an element by its index * Fetch an element by its index, omitting the brackets
* *
* @return a future which completes with the element or with {@code null} if it does not exist * @return a future which completes with the element or with {@code null} if it does not exist
*/ */
@ -701,8 +688,8 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* Indices are distinguished from names by the presence or absence of brackets {@code []}. If * Indices are distinguished from names by the presence or absence of brackets {@code []}. If
* the key is a bracket-enclosed index, this will retrieve a child, otherwise, it will retrieve * the key is a bracket-enclosed index, this will retrieve an element, otherwise, it will
* an attribute. * retrieve an attribute.
* *
* @see #fetchAttribute(String) * @see #fetchAttribute(String)
* @see #fetchElement(String) * @see #fetchElement(String)
@ -763,7 +750,8 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* Extend this reference's path with the given sub-path and request that object from the same * Extend this reference's path with the given sub-path and request that object from the same
* model. * model. Note unlike {@link #fetchValue(List)}, this can return objects which have been
* created, but not yet added to the model.
* *
* @param sub the sub-path to the successor * @param sub the sub-path to the successor
* @return a future which completes with the object or with {@code null} if it does not exist * @return a future which completes with the object or with {@code null} if it does not exist
@ -780,14 +768,13 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get a reference to a successor of this object * Get the cached successor of this object
* *
* <p> * <p>
* Extend this reference's path with the given sub-path, creating a new reference in the same * Extend this object's path with the given sub-path, and search the model's cache for it.
* model. This is mere path manipulation. The referenced object may not exist.
* *
* @param sub the sub-path to the successor * @param sub the sub-path to the successor
* @return a reference to the successor * @return the successor or {@code null} if it doesn't exist in the cache
*/ */
public default TargetObject getSuccessor(List<String> sub) { public default TargetObject getSuccessor(List<String> sub) {
return getModel().getModelObject(PathUtils.extend(getPath(), sub)); return getModel().getModelObject(PathUtils.extend(getPath(), sub));
@ -801,7 +788,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Fetch the attributes of the model at the given sub-path from this object * Fetch the attributes of a successor to this object
* *
* @param sub the sub-path to the successor whose attributes to list * @param sub the sub-path to the successor whose attributes to list
* @return a future map of attributes * @return a future map of attributes
@ -841,7 +828,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Fetch the elements of the model at the given sub-path from this object * Fetch the elements of a successor to this object
* *
* @param sub the sub-path to the successor whose elements to list * @param sub the sub-path to the successor whose elements to list
* @return a future map of elements * @return a future map of elements
@ -860,7 +847,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get a description of the object, suitable for display in the UI. * Get a description of the object, suitable for display in the UI
* *
* @return the display description * @return the display description
*/ */
@ -870,7 +857,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get a brief description of the object, suitable for display in the UI. * Get a brief description of the object, suitable for display in the UI
* *
* @return the display description * @return the display description
*/ */
@ -880,7 +867,7 @@ public interface TargetObject extends Comparable<TargetObject> {
} }
/** /**
* Get a hint to the "kind" of object this represents. * Get a hint to the "kind" of object this represents
* *
* <p> * <p>
* This is useful when the native debugger presents a comparable tree-like model. If this object * This is useful when the native debugger presents a comparable tree-like model. If this object
@ -942,7 +929,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* For values, check if it was "recently" modified * For values, check if it was "recently" modified
* *
* <p> * <p>
* TODO: This should probably be moved to a new {@code TargetType} interface. * TODO: This should probably be moved to a new {@code TargetObject} interface.
* *
* <p> * <p>
* "Recently" generally means since (or as a result of ) the last event affecting a target in * "Recently" generally means since (or as a result of ) the last event affecting a target in
@ -960,7 +947,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* For values, get the type of the value * For values, get the type of the value
* *
* <p> * <p>
* TODO: This should probably be moved to a new {@code TargetType} interface. How does this * TODO: This should probably be moved to a new {@code TargetObject} interface. How does this
* differ from "kind" when both are present? Can this be a {@link TargetNamedDataType} instead? * differ from "kind" when both are present? Can this be a {@link TargetNamedDataType} instead?
* Though, I suppose that would imply the object is a value in the target execution state, e.g., * Though, I suppose that would imply the object is a value in the target execution state, e.g.,
* a register, variable, field, etc. * a register, variable, field, etc.
@ -976,7 +963,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* For values, get the actual value * For values, get the actual value
* *
* <p> * <p>
* TODO: This should probably be moved to a new {@code TargetType} interface. * TODO: This should probably be moved to a new {@code TargetObject} interface.
* *
* @return the value * @return the value
*/ */
@ -1014,7 +1001,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* The opaque identifier should implement proper {@link Object#hashCode()} and * The opaque identifier should implement proper {@link Object#hashCode()} and
* {@link Object#equals(Object)}, so that paired with the client, it forms a unique key for this * {@link Object#equals(Object)}, so that paired with the model, it forms a unique key for this
* target object. It should also implement {@link Object#toString()}; however, it is for * target object. It should also implement {@link Object#toString()}; however, it is for
* debugging or informational purposes only. It is common for this identifier to be the object's * debugging or informational purposes only. It is common for this identifier to be the object's
* path. * path.
@ -1024,7 +1011,14 @@ public interface TargetObject extends Comparable<TargetObject> {
public Object getProtocolID(); public Object getProtocolID();
/** /**
* Get this same object, cast to the requested interface, if supported. * Get this same object, cast to the requested interface, if supported
*
* <p>
* This differs from Java-style casting in two ways: 1) The receiver cannot be {@code null}, and
* 2) It throws a different exception. Server-side proxy implementations must marshall the
* {@link DebuggerModelTypeException} to the client; whereas, for {@link ClassCastException}, it
* may simply report "Server-side Error," because that exception may have been thrown by an
* unrelated cast.
* *
* @param <T> the requested interface * @param <T> the requested interface
* @param iface the class of the requested interface * @param iface the class of the requested interface
@ -1038,18 +1032,6 @@ public interface TargetObject extends Comparable<TargetObject> {
/** /**
* Get the cached attributes of this object * Get the cached attributes of this object
* *
* <p>
* While this technically only returns "cached" attributes, the model should be pushing
* attribute updates to the object automatically. Thus, the names (keys) and values in the
* returned map should be up-to-date.
*
* <p>
* Note that object-valued attributes are only guaranteed to be a {@link TargetObjectRef}. Local
* implementations, and clients having the appropriate proxies cached may present some, all, or
* none of the object-valued attributes with the actual object. Users should NEVER depend on
* this being the case, however. Always call {@link TargetObjectRef#fetch()}, or use
* {@link #fetchAttributes()} instead, to guarantee the actual objects are presented.
*
* @return the cached name-value map of attributes * @return the cached name-value map of attributes
*/ */
public Map<String, ?> getCachedAttributes(); public Map<String, ?> getCachedAttributes();
@ -1089,7 +1071,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* *
* <p> * <p>
* Some objects, e.g., memories and register banks, may have caches to reduce requests and * Some objects, e.g., memories and register banks, may have caches to reduce requests and
* callbacks. This method should clear such caches, if applicable, but <em>should not</em> clear * callbacks. This method should clear such caches, if applicable, but <em>must not</em> clear
* caches of elements or attributes. * caches of elements or attributes.
* *
* <p> * <p>
@ -1107,14 +1089,21 @@ public interface TargetObject extends Comparable<TargetObject> {
* Listen for object events * Listen for object events
* *
* <p> * <p>
* The caller must maintain a strong reference to the listener. To allow stale listeners to be * The client must maintain a strong reference to the listener. To allow stale listeners to be
* garbage collected, the implementation should use weak or soft references. That said, the * garbage collected, the implementation should use weak or soft references. That said, the
* client user must not rely on the implementation to garbage collect its listeners. All * client should not rely on the implementation to garbage collect its listeners. All unneeded
* unneeded listeners should be removed using {@link #removeListener(TargetObjectListener)}. The * listeners should be removed using {@link #removeListener(TargetObjectListener)}. The
* exception is when an object is destroyed. The user may safely neglect removing any listeners * exception is when an object is invalidated. The client may safely neglect removing any
* it registered with that object. If the object does not keep listeners, i.e., it produces no * listeners it registered with that object. If the object does not keep listeners, i.e., it
* events, this method may do nothing. * produces no events, this method may do nothing.
* *
* <p>
* Clients ought to listen on the model instead of specific objects, especially since an object
* may emit events immediately after its creation, but before the client has a chance to add a
* listener. Worse yet, the object could be invalidated before the client can retrieve its
* children. Listening on the model ensures the reception of a complete log of events.
*
* @see DebuggerObjectModel#addModelListener(DebuggerModelListener)
* @param l the listener * @param l the listener
*/ */
public default void addListener(TargetObjectListener l) { public default void addListener(TargetObjectListener l) {
@ -1125,7 +1114,7 @@ public interface TargetObject extends Comparable<TargetObject> {
* Remove a listener * Remove a listener
* *
* <p> * <p>
* If the given listener is not registered with this object, this method should do nothing. * If the given listener is not registered with this object, this method does nothing.
* *
* @param l the listener * @param l the listener
*/ */