GP-1556 - Added support for searching for structure fields by offset

This commit is contained in:
dragonmacher 2022-03-25 09:43:50 -04:00
parent 883f5a687a
commit 812ea4fe1e
45 changed files with 1461 additions and 840 deletions

View file

@ -41,10 +41,10 @@ import utilities.util.reflection.ReflectionUtilities;
* the entire application.
* <p>
* DockingActions can be invoked from the global menu, a popup menu, a toolbar, and/or a keybinding,
* depending on whether or not menuBarData, popupMenuData, toolBarData, and/or keyBindingData have
* depending on whether or not menuBarData, popupMenuData, toolBarData, and/or keyBindingData have
* been set.
* <p>
* <b>
* <b>
* Implementors of this class should override {@link #actionPerformed(ActionContext)}.
* </b>
* <p>
@ -199,12 +199,12 @@ public abstract class DockingAction implements DockingActionIf {
* <P>
* If the client wants the action on all windows, then they can call {@link #shouldAddToAllWindows}
* <P>
* If the client wants the action to be on a window only when the window can produce
* a certain context type, the the client should call
* If the client wants the action to be on a window only when the window can produce
* a certain context type, the the client should call
* {@link #addToWindowWhen(Class)}
* <P>
* Otherwise, by default, the action will only be on the main window.
*
*
*/
@Override
public final boolean shouldAddToWindow(boolean isMainWindow, Set<Class<?>> contextTypes) {
@ -212,7 +212,7 @@ public abstract class DockingAction implements DockingActionIf {
if (menuBarData == null && toolBarData == null) {
return false;
}
// clients can specify that the action should be on all windows.
if (shouldAddToAllWindows) {
return true;
@ -242,6 +242,14 @@ public abstract class DockingAction implements DockingActionIf {
DockingWindowManager.getHelpService().registerHelp(this, location);
}
/**
* Returns the help location for this action
* @return the help location for this action
*/
public HelpLocation getHelpLocation() {
return DockingWindowManager.getHelpService().getHelpLocation(this);
}
/**
* Signals the the help system that this action does not need a help entry. Some actions
* are so obvious that they do not require help, such as an action that renames a file.
@ -579,10 +587,10 @@ public abstract class DockingAction implements DockingActionIf {
/**
* Sets a predicate for dynamically determining the action's enabled state. If this
* predicate is not set, the action's enable state must be controlled directly using the
* {@link DockingAction#setEnabled(boolean)} method. See
* {@link DockingAction#setEnabled(boolean)} method. See
* {@link DockingActionIf#isEnabledForContext(ActionContext)}
*
* @param predicate the predicate that will be used to dynamically determine an action's
*
* @param predicate the predicate that will be used to dynamically determine an action's
* enabled state.
*/
public void enabledWhen(Predicate<ActionContext> predicate) {
@ -592,10 +600,10 @@ public abstract class DockingAction implements DockingActionIf {
/**
* Sets a predicate for dynamically determining if this action should be included in
* an impending pop-up menu. If this predicate is not set, the action's will be included
* in an impending pop-up, if it is enabled. See
* in an impending pop-up, if it is enabled. See
* {@link DockingActionIf#isAddToPopup(ActionContext)}
*
* @param predicate the predicate that will be used to dynamically determine an action's
*
* @param predicate the predicate that will be used to dynamically determine an action's
* enabled state.
*/
public void popupWhen(Predicate<ActionContext> predicate) {
@ -603,10 +611,10 @@ public abstract class DockingAction implements DockingActionIf {
}
/**
* Sets a predicate for dynamically determining if this action is valid for the current
* Sets a predicate for dynamically determining if this action is valid for the current
* {@link ActionContext}. See {@link DockingActionIf#isValidContext(ActionContext)}
*
* @param predicate the predicate that will be used to dynamically determine an action's
*
* @param predicate the predicate that will be used to dynamically determine an action's
* validity for a given {@link ActionContext}
*/
public void validContextWhen(Predicate<ActionContext> predicate) {
@ -620,14 +628,14 @@ public abstract class DockingAction implements DockingActionIf {
* that can produce an ActionContext that is appropriate for this action.
* <P>
* @param contextClass the ActionContext class required to be producible by a
* provider that is hosted in that window before this action is added to that
* window.
*
* provider that is hosted in that window before this action is added to that
* window.
*
*/
public void addToWindowWhen(Class<? extends ActionContext> contextClass) {
addToWindowWhenContextClass = contextClass;
}
/**
* Tells this action to add itself to all windows
* <P>
@ -664,5 +672,5 @@ public abstract class DockingAction implements DockingActionIf {
String classInfo = trace[0].toString();
return classInfo;
}
}

View file

@ -27,8 +27,8 @@ import docking.widgets.label.GDLabel;
import docking.widgets.label.GHtmlLabel;
/**
* A dialog that has text fields to get user input.
*
* A dialog that has text fields to get user input.
*
*/
public class InputWithChoicesDialog extends DialogComponentProvider {
@ -39,12 +39,12 @@ public class InputWithChoicesDialog extends DialogComponentProvider {
/**
* Creates a provider for a generic input dialog with the specified title,
* a label and a editable comboBox pre-populated with selectable values. The user
* can check the value of {@link #isCanceled()} to know whether or not
* can check the value of {@link #isCanceled()} to know whether or not
* the user canceled the operation. To get the user selected value use the
* {@link #getValue()} value(s) entered by the user. If the user cancelled the operation, then
* null will be returned from <code>getValue()</code>.
* <P>
*
*
* @param dialogTitle used as the name of the dialog's title bar
* @param label value to use for the label of the text field
* @param optionValues values to populate the combo box
@ -69,12 +69,12 @@ public class InputWithChoicesDialog extends DialogComponentProvider {
/**
* Creates a provider for a generic input dialog with the specified title,
* a label and a editable comboBox pre-populated with selectable values. The user
* can check the value of {@link #isCanceled()} to know whether or not
* can check the value of {@link #isCanceled()} to know whether or not
* the user canceled the operation. To get the user selected value use the
* {@link #getValue()} value(s) entered by the user. If the user cancelled the operation, then
* null will be returned from <code>getValue()</code>.
* <P>
*
*
* @param dialogTitle used as the name of the dialog's title bar
* @param label value to use for the label of the text field
* @param optionValues values to populate the combo box
@ -180,6 +180,11 @@ public class InputWithChoicesDialog extends DialogComponentProvider {
if (isCanceled) {
return null;
}
if (allowEdits) {
return combo.getText();
}
Object selectedItem = combo.getSelectedItem();
return selectedItem == null ? null : selectedItem.toString();
}
@ -188,7 +193,7 @@ public class InputWithChoicesDialog extends DialogComponentProvider {
* Set the current choice to value.
* @param value updated choice
* @throws NoSuchElementException if choice does not permit edits and value is
* not a valid choice.
* not a valid choice.
*/
public void setValue(String value) {
combo.setSelectedItem(value);

View file

@ -57,17 +57,24 @@ public final class NumericUtilities {
}
/**
* parses the given string as a numeric value, detecting whether or not it begins with a Hex
* Parses the given string as a numeric value, detecting whether or not it begins with a Hex
* prefix, and if not, parses as a long int value.
* @param numStr the number string
* @return the long value or 0
*
*/
public static long parseNumber(String numStr) {
long value = 0;
return parseNumber(numStr, Long.valueOf(0));
}
public static Long parseNumber(String numStr, Long defaultValue) {
numStr = (numStr == null ? "" : numStr.trim());
if (numStr.length() == 0) {
return value;
return defaultValue;
}
long value = 0;
try {
if (numStr.startsWith(HEX_PREFIX_x) || numStr.startsWith(HEX_PREFIX_X)) {
value = Integer.parseInt(numStr.substring(2), 16);
@ -78,6 +85,7 @@ public final class NumericUtilities {
}
catch (NumberFormatException exc) {
// do nothing special; use default value
return defaultValue;
}
return value;
@ -192,7 +200,7 @@ public final class NumericUtilities {
/**
* returns the value of the specified long as hexadecimal, prefixing with the HEX_PREFIX_x
* string.
*
*
* @param value the long value to convert
*/
public final static String toHexString(long value) {
@ -202,7 +210,7 @@ public final class NumericUtilities {
/**
* returns the value of the specified long as hexadecimal, prefixing with the HEX_PREFIX_x
* string.
*
*
* @param value the long value to convert
* @param size number of bytes to be represented
*/
@ -216,7 +224,7 @@ public final class NumericUtilities {
/**
* returns the value of the specified long as signed hexadecimal, prefixing with the
* HEX_PREFIX_x string.
*
*
* @param value the long value to convert
*/
public final static String toSignedHexString(long value) {
@ -230,14 +238,14 @@ public final class NumericUtilities {
}
/**
* Converts a <strong>unsigned</strong> long value, which is currently stored in a
* Converts a <strong>unsigned</strong> long value, which is currently stored in a
* java <strong>signed</strong> long, into a {@link BigInteger}.
* <p>
* In other words, the full 64 bits of the primitive java <strong>signed</strong>
* long is being used to store an <strong>unsigned</strong> value. This
* In other words, the full 64 bits of the primitive java <strong>signed</strong>
* long is being used to store an <strong>unsigned</strong> value. This
* method converts this into a positive BigInteger value.
*
* @param value java <strong>unsigned</strong> long value stuffed into a
*
* @param value java <strong>unsigned</strong> long value stuffed into a
* java <strong>signed</strong> long
* @return new {@link BigInteger} with the positive value of the unsigned long value
*/
@ -258,7 +266,7 @@ public final class NumericUtilities {
/**
* Get an unsigned aligned value corresponding to the specified unsigned value which will be
* greater than or equal the specified value.
*
*
* @param unsignedValue value to be aligned
* @param alignment alignment
* @return aligned value
@ -384,7 +392,7 @@ public final class NumericUtilities {
* Philosophically, it is hexadecimal, but the only valid digits are 0 and F. Any
* partially-included nibble will be broken down into bracketed bits. Displaying masks in this
* way is convenient when shown proximal to related masked values.
*
*
* @param msk the mask
* @param n the number of nibbles, starting at the right
* @param truncate true if leading Xs may be truncated
@ -441,7 +449,7 @@ public final class NumericUtilities {
/**
* The reverse of {@link #convertMaskedValueToHexString(long, long, int, boolean, int, String)}
*
*
* @param msk an object to receive the resulting mask
* @param val an object to receive the resulting value
* @param hex the input string to parse
@ -669,7 +677,7 @@ public final class NumericUtilities {
* <td>-64h</td>
* </tr>
* </table>
*
*
* @param number The number to represent
* @param radix The base in which <code>number</code> is represented
* @param mode Specifies how the number is formatted with respect to its signed-ness
@ -849,7 +857,7 @@ public final class NumericUtilities {
/**
* Determine if the provided Number is an integer type -- Byte, Short, Integer, or Long.
*
*
* @param number the object to check for for integer-type
* @return true if the provided number is an integer-type, false otherwise
*/
@ -860,7 +868,7 @@ public final class NumericUtilities {
/**
* Determine if the provided Number class is an integer type.
*
*
* @param numClass Class of an object
* @return true if the class parameter is a integer type, false otherwise
*/
@ -870,7 +878,7 @@ public final class NumericUtilities {
/**
* Determine if the provided Number is a floating-point type -- Float or Double.
*
*
* @param number the object to check for for floating-point-type
* @return true if the provided number is a floating-point-type, false otherwise
*/
@ -881,7 +889,7 @@ public final class NumericUtilities {
/**
* Determine if the provided Number class is a floating-point type.
*
*
* @param numClass Class of an object
* @return true if the class parameter is a floating-point type, false otherwise
*/
@ -895,7 +903,7 @@ public final class NumericUtilities {
private static interface IntegerRadixRenderer {
/**
* Format the given number in the provided radix base.
*
*
* @param number the number to render
* @param radix the base in which to render
* @return a string representing the provided number in the given base

View file

@ -18,9 +18,8 @@ package ghidra.util.datastruct;
import java.util.*;
/**
* Provides a list of integer ranges that are maintained in sorted order.
* When a range is added any ranges that overlap or are adjacent to one another
* will coalesce into a single range.
* Provides a list of integer ranges that are maintained in sorted order. When a range is added
* any ranges that overlap or are adjacent to one another will coalesce into a single range.
*/
public class SortedRangeList implements Iterable<Range> {
TreeSet<Range> set;
@ -33,8 +32,7 @@ public class SortedRangeList implements Iterable<Range> {
}
/**
* Creates a new sorted range list with ranges equivalent to those in the
* specified list.
* Creates a new sorted range list with ranges equivalent to those in the specified list.
* @param list the sorted range list to make an equivalent copy of.
*/
public SortedRangeList(SortedRangeList list) {
@ -47,9 +45,8 @@ public class SortedRangeList implements Iterable<Range> {
}
/**
* Adds the range from min to max to this sorted range list.
* If the range is adjacent to or overlaps any other existing ranges,
* then those ranges will coalesce.
* Adds the range from min to max to this sorted range list. If the range is adjacent to or
* overlaps any other existing ranges, then those ranges will coalesce.
* @param min the range minimum
* @param max the range maximum (inclusive)
*/
@ -82,15 +79,18 @@ public class SortedRangeList implements Iterable<Range> {
/**
* Returns an iterator over all the ranges in this list.
* @return the iterator
*/
public Iterator<Range> getRanges() {
return set.iterator();
}
/**
* Returns an iterator over all the ranges in this list that iterates in the direction specified.
* @param forward true indicates to iterate forward from minimum to maximum range.
* false indicates backward iteration form maximum to minimum.
* Returns an iterator over all the ranges in this list that iterates in the direction
* specified.
* @param forward true indicates to iterate forward from minimum to maximum range; false
* indicates backward iteration form maximum to minimum.
* @return the iterator
*/
public Iterator<Range> getRanges(boolean forward) {
if (forward) {
@ -106,6 +106,7 @@ public class SortedRangeList implements Iterable<Range> {
/**
* Returns the minimum int value in this sorted range list.
* @return the min value
* @throws NoSuchElementException if the list is empty.
*/
public int getMin() throws NoSuchElementException {
@ -115,6 +116,7 @@ public class SortedRangeList implements Iterable<Range> {
/**
* Returns the maximum int value in this sorted range list.
* @return the max value
* @throws NoSuchElementException if the list is empty.
*/
public int getMax() throws NoSuchElementException {
@ -124,13 +126,14 @@ public class SortedRangeList implements Iterable<Range> {
/**
* Returns the number of ranges in the list.
* @return the number of ranges
*/
public int getNumRanges() {
return set.size();
}
/**
* Removes the indicated range of values from the list. This will remove
* Removes the indicated range of values from the list. This will remove
* any ranges or portion of ranges that overlap the indicated range.
* @param min the minimum value for the range to remove.
* @param max the maximum value for the range to remove.
@ -182,6 +185,7 @@ public class SortedRangeList implements Iterable<Range> {
/**
* Returns true if the value is contained in any ranges within this list.
* @param value the value to check for.
* @return true if the value is contained in any ranges within this list.
*/
public boolean contains(int value) {
Range key = new Range(value, value);
@ -217,6 +221,7 @@ public class SortedRangeList implements Iterable<Range> {
* Returns true if a single range contains all the values from min to max.
* @param min the minimum value
* @param max the maximum value
* @return true if a single range contains all the values from min to max.
*/
public boolean contains(int min, int max) {
Range range = getRangeContaining(min);
@ -284,9 +289,12 @@ public class SortedRangeList implements Iterable<Range> {
}
/**
* Returns true if the range from min to max intersects (overlaps) any ranges in this sorted range list.
* Returns true if the range from min to max intersects (overlaps) any ranges in this sorted
* range list.
* @param min the range minimum value.
* @param max the range maximum value
* @param max the range maximum value.
* @return true if the range from min to max intersects (overlaps) any ranges in this sorted
* range list.
*/
public boolean intersects(int min, int max) {
Range key = new Range(min, min);
@ -309,6 +317,7 @@ public class SortedRangeList implements Iterable<Range> {
/**
* Returns true if the range list is empty.
* @return true if the range list is empty.
*/
public boolean isEmpty() {
return set.isEmpty();
@ -327,7 +336,8 @@ public class SortedRangeList implements Iterable<Range> {
}
/**
* Creates a new SortedRangeList that is the intersection of this range list and the other range list specified.
* Creates a new SortedRangeList that is the intersection of this range list and the other
* range list specified.
* @param other the other range list
* @return the new SortedRangeList representing the intersection.
*/
@ -339,12 +349,9 @@ public class SortedRangeList implements Iterable<Range> {
return srl2;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuffer buf = new StringBuffer();
StringBuilder buf = new StringBuilder();
Iterator<Range> it = getRanges();
if (it.hasNext()) {
Range r = it.next();
@ -365,4 +372,28 @@ public class SortedRangeList implements Iterable<Range> {
public void clear() {
set.clear();
}
@Override
public int hashCode() {
return Objects.hash(set);
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
SortedRangeList other = (SortedRangeList) obj;
if (!Objects.equals(set, other.set)) {
return false;
}
return true;
}
}

View file

@ -48,10 +48,10 @@ public class ReferenceTagProcessor extends TagProcessor {
this.anchorManager = anchorManager;
//
// Note: currently all help being built has the required stylesheet living under
// Note: currently all help being built has the required stylesheet living under
// <help dir>/shared/<stylesheet name>
//
// If we ever need a more robust styling mechanism, then this code would need to be
//
// If we ever need a more robust styling mechanism, then this code would need to be
// updated to know how to search for the referenced stylesheet
Path helpPath = help.getHelpLocation();
FileSystem fs = helpPath.getFileSystem();
@ -81,8 +81,8 @@ public class ReferenceTagProcessor extends TagProcessor {
if ("a".equals(tagType)) {
if (tagAttributes.containsKey("href")) {
try {
anchorManager.addAnchorRef(
new HREF(help, file, tagAttributes.get("href"), lineNum));
anchorManager
.addAnchorRef(new HREF(help, file, tagAttributes.get("href"), lineNum));
}
catch (URISyntaxException e) {
errorCount++;
@ -102,8 +102,8 @@ public class ReferenceTagProcessor extends TagProcessor {
else if ("img".equals(tagType)) {
if (tagAttributes.containsKey("src")) {
try {
anchorManager.addImageRef(
new IMG(help, file, tagAttributes.get("src"), lineNum));
anchorManager
.addImageRef(new IMG(help, file, tagAttributes.get("src"), lineNum));
}
catch (URISyntaxException e) {
errorCount++;
@ -119,7 +119,7 @@ public class ReferenceTagProcessor extends TagProcessor {
else if ("link".equals(tagType)) {
String rel = tagAttributes.get("rel");
if (rel != null && "stylesheet".equals(rel.toLowerCase())) {
// TODO there is at least one help module that has multiple style sheets. I see no reason to
// TODO there is at least one help module that has multiple style sheets. I see no reason to
// enforce this constraint:
// if (hasStyleSheet) {
// errorCount++;
@ -191,7 +191,8 @@ public class ReferenceTagProcessor extends TagProcessor {
if (!hasDefaultStyleSheet) {
errorCount++;
errors.append("Incorrect stylesheet defined - none match " + defaultStyleSheet +
" in file " + htmlFile + EOL);
" in file " + htmlFile + EOL + "\tDiscovered stylesheets: " + styleSheets + EOL);
}
}

View file

@ -38,10 +38,10 @@ public interface Data extends CodeUnit, Settings {
/**
* Get the class used to express the value of this data.
*
*
* <p>NOTE: This determination is made based upon data type and settings only and does not
* examine memory bytes which are used to construct the data value object.
*
*
* @return value class or null if a consistent class is not utilized.
*/
public Class<?> getValueClass();
@ -216,7 +216,7 @@ public interface Data extends CodeUnit, Settings {
* Return the first immediate child component that contains the byte at the given offset. It
* is important to note that with certain datatypes there may be more than one component
* containing the specified offset (see {@link #getComponentsContaining(int)}).
*
*
* @param offset the amount to add to this data items address to get the address of the
* requested data item.
* @return first data component containing offset or null
@ -227,10 +227,10 @@ public interface Data extends CodeUnit, Settings {
public Data getComponentAt(int offset);
/**
* RReturn the first immediate child component that contains the byte at the given offset. It
* Return the first immediate child component that contains the byte at the given offset. It
* is important to note that with certain datatypes there may be more than one component
* containing the specified offset (see {@link #getComponentsContaining(int)}).
*
*
* @param offset the amount to add to this data items address to get the
* @return first data component containing offset or null address of the requested data item.
*/

View file

@ -17,13 +17,15 @@
package ghidra.program.util;
import java.util.Objects;
import ghidra.framework.options.SaveState;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
/**
* The <CODE>FieldNameFieldLocation</CODE> class provides specific information
* about the Function Name field within a program location.
* The <CODE>FieldNameFieldLocation</CODE> class provides specific information about the Function
* Name field within a program location.
*/
public class FieldNameFieldLocation extends CodeUnitLocation {
@ -31,11 +33,11 @@ public class FieldNameFieldLocation extends CodeUnitLocation {
/**
* Construct a new FieldNameFieldLocation.
*
*
* @param program the program of the location
* @param addr the address of the codeunit.
* @param componentPath if not null, it is the array of indexes that point
* to a specific data type inside of another data type
* @param addr the address of the code unit
* @param componentPath if not null, it is the array of indexes that point to a specific data
* type inside of another data type
* @param fieldName the field name
* @param charOffset the character position within the field name for this location.
*/
@ -48,14 +50,14 @@ public class FieldNameFieldLocation extends CodeUnitLocation {
}
/**
* Default constructor needed for restoring
* a field name location from XML
* Default constructor needed for restoring a field name location from XML
*/
public FieldNameFieldLocation() {
}
/**
* Returns the field name of this location.
* @return the name.
*/
public String getFieldName() {
return fieldName;
@ -71,19 +73,19 @@ public class FieldNameFieldLocation extends CodeUnitLocation {
@Override
public boolean equals(Object obj) {
if (this == obj)
if (this == obj) {
return true;
if (!super.equals(obj))
return false;
if (getClass() != obj.getClass())
return false;
FieldNameFieldLocation other = (FieldNameFieldLocation) obj;
if (fieldName == null) {
if (other.fieldName != null)
return false;
}
else if (!fieldName.equals(other.fieldName))
if (!super.equals(obj)) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FieldNameFieldLocation other = (FieldNameFieldLocation) obj;
if (!Objects.equals(fieldName, other.fieldName)) {
return false;
}
return true;
}

View file

@ -15,14 +15,16 @@
*/
package ghidra.program.util;
import java.util.Objects;
import ghidra.framework.options.SaveState;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.listing.VariableOffset;
/**
* The <CODE>OperandFieldLocation</CODE> class contains specific location information
* within the OPERAND field of a CodeUnitLocation object.
* The <CODE>OperandFieldLocation</CODE> class contains specific location information within the
* OPERAND field of a CodeUnitLocation object.
*/
public class OperandFieldLocation extends CodeUnitLocation {
@ -32,17 +34,18 @@ public class OperandFieldLocation extends CodeUnitLocation {
/**
* Construct a new OperandFieldLocation object.
*
* @param program the program of the location
* @param addr address of the location; should not be null
* @param componentPath array of indexes for each nested data component; the
* index is the data component's index within its parent; may be null
*
* @param program the program of the location.
* @param addr address of the location; should not be null.
* @param componentPath array of indexes for each nested data component; the index is the data
* component's index within its parent; may be null.
* @param refAddr the reference 'to' address.
* @param rep the String representation of the operand.
* @param opIndex the index of the operand at this location.
* @param characterOffset the character position from the beginning of the operand.
*/
public OperandFieldLocation(Program program, Address addr, int[] componentPath,
Address refAddr, String rep, int opIndex, int characterOffset) {
public OperandFieldLocation(Program program, Address addr, int[] componentPath, Address refAddr,
String rep, int opIndex, int characterOffset) {
super(program, addr, componentPath, refAddr, 0, opIndex, characterOffset);
@ -52,68 +55,63 @@ public class OperandFieldLocation extends CodeUnitLocation {
/**
* Construct a new OperandFieldLocation object.
*
* @param program the program of the location
* @param addr address of the location; should not be null
* @param componentPath array of indexes for each nested data component; the
* index is the data component's index within its parent; may be null
* @param refAddr the "referred to" address if the location is
* over a reference; may be null
*
* @param program the program of the location.
* @param addr address of the location; should not be null.
* @param componentPath array of indexes for each nested data component; the index is the data
* component's index within its parent; may be null .
* @param refAddr the "referred to" address if the location is over a reference; may be null.
* @param rep the String representation of the operand.
* @param opIndex the index indicating the operand the location is on.
* @param subOpIndex the index of the Object within the operand, this can
* be used to call an instructions getOpObjects() method
* @param characterOffset the character position from the beginning of the operand field
* @param subOpIndex the index of the Object within the operand, this can be used to call an
* instructions getOpObjects() method.
* @param characterOffset the character position from the beginning of the operand field.
*/
public OperandFieldLocation(Program program, Address addr, int[] componentPath,
Address refAddr, String rep, int opIndex, int subOpIndex, int characterOffset) {
public OperandFieldLocation(Program program, Address addr, int[] componentPath, Address refAddr,
String rep, int opIndex, int subOpIndex, int characterOffset) {
super(program, addr, componentPath, refAddr, 0, opIndex, characterOffset);
this.rep = rep;
this.subOpIndex = subOpIndex;
}
/**
* Construct a new OperandFieldLocation object for an instruction operand.
*
* @param program the program of the location
* @param addr address of the location; should not be null
* @param variableOffset associated variable offset or null
* @param refAddr the "referred to" address if the location is
* over a reference; may be null
*
* @param program the program of the location.
* @param addr address of the location; should not be null.
* @param variableOffset associated variable offset or null.
* @param refAddr the "referred to" address if the location is over a reference; may be null.
* @param rep the String representation of the operand.
* @param opIndex the index indicating the operand the location is on.
* @param subOpIndex the index of the Object within the operand, this can
* be used to call an instructions getOpObjects() method
* @param characterOffset the character position from the beginning of the operand field
* @param subOpIndex the index of the Object within the operand, this can be used to call an
* instructions getOpObjects() method.
* @param characterOffset the character position from the beginning of the operand field.
*/
public OperandFieldLocation(Program program, Address addr, VariableOffset variableOffset,
Address refAddr, String rep, int opIndex, int subOpIndex, int characterOffset) {
super(program, addr, null, refAddr, 0, opIndex, characterOffset);
this.rep = rep;
this.subOpIndex = subOpIndex;
this.variableOffset = variableOffset;
}
/**
* Default constructor needed for restoring
* an operand field location from XML.
*/
* Default constructor needed for restoring an operand field location from XML.
*/
public OperandFieldLocation() {
}
/**
* Returns VariableOffset object if applicable or null
* Returns VariableOffset object if applicable or null.
* @return the variable offset.
*/
public VariableOffset getVariableOffset() {
return variableOffset;
}
/**
* Returns a string representation of the opernand at this location.
* Returns a string representation of the operand at this location.
* @return the representation.
*/
public String getOperandRepresentation() {
return rep;
@ -121,6 +119,7 @@ public class OperandFieldLocation extends CodeUnitLocation {
/**
* Returns the index of the operand at this location.
* @return the index
*/
public int getOperandIndex() {
return getColumn();
@ -128,18 +127,15 @@ public class OperandFieldLocation extends CodeUnitLocation {
/**
* Returns the sub operand index at this location.
* This index can be used on the instruction.getOpObjects()
* to find the actual object (Address, Register, Scalar) the
* cursor is over.
* <p>
* This index can be used on the instruction.getOpObjects() to find the actual object (Address,
* Register, Scalar) the cursor is over.
* @return 0-n if over a valid OpObject, -1 otherwise
*/
public int getSubOperandIndex() {
return subOpIndex;
}
/**
* Returns a String representation of this location.
*/
@Override
public String toString() {
return super.toString() + ", OpRep = " + rep + ", subOpIndex = " + subOpIndex +
@ -158,27 +154,25 @@ public class OperandFieldLocation extends CodeUnitLocation {
@Override
public boolean equals(Object obj) {
if (this == obj)
if (this == obj) {
return true;
if (!super.equals(obj))
}
if (!super.equals(obj)) {
return false;
if (getClass() != obj.getClass())
}
if (getClass() != obj.getClass()) {
return false;
}
OperandFieldLocation other = (OperandFieldLocation) obj;
if (rep == null) {
if (other.rep != null)
return false;
if (!Objects.equals(rep, other.rep)) {
return false;
}
else if (!rep.equals(other.rep))
if (subOpIndex != other.subOpIndex) {
return false;
if (subOpIndex != other.subOpIndex)
return false;
if (variableOffset == null) {
if (other.variableOffset != null)
return false;
}
else if (!variableOffset.equals(other.variableOffset))
if (!Objects.equals(variableOffset, other.variableOffset)) {
return false;
}
return true;
}

View file

@ -95,7 +95,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
* Construct a new ProgramLocation for the given address. The address will be adjusted to the
* beginning of the {@link CodeUnit code unit} containing that address (if it exists). The
* original address can be retrieved using the {@link #getByteAddress()}" method.
*
*
* @param program the program associated with this program location (also used to obtain a
* code-unit-aligned address)
* @param addr address of the location; cannot be null
@ -118,7 +118,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
* Construct a new ProgramLocation for the given address. The address will be adjusted to the
* beginning of the {@link CodeUnit code unit} containing that address (if it exists). The
* original address can be retrieved using the {@link #getByteAddress()} method.
*
*
* @param program the program associated with this program location (also used to obtain a
* code-unit-aligned address)
* @param addr address for the location
@ -132,7 +132,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
* Construct a new ProgramLocation for the given address. The address will be adjusted to the
* beginning of the {@link CodeUnit code unit} containing that address (if it exists). The
* original address can be retrieved using the {@link #getByteAddress()} method.
*
*
* @param program the program associated with this program location (also used to obtain a
* code-unit-aligned address)
* @param addr address for the location
@ -150,7 +150,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
* Construct a new ProgramLocation for the given address. The address will be adjusted to the
* beginning of the {@link CodeUnit code unit} containing that address (if it exists). The
* original address can be retrieved using the {@link #getByteAddress()} method.
*
*
* @param program the program associated with this program location (also used to obtain a
* code-unit-aligned address)
* @param addr address for the location
@ -170,6 +170,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the componentPath for the {@link CodeUnit code unit}. Null will be returned if the
* object is an {@link Instruction} or a top-level {@link Data} object.
* @return the path.
*/
public int[] getComponentPath() {
return componentPath;
@ -177,6 +178,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the program associated with this location.
* @return the program.
*/
public Program getProgram() {
return program;
@ -184,11 +186,12 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the address associated with this location.
*
*
* <p>
* Note: this may not be the same as the byte address. For example, in a {@link CodeUnit code
* unit} location this may be the minimum address of the code unit that contains the byte
* address.
* @return the address.
*/
public Address getAddress() {
return addr;
@ -196,6 +199,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the byte level address associated with this location.
* @return the byte address.
*/
public Address getByteAddress() {
return byteAddr;
@ -203,6 +207,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the "referred to" address if the location is over an address in some field.
* @return the address.
*/
public Address getRefAddress() {
return refAddr;
@ -210,7 +215,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Save this program location to the given save state object.
*
*
* @param obj the save state object for saving the location
*/
public void saveState(SaveState obj) {
@ -231,7 +236,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Restore this program location using the given program and save state object.
*
*
* @param program1 program to restore from
* @param obj the save state to restore from
*/
@ -254,7 +259,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Get the program location for the given program and save state object.
*
*
* @param program the program for the location
* @param saveState the state to restore
* @return the restored program location
@ -274,7 +279,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
}
// no address, it must be in a removed block; we can't use it
}
catch (RuntimeException e) { // restoreState may not parse the address if it is no longer valid.
catch (RuntimeException e) { // state may not parse the address if it is no longer valid
}
catch (ClassNotFoundException e) {
// not sure why we are ignoring this--if you know, then please let everyone else know
@ -419,7 +424,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
}
CodeUnit cu = p.getListing().getCodeUnitContaining(addr);
// if the codeunit is a data, try and dig down to the lowest subdata containing the address
// if the code unit is data, get the lowest sub-data containing the address
if (cu instanceof Data) {
Data data = (Data) cu;
cu = data.getPrimitiveAt((int) addr.subtract(data.getAddress()));
@ -437,10 +442,10 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
}
/**
* Returns true if this location represents a valid location in the given program
*
* Returns true if this location represents a valid location in the given program.
*
* @param testProgram the program to test if this location is valid.
* @return true if this location represents a valid location in the given program
* @return true if this location represents a valid location in the given program.
*/
public boolean isValid(Program testProgram) {
return addr == null || testProgram.getAddressFactory().isValidAddress(addr);
@ -448,7 +453,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the row within the program location.
*
*
* @return the row within the program location.
*/
public int getRow() {
@ -456,9 +461,9 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
}
/**
* Returns the character offset in the display item at the (row,col)
*
* @return the character offset in the display item at the (row,col)
* Returns the character offset in the display item at the (row,col).
*
* @return the character offset in the display item at the (row,col).
*/
public int getCharOffset() {
return charOffset;
@ -467,6 +472,7 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
/**
* Returns the column index of the display piece represented by this location. For most
* locations, there is only one display item per row, in which case this value will be 0.
* @return the column.
*/
public int getColumn() {
return col;

View file

@ -0,0 +1,34 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utility.function;
/**
* A generic functional interface that is more semantically sound than {@link Runnable}. Use
* anywhere you wish to have a generic callback function and you need to throw an exception.
*
* @param <T> the return type of your choice
* @param <E> the exception of your choice
*/
@FunctionalInterface
public interface ExceptionalSupplier<T, E extends Exception> {
/**
* The supplier method
* @return the item to return
* @throws E the declared exception
*/
public T get() throws E;
}