Merge branch 'GP-5586_ghidra1_StackEditorIssues'

This commit is contained in:
ghidra1
2025-04-25 15:33:22 -04:00
25 changed files with 4724 additions and 1964 deletions
File diff suppressed because it is too large Load Diff
@@ -511,7 +511,7 @@ def on_breakpoint_hit(*args) -> None:
@log_errors
def on_exception(*args) -> None:
# print("ON_EXCEPTION: args={}".format(args))
return DbgEng.DEBUG_STATUS_BREAK
return DbgEng.DEBUG_STATUS_NO_CHANGE
@util.dbg.eng_thread
@@ -419,11 +419,7 @@ public abstract class AbstractTraceRmiLaunchOffer implements TraceRmiLaunchOffer
if (program == null) {
return state;
}
SaveState pstate = plugin.readProgramLaunchConfig(program, getConfigName(), forPrompt);
if (!pstate.isEmpty()) {
state = pstate;
}
return state;
return plugin.readProgramLaunchConfig(program, getConfigName(), forPrompt);
}
/**
@@ -248,17 +248,17 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
return true;
}
@Override
public DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
throws UsrException {
dtString = DataTypeHelper.stripWhiteSpace(dtString);
if ((dtString == null) || (dtString.length() < 1)) {
if (rowIndex == getNumComponents()) {
return null;
}
}
return super.validateComponentDataType(rowIndex, dtString);
}
// @Override
// public DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
// throws UsrException {
// dtString = DataTypeHelper.stripWhiteSpace(dtString);
// if ((dtString == null) || (dtString.length() < 1)) {
// if (rowIndex == getNumComponents()) {
// return null;
// }
// }
// return super.validateComponentDataType(rowIndex, dtString);
// }
@Override
public boolean isAddAllowed(DataType dataType) {
@@ -894,18 +894,18 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
protected abstract void replaceOriginalComponents();
@Override
protected void checkIsAllowableDataType(DataType datatype) throws InvalidDataTypeException {
protected void checkIsAllowableDataType(DataType dataType) throws InvalidDataTypeException {
super.checkIsAllowableDataType(datatype);
super.checkIsAllowableDataType(dataType);
// Verify that we aren't adding this structure or anything that it is
// part of to this editable structure.
if (datatype.equals(viewComposite)) {
String msg = "Data type \"" + datatype.getDisplayName() + "\" can't contain itself.";
if (dataType.equals(viewComposite)) {
String msg = "Data type \"" + dataType.getDisplayName() + "\" can't contain itself.";
throw new InvalidDataTypeException(msg);
}
else if (DataTypeUtilities.isSecondPartOfFirst(datatype, viewComposite)) {
String msg = "Data type \"" + datatype.getDisplayName() + "\" has \"" +
else if (DataTypeUtilities.isSecondPartOfFirst(dataType, viewComposite)) {
String msg = "Data type \"" + dataType.getDisplayName() + "\" has \"" +
viewComposite.getDisplayName() + "\" within it.";
throw new InvalidDataTypeException(msg);
}
@@ -1314,25 +1314,25 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
return;
}
DataType dataType = viewDTM.getDataType(path.getCategoryPath(), path.getDataTypeName());
DataType dataType = viewDTM.getDataType(path);
if (dataType == null) {
return;
}
if (!path.equals(originalDataTypePath)) {
DataType dt = viewDTM.getDataType(path);
if (dt != null) {
if (hasSubDt(viewComposite, path)) {
String msg = "Removed sub-component data type \"" + path;
setStatus(msg, true);
}
viewDTM.withTransaction("Removed Dependency", () -> {
viewDTM.clearUndoOnChange();
viewDTM.remove(dt, TaskMonitor.DUMMY);
});
fireTableDataChanged();
componentDataChanged();
if (!viewDTM.isViewDataTypeFromOriginalDTM(dataType)) {
return;
}
if (hasSubDt(viewComposite, path)) {
String msg = "Removed sub-component data type \"" + path;
setStatus(msg, true);
}
viewDTM.withTransaction("Removed Dependency", () -> {
viewDTM.clearUndoOnChange();
viewDTM.remove(dataType, TaskMonitor.DUMMY);
});
fireTableDataChanged();
componentDataChanged();
return;
}
@@ -1366,56 +1366,7 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
@Override
public void dataTypeRenamed(DataTypeManager dtm, DataTypePath oldPath, DataTypePath newPath) {
if (dtm != originalDTM) {
throw new AssertException("Listener only supports original DTM");
}
if (!isLoaded()) {
return;
}
if (oldPath.getDataTypeName().equals(newPath.getDataTypeName())) {
return;
}
String newName = newPath.getDataTypeName();
String oldName = oldPath.getDataTypeName();
// Does the old name match our original name.
// Check originalCompositeId to ensure original type is managed
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
oldPath.equals(originalDataTypePath)) {
originalDataTypePath = newPath;
try {
if (viewComposite.getName().equals(oldName)) {
setName(newName);
}
}
catch (InvalidNameException | DuplicateNameException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
return;
}
// Check for managed datatype changing
DataType dt = viewDTM.getDataType(oldPath);
if (dt == null) {
return;
}
viewDTM.withTransaction("Renamed Dependency", () -> {
viewDTM.clearUndoOnChange();
try {
dt.setName(newPath.getDataTypeName());
}
catch (InvalidNameException | DuplicateNameException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
});
fireTableDataChanged();
componentDataChanged();
dataTypeMoved(dtm, oldPath, newPath);
}
@Override
@@ -1429,31 +1380,64 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
return;
}
DataType dt = viewDTM.getDataType(oldPath);
if (dt == null) {
if (oldPath.equals(newPath)) {
return;
}
try {
viewDTM.withTransaction("Moved " + oldPath, () -> {
viewDTM.clearUndoOnChange();
Category newDtCat = viewDTM.createCategory(newPath.getCategoryPath());
newDtCat.moveDataType(dt, null);
});
}
catch (DataTypeDependencyException e) {
throw new AssertException(e);
}
String newName = newPath.getDataTypeName();
String oldName = oldPath.getDataTypeName();
if (originalDataTypePath.getDataTypeName().equals(newPath.getDataTypeName()) &&
originalDataTypePath.getCategoryPath().equals(oldPath.getCategoryPath())) {
originalDataTypePath = newPath;
CategoryPath newCategoryPath = newPath.getCategoryPath();
CategoryPath oldCategoryPath = oldPath.getCategoryPath();
// Does the old name match our original name.
// Check originalCompositeId to ensure original type is managed
if (originalCompositeId != DataTypeManager.NULL_DATATYPE_ID &&
oldPath.equals(originalDataTypePath)) {
viewDTM.withTransaction("Name Changed", () -> {
viewDTM.clearUndoOnChange();
originalDataTypePath = newPath;
try {
if (viewComposite.getName().equals(oldName)) {
setName(newName);
}
if (!newCategoryPath.equals(oldCategoryPath)) {
viewComposite.setCategoryPath(newCategoryPath);
}
}
catch (InvalidNameException | DuplicateNameException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
});
compositeInfoChanged();
}
else {
fireTableDataChanged();
componentDataChanged();
// Check for managed datatype changing
DataType originalDt = originalDTM.getDataType(newPath);
if (!(originalDt instanceof DatabaseObject)) {
return;
}
DataType dt = viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(originalDt));
if (dt == null) {
return;
}
viewDTM.withTransaction("Renamed Dependency", () -> {
viewDTM.clearUndoOnChange();
try {
dt.setName(newName);
if (!newCategoryPath.equals(oldCategoryPath)) {
dt.setCategoryPath(newCategoryPath);
}
}
catch (InvalidNameException | DuplicateNameException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
});
}
fireTableDataChanged();
componentDataChanged();
}
@Override
@@ -1517,11 +1501,10 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
// potentially many types getting changed by one change.
DataType changedDt = originalDTM.getDataType(path);
if (!(changedDt instanceof DatabaseObject)) {
// NOTE: viewDTM only maps view-to-original IDs for DataTypeDB
return;
}
long originalId = originalDTM.getID(changedDt);
DataType viewDt = viewDTM.findMyDataTypeFromOriginalID(originalId);
DataType viewDt =
viewDTM.findMyDataTypeFromOriginalID(originalDTM.getID(changedDt));
if (viewDt == null) {
return;
}
@@ -1562,30 +1545,32 @@ public abstract class CompEditorModel<T extends Composite> extends CompositeEdit
if (!oldPath.equals(originalDataTypePath)) {
// Check for type which may be referenced by viewComposite
DataType dt = viewDTM.getDataType(oldPath);
if (dt != null) {
if (hasSubDt(viewComposite, oldPath)) {
String msg = "Replaced data type \"" + oldPath +
"\", which is a sub-component of \"" + getOriginalDataTypeName() + "\".";
setStatus(msg, true);
}
// NOTE: depending upon event sequence and handling a
// re-load may have occurred and replacement may be unnecessary
try {
viewDTM.withTransaction("Replaced Dependency", () -> {
viewDTM.clearUndoOnChange();
viewDTM.replaceDataType(dt, newDataType, true);
});
}
catch (DataTypeDependencyException e) {
throw new AssertException(e);
}
// Clear undo/redo stack to avoid inconsistency with originalDTM
viewDTM.clearUndo();
fireTableDataChanged();
componentDataChanged();
if (dt == null || !viewDTM.isViewDataTypeFromOriginalDTM(dt)) {
return;
}
if (hasSubDt(viewComposite, oldPath)) {
String msg = "Replaced data type \"" + oldPath +
"\", which is a sub-component of \"" + getOriginalDataTypeName() + "\".";
setStatus(msg, true);
}
// NOTE: depending upon event sequence and handling a
// re-load may have occurred and replacement may be unnecessary
try {
viewDTM.withTransaction("Replaced Dependency", () -> {
viewDTM.clearUndoOnChange();
viewDTM.replaceDataType(dt, newDataType, true);
});
}
catch (DataTypeDependencyException e) {
throw new AssertException(e);
}
// Clear undo/redo stack to avoid inconsistency with originalDTM
viewDTM.clearUndo();
fireTableDataChanged();
componentDataChanged();
return;
}
@@ -157,7 +157,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
originalDataTypePath = originalComposite.getDataTypePath();
currentName = dataType.getName();
createViewCompositeFromOriginalComposite(originalComposite);
createViewCompositeFromOriginalComposite();
// Listen so we can update editor if name changes for this structure.
originalDTM.addDataTypeManagerListener(this);
@@ -204,12 +204,10 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
}
/**
* Create {@code viewComposite} and associated view datatype manager ({@code viewDTM}) and
* changes listener(s) if required.
*
* @param original original composite being loaded
* Create {@code viewComposite} and {@link CompositeViewerDataTypeManager viewDTM} for this
* editor and the {@code originalComposite}.
*/
protected void createViewCompositeFromOriginalComposite(T original) {
protected void createViewCompositeFromOriginalComposite() {
if (viewDTM != null) {
viewDTM.close();
@@ -217,8 +215,9 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
}
// Use temporary standalone view datatype manager
viewDTM = new CompositeViewerDataTypeManager<>(original.getDataTypeManager().getName(),
original, this::componentEdited, this::restoreEditor);
viewDTM =
new CompositeViewerDataTypeManager<>(originalComposite.getDataTypeManager().getName(),
originalComposite, this::componentEdited, this::restoreEditor);
viewComposite = viewDTM.getResolvedViewComposite();
@@ -230,7 +229,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
// underlying datatype default setting value being presented when adjusting component
// default settings.
viewDTM.withTransaction("Load Settings",
() -> cloneAllComponentSettings(original, viewComposite));
() -> cloneAllComponentSettings(originalComposite, viewComposite));
viewDTM.clearUndo();
}
@@ -317,7 +316,6 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
throw new InvalidDataTypeException("Data types of size 0 are not allowed.");
}
// TODO: Need to handle proper placement for big-endian within a larger component (i.e., right-justified)
return DataTypeInstance.getDataTypeInstance(resultDt, resultLen,
viewComposite.isPackingEnabled());
}
@@ -481,13 +479,13 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
dtName = previousDt.getDisplayName();
}
DataType newDt = null;
int newLength = -1;
int newLength;
if (dataTypeObject instanceof DataTypeInstance dti) {
newDt = resolve(dti.getDataType());
newDt = dti.getDataType();
newLength = dti.getLength();
}
else if (dataTypeObject instanceof DataType dt) {
newDt = resolve(dt);
newDt = dt;
newLength = newDt.getLength();
}
else if (dataTypeObject instanceof String dtString) {
@@ -506,6 +504,9 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
newLength = 0;
}
DataType dataType = newDt.clone(originalDTM);
newLength = newDt.getLength();
checkIsAllowableDataType(newDt);
if (newLength < 0) {
@@ -535,8 +536,7 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
}
// Set component datatype and length on view composite
DataType dataType = resolve(newDt); // probably already resolved
setComponentDataTypeInstance(rowIndex, dataType, newLength);
setComponentDataTypeInstance(rowIndex, newDt, newLength);
return true;
});
@@ -1434,51 +1434,51 @@ abstract public class CompositeEditorModel<T extends Composite> extends Composit
* @return a valid data type instance or null if at blank line with no data type name.
* @throws UsrException indicating that the data type is not valid.
*/
protected DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
throws UsrException {
DataType dt = null;
String dtName = "";
dtString = DataTypeHelper.stripWhiteSpace(dtString);
DataTypeComponent element = getComponent(rowIndex);
if (element != null) {
dt = element.getDataType();
dtName = dt.getDisplayName();
if (dtString.equals(dtName)) {
return DataTypeInstance.getDataTypeInstance(element.getDataType(),
element.getLength(), usesAlignedLengthComponents());
}
}
int newLength = 0;
DataType newDt = DataTypeHelper.parseDataType(rowIndex, dtString, this, originalDTM,
provider.dtmService);
if (newDt == null) {
if (dt != null) {
throw new UsrException("No data type was specified.");
}
throw new AssertException("Can't set data type to null.");
}
checkIsAllowableDataType(newDt);
newLength = newDt.getLength();
if (newLength < 0) {
DataTypeInstance sizedDataType = DataTypeHelper.getSizedDataType(provider, newDt,
lastNumBytes, getMaxReplaceLength(rowIndex));
newLength = sizedDataType.getLength();
}
newDt = viewDTM.resolve(newDt, null);
int maxLength = getMaxReplaceLength(rowIndex);
if (newLength <= 0) {
throw new UsrException("Can't currently add this data type.");
}
if (maxLength > 0 && newLength > maxLength) {
throw new UsrException(newDt.getDisplayName() + " doesn't fit.");
}
return DataTypeInstance.getDataTypeInstance(newDt, newLength,
usesAlignedLengthComponents());
}
// protected DataTypeInstance validateComponentDataType(int rowIndex, String dtString)
// throws UsrException {
// DataType dt = null;
// String dtName = "";
// dtString = DataTypeHelper.stripWhiteSpace(dtString);
// DataTypeComponent element = getComponent(rowIndex);
// if (element != null) {
// dt = element.getDataType();
// dtName = dt.getDisplayName();
// if (dtString.equals(dtName)) {
// return DataTypeInstance.getDataTypeInstance(element.getDataType(),
// element.getLength(), usesAlignedLengthComponents());
// }
// }
//
// int newLength = 0;
// DataType newDt = DataTypeHelper.parseDataType(rowIndex, dtString, this, originalDTM,
// provider.dtmService);
// if (newDt == null) {
// if (dt != null) {
// throw new UsrException("No data type was specified.");
// }
// throw new AssertException("Can't set data type to null.");
// }
//
// checkIsAllowableDataType(newDt);
//
// newLength = newDt.getLength();
// if (newLength < 0) {
// DataTypeInstance sizedDataType = DataTypeHelper.getSizedDataType(provider, newDt,
// lastNumBytes, getMaxReplaceLength(rowIndex));
// newLength = sizedDataType.getLength();
// }
//
// newDt = viewDTM.resolve(newDt, null);
// int maxLength = getMaxReplaceLength(rowIndex);
// if (newLength <= 0) {
// throw new UsrException("Can't currently add this data type.");
// }
// if (maxLength > 0 && newLength > maxLength) {
// throw new UsrException(newDt.getDisplayName() + " doesn't fit.");
// }
// return DataTypeInstance.getDataTypeInstance(newDt, newLength,
// usesAlignedLengthComponents());
// }
@SuppressWarnings("unused") // the exception is thrown by subclasses
protected void validateComponentName(int rowIndex, String name) throws UsrException {
@@ -47,8 +47,7 @@ import utilities.util.reflection.ReflectionUtilities;
* @param <M> Specific {@link CompositeEditorModel} implementation which supports editing T
*/
public abstract class CompositeEditorProvider<T extends Composite, M extends CompositeEditorModel<T>>
extends ComponentProviderAdapter
implements EditorProvider, EditorActionListener {
extends ComponentProviderAdapter implements EditorProvider, EditorActionListener {
protected static final Icon EDITOR_ICON = new GIcon("icon.plugin.composite.editor.provider");
@@ -317,7 +316,7 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
// Check for changes and prompt user to check if saving them.
if (editorModel.isValidName() && editorModel.hasChanges()) {
String question = "The " + editorModel.getTypeName() + " Editor is closing.\n" +
"Save the changes to " + getDtPath() + "?";
"Save the changes to " + getDisplayName() + "?";
String title = "Save " + editorModel.getTypeName() + " Editor Changes?";
int response;
if (allowCancel) {
@@ -337,6 +336,10 @@ public abstract class CompositeEditorProvider<T extends Composite, M extends Com
return 2;
}
protected String getDisplayName() {
return getDtPath().toString();
}
@Override
public String getWindowSubMenuName() {
return getName();
@@ -19,6 +19,8 @@ import java.io.IOException;
import java.util.Iterator;
import java.util.TreeSet;
import javax.help.UnsupportedOperationException;
import db.util.ErrorHandler;
import ghidra.program.database.DatabaseObject;
import ghidra.program.model.data.*;
@@ -66,16 +68,15 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
private TreeSet<Long> orphanIds = new TreeSet<>();
/**
* Creates a data type manager that the structure editor will use internally for managing
* dependencies for an unmanaged structure being edited. A single transaction will be started
* with this instantiation and held open until this instance is closed. Undo/redo is
* not be supported.
* Creates a data type manager that the composite editor will use internally for managing
* dependencies without resolving the actual composite being edited. A single transaction
* will be started with this instantiation and held open until this instance is closed.
* Undo/redo and datatype pruning is not be supported.
* @param rootName the root name for this data type manager (usually the program name).
* @param originalDTM the original data type manager.
*/
public CompositeViewerDataTypeManager(String rootName, DataTypeManager originalDTM) {
this(rootName, originalDTM, null, null, null);
clearUndo();
transactionId = startTransaction("Composite Edit");
}
@@ -123,8 +124,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
@SuppressWarnings("unchecked")
private T resolveViewComposite() {
return originalComposite != null ? (T) super.resolve(originalComposite, null)
: null;
return originalComposite != null ? (T) super.resolve(originalComposite, null) : null;
}
private void initializeArchitecture() {
@@ -158,12 +158,18 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
@Override
public void undo() {
if (!isUndoRedoAllowed()) {
throw new UnsupportedOperationException();
}
dataTypeIDMap.invalidate();
super.undo();
}
@Override
public void redo() {
if (!isUndoRedoAllowed()) {
throw new UnsupportedOperationException();
}
dataTypeIDMap.invalidate();
super.redo();
}
@@ -237,10 +243,12 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
public DataType replaceDataType(DataType existingViewDt, DataType replacementDt,
boolean updateCategoryPath) throws DataTypeDependencyException {
long viewDtId = getID(existingViewDt);
if (existingViewDt.getDataTypeManager() != this) {
throw new IllegalArgumentException("datatype is not from this manager");
}
if (existingViewDt instanceof DatabaseObject) {
dataTypeIDMap.remove(viewDtId);
dataTypeIDMap.remove(getID(existingViewDt));
}
DataType newResolvedDt =
@@ -259,10 +267,12 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
@Override
public boolean remove(DataType existingViewDt, TaskMonitor monitor) {
long viewDtId = getID(existingViewDt);
if (existingViewDt.getDataTypeManager() != this) {
throw new IllegalArgumentException("datatype is not from this manager");
}
if (existingViewDt instanceof DatabaseObject) {
dataTypeIDMap.remove(viewDtId);
dataTypeIDMap.remove(getID(existingViewDt));
}
return super.remove(existingViewDt, monitor);
@@ -373,7 +383,7 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
if (committed && dataTypeChanged && changeCallback != null) {
Swing.runLater(() -> changeCallback.call());
}
if (getTransactionCount() == 0) {
dataTypeChanged = false;
}
@@ -432,14 +442,53 @@ public class CompositeViewerDataTypeManager<T extends Composite> extends StandAl
}
}
public DataType findOriginalDataTypeFromMyID(long myId) {
Long originalId = dataTypeIDMap.getOriginalIDFromViewID(myId);
return originalId != null ? originalDTM.getDataType(originalId) : null;
}
/**
* Find a resolved DB-datatype within this manager based upon its source datatype's ID
* within the original datatype manager associated with this manager. This method is
* useful when attempting to matchup a datatype within this manager to one which has changed
* within the original datatype manager.
*
* @param originalId datatype ID within original datatype manager
* @return matching DB-datatype or null if not found
*/
public DataType findMyDataTypeFromOriginalID(long originalId) {
Long myId = dataTypeIDMap.getViewIDFromOriginalID(originalId);
return myId != null ? getDataType(myId) : null;
}
/**
* Find a resolved DB-datatype within the original datatype manager based upon a resolved
* datatype's ID within this manager. This method is useful when attempting to matchup a
* datatype within this manager to one which has possibly changed within the original
* datatype manager.
*
* @param myId resolved datatype ID within this datatype manager
* @return matching DB-datatype or null if not found
*/
public DataType findOriginalDataTypeFromMyID(long myId) {
Long originalId = dataTypeIDMap.getOriginalIDFromViewID(myId);
return originalId != null ? originalDTM.getDataType(originalId) : null;
}
/**
* Determine if the specified datatype which has previsouly been resolved to this datatype
* manager originated from original composite's source (e.g., program).
* <P>
* NOTE: Non-DB datatypes will always return false.
*
* @param existingViewDt existing datatype which has previously been resolved to this
* datatype manager.
* @return true if specified datatype originated from this manager's associated original
* datatype manager.
*/
public boolean isViewDataTypeFromOriginalDTM(DataType existingViewDt) {
if (existingViewDt.getDataTypeManager() != this) {
throw new IllegalArgumentException("datatype is not from this manager");
}
if (!(existingViewDt instanceof DatabaseObject)) {
return false;
}
return dataTypeIDMap.getOriginalIDFromViewID(getID(existingViewDt)) != null;
}
}
@@ -199,35 +199,35 @@ abstract class CompositeViewerModel<T extends Composite> extends AbstractTableMo
}
}
/**
* Resolves the data type against the indicated data type manager using the specified
* conflictHandler. In general, a transaction should have already been initiated prior to
* calling this method so that the true nature of the transaction may be established for
* use with undo/redo (e.g., Set Datatype).
*
* @param dataType the data type to be resolved
* @param resolveDtm the data type manager to resolve the data type against
* @param conflictHandler the handler to be used for any conflicts encountered while resolving
* @return the resolved data type
*/
protected final DataType resolveDataType(DataType dataType, DataTypeManager resolveDtm,
DataTypeConflictHandler conflictHandler) {
if (resolveDtm == null || dataType == DataType.DEFAULT) {
return DataType.DEFAULT;
}
return resolveDtm.withTransaction("Resolve " + dataType.getPathName(), () -> {
return resolveDtm.resolve(dataType, conflictHandler);
});
}
/**
* Resolves the indicated data type against the working copy in the viewer's data type manager.
* @param dataType the data type
* @return the working copy of the data type.
*/
public DataType resolve(DataType dataType) {
return resolveDataType(dataType, viewDTM, null);
}
// /**
// * Resolves the data type against the indicated data type manager using the specified
// * conflictHandler. In general, a transaction should have already been initiated prior to
// * calling this method so that the true nature of the transaction may be established for
// * use with undo/redo (e.g., Set Datatype).
// *
// * @param dataType the data type to be resolved
// * @param resolveDtm the data type manager to resolve the data type against
// * @param conflictHandler the handler to be used for any conflicts encountered while resolving
// * @return the resolved data type
// */
// protected final DataType resolveDataType(DataType dataType, DataTypeManager resolveDtm,
// DataTypeConflictHandler conflictHandler) {
// if (resolveDtm == null || dataType == DataType.DEFAULT) {
// return DataType.DEFAULT;
// }
// return resolveDtm.withTransaction("Resolve " + dataType.getPathName(), () -> {
// return resolveDtm.resolve(dataType, conflictHandler);
// });
// }
//
// /**
// * Resolves the indicated data type against the working copy in the viewer's data type manager.
// * @param dataType the data type
// * @return the working copy of the data type.
// */
// public DataType resolve(DataType dataType) {
// return resolveDataType(dataType, viewDTM, null);
// }
/**
* Gets the current row
@@ -1,44 +0,0 @@
/* ###
* 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 ghidra.app.plugin.core.stackeditor;
import ghidra.program.model.data.*;
public interface BiDirectionStructure extends Structure {
/**
* Get the length of this DataType in the negative direction.
* @return the length of this DataType in the negative direction.
*/
public abstract int getNegativeLength();
/**
* Get the length of this DataType in the positive direction.
* @return the length of this DataType in the positive direction.
*/
public abstract int getPositiveLength();
/**
* Get the component offset which represents the division point
* between the positive and negative halves of the structure.
* @return split offset
*/
public abstract int getSplitOffset();
public DataTypeComponent addNegative(DataType dataType, int length, String name, String comment);
public DataTypeComponent addPositive(DataType dataType, int length, String name, String comment);
}
@@ -23,16 +23,13 @@ import ghidra.app.plugin.core.compositeeditor.*;
import ghidra.framework.model.*;
import ghidra.framework.plugintool.Plugin;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataTypePath;
import ghidra.program.model.listing.Function;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.Symbol;
import ghidra.program.model.symbol.SymbolType;
import ghidra.program.util.ProgramChangeRecord;
import ghidra.program.util.ProgramEvent;
import ghidra.util.InvalidNameException;
import ghidra.util.Msg;
import ghidra.util.task.SwingUpdateManager;
/**
* Editor for a Function Stack.
@@ -45,6 +42,31 @@ public class StackEditorProvider
private Function function;
private StackEditorModel stackModel;
boolean scheduleRefreshName = false;
boolean scheduleReload = false;
/**
* Delay model update caused by Program change events.
*/
SwingUpdateManager delayedUpdateMgr = new SwingUpdateManager(200, 200, () -> {
try {
if (function.isDeleted()) {
stackModel.functionChanged(false);
return;
}
if (scheduleRefreshName) {
updateTitle();
}
if (scheduleReload) {
stackModel.functionChanged(false);
}
}
finally {
scheduleRefreshName = false;
scheduleReload = false;
}
});
public StackEditorProvider(Plugin plugin, Function function) {
super(plugin);
this.program = function.getProgram();
@@ -56,15 +78,22 @@ public class StackEditorProvider
initializeActions();
editorPanel = new StackEditorPanel(program, stackModel, this);
setTitle(getName() + " - " + getProviderSubTitle(function));
updateTitle();
plugin.getTool().addComponentProvider(this, true);
addActionsToTool();
editorPanel.getTable().requestFocus();
}
@Override
protected void updateTitle() {
setTabText(function.getName());
setTitle(getName() + " - " + getProviderSubTitle(function));
}
@Override
public void dispose() {
delayedUpdateMgr.dispose();
program.removeListener(this);
super.dispose();
}
@@ -84,6 +113,11 @@ public class StackEditorProvider
return "Stack Editor";
}
@Override
protected String getDisplayName() {
return "stack frame: " + function.getName();
}
@Override
public String getHelpName() {
return "Stack_Editor";
@@ -147,32 +181,6 @@ public class StackEditorProvider
return actionMgr.getAllActions();
}
private void refreshName() {
StackFrameDataType origDt = stackModel.getOriginalComposite();
StackFrameDataType viewDt = stackModel.getEditorStack();
String oldName = origDt.getName();
String newName = function.getName();
if (oldName.equals(newName)) {
return;
}
setTitle("Stack Editor: " + newName);
try {
origDt.setName(newName);
if (viewDt.getName().equals(oldName)) {
viewDt.setName(newName);
}
}
catch (InvalidNameException e) {
Msg.error(this, "Unexpected Exception: " + e.getMessage(), e);
}
CategoryPath oldCategoryPath = origDt.getCategoryPath();
DataTypePath oldDtPath = new DataTypePath(oldCategoryPath, oldName);
DataTypePath newDtPath = new DataTypePath(oldCategoryPath, newName);
stackModel.dataTypeRenamed(stackModel.getOriginalDataTypeManager(), oldDtPath, newDtPath);
}
@Override
public void domainObjectChanged(DomainObjectChangedEvent event) {
if (!isVisible()) {
@@ -181,35 +189,40 @@ public class StackEditorProvider
int recordCount = event.numRecords();
for (int i = 0; i < recordCount; i++) {
DomainObjectChangeRecord rec = event.getChangeRecord(i);
EventType eventType = rec.getEventType();
if (eventType == DomainObjectEvent.RESTORED) {
refreshName();
// NOTE: editorPanel should be notified of restored datatype manager via the
// CompositeViewerModel's DataTypeManagerChangeListener restored method
return;
// NOTE: RESTORED event can be ignored here since the model will be notified
// of restored datatype manager via the CompositeViewerModel's
// DataTypeManagerChangeListener restored method.
if (eventType == DomainObjectEvent.FILE_CHANGED) {
scheduleRefreshName = true;
delayedUpdateMgr.updateLater();
continue;
}
if (eventType instanceof ProgramEvent type) {
switch (type) {
case FUNCTION_REMOVED:
Function func = (Function) ((ProgramChangeRecord) rec).getObject();
if (func == function) {
this.dispose();
// Close the Editor.
tool.setStatusInfo("Stack Editor was closed for " + getName());
dispose();
return;
}
return;
break;
case SYMBOL_RENAMED:
case SYMBOL_DATA_CHANGED:
Symbol sym = (Symbol) ((ProgramChangeRecord) rec).getObject();
SymbolType symType = sym.getSymbolType();
if (symType == SymbolType.LABEL) {
if (sym.isPrimary() &&
sym.getAddress().equals(function.getEntryPoint())) {
refreshName();
}
if (sym.isPrimary() && sym.getAddress().equals(function.getEntryPoint())) {
scheduleRefreshName = true;
delayedUpdateMgr.updateLater();
}
else if (inCurrentFunction(rec)) {
reloadFunction();
scheduleReload = true;
delayedUpdateMgr.updateLater();
}
break;
case FUNCTION_CHANGED:
@@ -217,15 +230,15 @@ public class StackEditorProvider
case SYMBOL_REMOVED:
case SYMBOL_ADDRESS_CHANGED:
if (inCurrentFunction(rec)) {
reloadFunction();
scheduleReload = true;
delayedUpdateMgr.updateLater();
}
break;
case SYMBOL_PRIMARY_STATE_CHANGED:
sym = (Symbol) ((ProgramChangeRecord) rec).getNewValue();
symType = sym.getSymbolType();
if (symType == SymbolType.LABEL &&
sym.getAddress().equals(function.getEntryPoint())) {
refreshName();
if (sym.getAddress().equals(function.getEntryPoint())) {
scheduleRefreshName = true;
delayedUpdateMgr.updateLater();
}
break;
default:
@@ -234,16 +247,6 @@ public class StackEditorProvider
}
}
private void reloadFunction() {
if (!stackModel.hasChanges()) {
stackModel.load(function);
}
else {
stackModel.stackChangedExternally(true);
editorPanel.setStatus("Stack may have been changed externally--data may be stale.");
}
}
private boolean inCurrentFunction(DomainObjectChangeRecord record) {
if (!(record instanceof ProgramChangeRecord)) {
return false;
@@ -1,131 +0,0 @@
/* ###
* 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 ghidra.app.plugin.core.stackeditor;
import ghidra.docking.settings.Settings;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Variable;
import ghidra.program.model.listing.VariableStorage;
import ghidra.program.model.mem.MemBuffer;
import ghidra.program.model.pcode.Varnode;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
public class StackPieceDataType extends DataTypeImpl {
private final Variable variable;
StackPieceDataType(Variable var, DataTypeManager dataMgr) {
super(CategoryPath.ROOT, getPieceName(var), dataMgr);
variable = var;
}
private static String getPieceName(Variable var) {
VariableStorage storage = var.getVariableStorage();
Varnode stackVarnode = storage.getLastVarnode();
int pieceLen = stackVarnode.getSize();
return var.getDataType().getName() + ":" + pieceLen + " (piece)";
}
@Override
public DataType clone(DataTypeManager dtm) {
if (dtm == getDataTypeManager()) {
return this;
}
throw new IllegalArgumentException("May not be cloned with new DataTypeManager");
}
@Override
public DataType copy(DataTypeManager dtm) {
throw new UnsupportedOperationException();
}
@Override
public void setCategoryPath(CategoryPath path) throws DuplicateNameException {
throw new UnsupportedOperationException();
}
@Override
public void setName(String name) throws InvalidNameException {
throw new UnsupportedOperationException();
}
@Override
public void setNameAndCategory(CategoryPath path, String name)
throws InvalidNameException, DuplicateNameException {
throw new UnsupportedOperationException();
}
@Override
public String getMnemonic(Settings settings) {
DataType dt = variable.getDataType();
return dt.getMnemonic(settings) + ":" + getLength();
}
@Override
public int getLength() {
VariableStorage storage = variable.getVariableStorage();
Varnode stackVarnode = storage.getLastVarnode();
return stackVarnode.getSize();
}
@Override
public String getDescription() {
// We could provide a description if needed
return null;
}
@Override
public Object getValue(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public String getRepresentation(MemBuffer buf, Settings settings, int length) {
return null;
}
@Override
public boolean isEquivalent(DataType dt) {
return false;
}
@Override
public void dataTypeSizeChanged(DataType dt) {
// ignore
}
@Override
public void dataTypeDeleted(DataType dt) {
// ignore
}
@Override
public void dataTypeReplaced(DataType oldDt, DataType newDt) {
// ignore
}
@Override
public void dataTypeNameChanged(DataType dt, String oldName) {
// ignore
}
@Override
public boolean dependsOn(DataType dt) {
return false;
}
}
@@ -44,8 +44,6 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito
env.showTool();
}
//==================================================================================================
// Private Methods
//==================================================================================================
@@ -140,7 +138,7 @@ public abstract class AbstractStackEditorProviderTest extends AbstractStackEdito
Parameter parameter = function.getParameter(parameterIndex);
SetVariableNameCmd cmd =
new SetVariableNameCmd(parameter, newName, SourceType.USER_DEFINED);
applyCmd(program, cmd);
program.withTransaction("Rename Parameter", () -> cmd.applyTo(program)); // avoid blocking
return parameter;
}
@@ -4,9 +4,9 @@
* 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.
@@ -384,11 +384,29 @@ public class StackEditorCellEditTest extends AbstractStackEditorTest {
typeInCellEditor("testName1\n");
assertTrue(applyAction.isEnabled());
// Change name back and apply disables
// Attempt use of another default name
clickTableCell(getTable(), 0, colNum, 2);
assertIsEditingField(0, colNum);
selectAllInCellEditor();
typeInCellEditor("local_8\n");
assertStatus("Cannot set a stack variable name to a default value");
assertCellString("testName1", 0, colNum);
assertTrue(applyAction.isEnabled());
// Change name back to original and apply disables
clickTableCell(getTable(), 0, colNum, 2);
assertIsEditingField(0, colNum);
selectAllInCellEditor();
typeInCellEditor("local_10\n");
assertCellString("local_10", 0, colNum);
assertTrue(!applyAction.isEnabled());
// Change name back to original and apply disables
clickTableCell(getTable(), 0, colNum, 2);
assertIsEditingField(0, colNum);
selectAllInCellEditor();
typeInCellEditor("\b\n"); // clear entry
assertCellString("local_10", 0, colNum);
assertTrue(!applyAction.isEnabled());
}
@@ -4,9 +4,9 @@
* 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.
@@ -200,7 +200,7 @@ public class StackEditorEnablementTest extends AbstractStackEditorTest {
public void testCentralComponentSelectedEnablement() throws Exception {
init(SIMPLE_STACK);
// Check enablement on central component selected.
// Check enablement on central defined-component selected which has undefined datatype
runSwing(() -> model.setSelection(new int[] { 1 }));
int numBytes = getModel().getMaxReplaceLength(1);
@@ -19,8 +19,7 @@ import static org.junit.Assert.*;
import java.awt.Window;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.*;
import org.junit.Test;
@@ -324,6 +323,8 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
int parameterIndex = 0;
Parameter parameter = renameParameterInListing(parameterIndex, "listing.test.name");
waitForSwing();
// Verify the provider's name for that parameter is updated
String modelParameterName = getParameterNameFromModel(parameterIndex);
assertEquals(parameter.getName(), modelParameterName);
@@ -342,6 +343,9 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
// Change the name of a parameter in the Listing
renameParameterInListing(parameterIndex, "listing.test.name");
JDialog reloadDialog = waitForJDialog("Reload Stack Editor?");
pressButton(reloadDialog, "No");
// Verify the name of the parameter in the provider is not changed from the original edit
String currentModelName = getParameterNameFromModel(parameterIndex);
assertEquals(newModelName, currentModelName);
@@ -360,6 +364,9 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
// Change the name of a parameter in the Listing
renameParameterInListing(parameterIndex, "listing.test.name");
JDialog reloadDialog = waitForJDialog("Reload Stack Editor?");
pressButton(reloadDialog, "No");
// Press Apply
apply();
@@ -386,6 +393,9 @@ public class StackEditorProvider1Test extends AbstractStackEditorProviderTest {
String newListingText = "listing.test.name";
renameParameterInListing(parameterIndex, newListingText);
JDialog reloadDialog = waitForJDialog("Reload Stack Editor?");
pressButton(reloadDialog, "No");
// Press Apply
apply();
@@ -108,6 +108,7 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
*/
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (blockKeyInput(event)) {
return true; // let NO events through!
}
@@ -143,10 +144,19 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
// actions registered on the focused component are allowed to process the event before our
// action system. This allows clients to perform custom event processing without the action
// system interfering.
if (processComponentKeyListeners(event) || processInputAndActionMaps(event)) {
if (processComponentKeyListeners(event)) {
return true;
}
// If there is a registered Java action, let the normal Java event flow process the event.
// (This will only work as expected if the Java action is registered for key pressed events.
// If it is registered for released events, and we have a valid and enabled docking action,
// then the docking action will take precedence, since docking actions are always registered
// for key pressed events.)
if (hasJavaAction(event)) {
return false;
}
if (!executableAction.isValid()) {
// The action is not currently valid for the given focus owner. Let all key strokes go
// to Java when we have no valid context. This allows keys like Escape to work on Java
@@ -380,7 +390,7 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
//
// returns true if there is a focused component that has an action for the given event
// and it processes that action.
private boolean processInputAndActionMaps(KeyEvent event) {
private boolean hasJavaAction(KeyEvent event) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(event);
Component focusOwner = focusProvider.getFocusOwner();
@@ -390,12 +400,7 @@ public class KeyBindingOverrideKeyEventDispatcher implements KeyEventDispatcher
JComponent jComponent = (JComponent) focusOwner;
Action action = getJavaActionForComponent(jComponent, keyStroke);
if (action != null) {
Object source = event.getSource();
int modifiers = event.getModifiersEx();
return SwingUtilities.notifyAction(action, keyStroke, event, source, modifiers);
}
return false;
return action != null && action.isEnabled();
}
private Action getJavaActionForComponent(JComponent jComponent, KeyStroke keyStroke) {
@@ -147,7 +147,6 @@ public interface Span<N, S extends Span<N, S>> extends Comparable<S> {
* Render the given span as a string
*
* @param s the span
* @param nToString a function to convert n to a string
* @return the string
*/
default String toString(S s) {
@@ -36,8 +36,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
private final ComponentDBAdapter adapter;
private final DBRecord record; // null record -> immutable component
private final CompositeDB parent;
private DataType cachedDataType; // required for bit-fields during packing process
private final DataType cachedDataType; // used by immutable defined component (no record)
private int ordinal;
private int offset;
@@ -56,9 +55,15 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
*/
DataTypeComponentDB(DataTypeManagerDB dataMgr, CompositeDB parent, int ordinal, int offset,
DataType datatype, int length) {
this(dataMgr, parent, ordinal, offset);
this.dataMgr = dataMgr;
this.parent = parent;
this.cachedDataType = datatype;
this.ordinal = ordinal;
this.offset = offset;
this.length = length;
this.record = null;
this.adapter = null;
}
/**
@@ -73,6 +78,8 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
this.dataMgr = dataMgr;
this.parent = parent;
this.ordinal = ordinal;
this.cachedDataType = null;
this.offset = offset;
this.length = 1;
this.record = null;
@@ -90,11 +97,13 @@ class DataTypeComponentDB implements InternalDataTypeComponent {
DBRecord record) {
this.dataMgr = dataMgr;
this.adapter = adapter;
this.cachedDataType = null;
this.record = record;
this.parent = parent;
ordinal = record.getIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL);
offset = record.getIntValue(ComponentDBAdapter.COMPONENT_OFFSET_COL);
length = record.getIntValue(ComponentDBAdapter.COMPONENT_SIZE_COL);
this.ordinal = record.getIntValue(ComponentDBAdapter.COMPONENT_ORDINAL_COL);
this.offset = record.getIntValue(ComponentDBAdapter.COMPONENT_OFFSET_COL);
this.length = record.getIntValue(ComponentDBAdapter.COMPONENT_SIZE_COL);
if (isZeroBitFieldComponent()) {
length = 0; // previously stored as 1, force to 0
}
@@ -1378,11 +1378,13 @@ class StructureDB extends CompositeDB implements StructureInternal {
* @param componentName name of component replacement (may be null)
* @param comment comment for component replacement (may be null)
* @return new/updated component (may be null if replacement is not a defined component)
* @throws IllegalArgumentException if unable to identify/make sufficient space
* @throws IOException if an IO error occurs
*/
private DataTypeComponent doComponentReplacement(
LinkedList<DataTypeComponentDB> replacedComponents, int offset, DataType dataType,
int length, String componentName, String comment) throws IOException {
int length, String componentName, String comment)
throws IllegalArgumentException, IOException {
// Attempt quick update of a single defined component if possible.
// A quick update requires that component characteristics including length, offset,
@@ -1416,13 +1418,14 @@ class StructureDB extends CompositeDB implements StructureInternal {
@Override
public final DataTypeComponent replace(int ordinal, DataType dataType, int length)
throws IllegalArgumentException {
throws IllegalArgumentException, IndexOutOfBoundsException {
return replace(ordinal, dataType, length, null, null);
}
@Override
public DataTypeComponent replace(int ordinal, DataType dataType, int length,
String componentName, String comment) {
String componentName, String comment)
throws IllegalArgumentException, IndexOutOfBoundsException {
lock.acquire();
try {
checkDeleted();
@@ -4,9 +4,9 @@
* 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.
@@ -277,16 +277,18 @@ class FunctionStackFrame implements StackFrame {
function.setLocalSize(size);
}
/*
* (non-Javadoc)
* @see ghidra.program.model.listing.StackFrame#getParameterSize()
*/
@Override
public int getParameterSize() {
function.manager.lock.acquire();
try {
checkIsValid();
// NOTE: This logic is sensitive to the existance of Local variables at the incorrect
// stack offset placed before parameters. This can occur when adjustments are made to
// the prototype model's stack pentry specification. Unfortunately, the distinction
// between a parameter and a local is locked-in at the time of creation due to the
// use of distinct symbol types.
int baseOffset = 0;
Integer base = VariableUtilities.getBaseStackParamOffset(function);
if (base != null) {
@@ -44,7 +44,8 @@ public interface Structure extends Composite {
public DataTypeComponent getComponent(int ordinal) throws IndexOutOfBoundsException;
/**
* Gets the first defined component located at or after the specified offset.
* Gets the first defined component located at or after the specified offset. If a
* component contains the specified offset that component will be returned.
* Note: The returned component may be a zero-length component.
*
* @param offset the byte offset into this structure
@@ -436,7 +437,7 @@ public interface Structure extends Composite {
* @throws IllegalArgumentException if amount &lt; 0
*/
public void growStructure(int amount);
/**
* Set the size of the structure to the specified byte-length. If the length is shortened defined
* components will be cleared and removed as required.
@@ -107,13 +107,6 @@ public interface StackFrame {
*/
public int getParameterOffset();
// /**
// * Set the offset on the stack of the parameters.
// *
// * @param offset the start offset of parameters on the stack
// */
// public void setParameterOffset(int offset) throws InvalidInputException;
/**
* Returns true if specified offset could correspond to a parameter
* @param offset