From abce9bbf858fd3a8cd5db81ecf799b3a59176743 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 23 Mar 2022 14:18:24 -0400 Subject: [PATCH] GP-1403 Allow unrestricted clearing of settings. Improve Pointer-Typedef error condition feedback in listing. Various tweaks to settings-based pointer calculations. --- .../core/data/AbstractSettingsDialog.java | 18 ++- .../program/model/listing/CodeUnitFormat.java | 19 ++- .../core/data/AbstractDataActionTest.java | 4 +- .../docking/widgets/combobox/GComboBox.java | 2 + .../ghidra/docking/settings/SettingsImpl.java | 30 +++- .../emulate/EmulateMemoryStateBuffer.java | 7 +- .../database/data/DataTypeManagerDB.java | 14 +- .../database/data/DataTypeSettingsDB.java | 28 +++- .../program/database/data/TypedefDB.java | 3 + .../ghidra/program/model/data/DataType.java | 11 +- .../program/model/data/PointerDataType.java | 139 ++++++++++++++---- .../program/model/data/TypedefDataType.java | 3 + .../program/model/listing/DataStub.java | 2 +- .../model/listing/InstructionStub.java | 2 +- .../program/model/mem/ByteMemBufferImpl.java | 2 +- .../ghidra/program/model/mem/MemBuffer.java | 2 +- 16 files changed, 215 insertions(+), 71 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java index 3426e5d1c5..951207ce9a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/data/AbstractSettingsDialog.java @@ -27,6 +27,7 @@ import javax.swing.table.TableCellEditor; import docking.DialogComponentProvider; import docking.widgets.combobox.GComboBox; +import docking.widgets.combobox.GhidraComboBox; import docking.widgets.dialogs.StringChoices; import docking.widgets.table.*; import docking.widgets.textfield.IntegerTextField; @@ -232,6 +233,7 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider { @Override protected void okCallback() { + settingsTable.editingStopped(null); apply(); close(); dispose(); @@ -548,6 +550,9 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider { @Override public void setValueAt(Object value, int row, int col) { + if (settings == null) { + return; // dialog has been disposed + } SettingsRowObject rowObject = rows.get(row); switch (col) { case 1: @@ -665,6 +670,12 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider { } } + class StringSettingsComboBox extends GComboBox { + StringSettingsComboBox() { + super(); + } + } + class SettingsEditor extends AbstractCellEditor implements TableCellEditor { final static int ENUM = 0; @@ -674,18 +685,19 @@ public abstract class AbstractSettingsDialog extends DialogComponentProvider { final static int STRING_WITH_SUGGESTIONS = 4; private int mode; - private GComboBox comboBox = new GComboBox<>(); + private GhidraComboBox comboBox = new GhidraComboBox<>(); private IntegerTextField intTextField = new IntegerTextField(); private JTextField textField = new JTextField(); private SettingsRowObject rowobject; SettingsEditor() { - comboBox.addItemListener(e -> fireEditingStopped()); + comboBox.setEnterKeyForwarding(false); + comboBox.addActionListener(e -> fireEditingStopped()); intTextField.addChangeListener(e -> updateHexMode()); } - GComboBox getComboBox() { + GhidraComboBox getComboBox() { return comboBox; // used for testing } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java b/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java index 27d9fd100c..8596088f71 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/model/listing/CodeUnitFormat.java @@ -1077,12 +1077,27 @@ public class CodeUnitFormat { representationList.setHasError(true); } } - representationList.add(dataType.getRepresentation(data, data, length)); + representationList.setPrimaryReferenceHidden(ref != null); + if (data.isDefined() && dataValue == null) { + DataType baseDt = dataType; + if (baseDt instanceof TypeDef) { + baseDt = ((TypeDef) dataType).getBaseDataType(); + } + if (baseDt instanceof Pointer) { + // Render pointer error + PointerDataType.getAddressValue(data, baseDt.getLength(), data, + m -> representationList.add(m)); + } representationList.setHasError(true); } - else if ((dataValue instanceof Address) && ref == null && + + if (representationList.isEmpty()) { + representationList.add(dataType.getRepresentation(data, data, length)); + } + + if ((dataValue instanceof Address) && ref == null && data.getProgram().getMemory().getBlock((Address) dataValue) == null) { representationList.setHasError(true); } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java index 2b945d0dcb..2aa65d4365 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/data/AbstractDataActionTest.java @@ -29,7 +29,7 @@ import org.junit.*; import docking.ActionContext; import docking.action.DockingActionIf; import docking.action.MenuData; -import docking.widgets.combobox.GComboBox; +import docking.widgets.combobox.GhidraComboBox; import docking.widgets.dialogs.StringChoices; import docking.widgets.table.AbstractSortedTableModel; import docking.widgets.table.GTable; @@ -309,7 +309,7 @@ public abstract class AbstractDataActionTest extends AbstractGhidraHeadedIntegra assertTrue("Editor type is not correct", activeEditor instanceof SettingsEditor); SettingsEditor settingsEditor = (SettingsEditor) activeEditor; - GComboBox combo = settingsEditor.getComboBox(); + GhidraComboBox combo = settingsEditor.getComboBox(); int index = runSwing(() -> { int n = combo.getItemCount(); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GComboBox.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GComboBox.java index e38cd8893f..bf23fbf519 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GComboBox.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/combobox/GComboBox.java @@ -25,6 +25,8 @@ import docking.widgets.GComponent; * A {@link JComboBox} that disables HTML rendering. * * @param the type of the elements of this combo box + * + * See {@link GhidraComboBox} for improved functionality including handling of Enter key. */ public class GComboBox extends JComboBox implements GComponent { diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java index 2f36664245..21fdee6d55 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/docking/settings/SettingsImpl.java @@ -114,12 +114,31 @@ public class SettingsImpl implements Settings, Serializable { } /** - * Check for immutable settings and log error of modification not permitted + * Check for immutable or restricted settings and log error of modification not permitted * @param type setting type or null * @param name setting name or null * @return true if change permitted */ private boolean checkSetting(String type, String name) { + if (!checkImmutableSetting(type, name)) { + return false; + } + if (name != null && allowedSettingPredicate != null && + !allowedSettingPredicate.apply(name)) { + Msg.warn(this, "Ignored disallowed setting '" + name + "'"); + return false; + } + return true; + } + + /** + * Check for immutable settings and log error of modification not permitted. + * Does not check for other setting restrictions. + * @param type setting type or null + * @param name setting name or null + * @return true if change permitted + */ + private boolean checkImmutableSetting(String type, String name) { if (immutable) { String typeStr = ""; if (type != null) { @@ -134,11 +153,6 @@ public class SettingsImpl implements Settings, Serializable { nameStr); return false; } - if (name != null && allowedSettingPredicate != null && - !allowedSettingPredicate.apply(name)) { - Msg.warn(this, "Ignored disallowed setting '" + name + "'"); - return false; - } return true; } @@ -190,7 +204,7 @@ public class SettingsImpl implements Settings, Serializable { @Override public void clearSetting(String name) { - if (checkSetting(null, name)) { + if (checkImmutableSetting(null, name)) { map.remove(name); changed(); } @@ -244,7 +258,7 @@ public class SettingsImpl implements Settings, Serializable { if (map.isEmpty()) { return; } - if (checkSetting(null, null)) { + if (checkImmutableSetting(null, null)) { map.clear(); changed(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/EmulateMemoryStateBuffer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/EmulateMemoryStateBuffer.java index 8b5d8cfca7..889b90a54a 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/EmulateMemoryStateBuffer.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/pcode/emulate/EmulateMemoryStateBuffer.java @@ -15,12 +15,12 @@ */ package ghidra.pcode.emulate; +import java.math.BigInteger; + import ghidra.pcode.memstate.MemoryState; import ghidra.program.model.address.Address; import ghidra.program.model.mem.*; -import java.math.BigInteger; - /** * MemoryStateBuffer provides a MemBuffer for instruction parsing use * which wraps an emulator MemoryState. This implementation wraps all specified @@ -111,8 +111,7 @@ public class EmulateMemoryStateBuffer implements MemBuffer { @Override public Memory getMemory() { - // Make sure Sleigh language provider does not call this method - throw new UnsupportedOperationException(); + return null; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java index 73b0d918cf..65cac28bc4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeManagerDB.java @@ -120,7 +120,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { private SettingsCache settingsCache = new SettingsCache<>(200); private List sortedDataTypes; private Map> enumValueMap; - private Map> suggestedSettingsValuesMap = new HashMap<>(); + private Map> previouslyUsedSettingsValuesMap = new HashMap<>(); private List invalidatedListeners = new ArrayList<>(); protected DataTypeManagerChangeListenerHandler defaultListener = @@ -679,7 +679,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { SettingDB setting = new SettingDB(rec, settingsAdapter.getSettingName(rec)); settingsCache.put(dataTypeId, name, setting); if (strValue != null) { - Set suggestions = suggestedSettingsValuesMap.get(name); + Set suggestions = previouslyUsedSettingsValuesMap.get(name); if (suggestions != null) { // only cache suggestion if suggestions previously requested suggestions.add(strValue); @@ -702,7 +702,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager { Set set = new TreeSet<>(); try { settingsAdapter.addAllValues(settingsDefinition.getStorageKey(), set); - settingsDefinition.addPreferredValues(this, set); } catch (IOException e) { errHandler.dbError(e); @@ -716,11 +715,17 @@ abstract public class DataTypeManagerDB implements DataTypeManager { * @return suggested values or empty array if none */ String[] getSuggestedValues(StringSettingsDefinition settingsDefinition) { + if (!settingsDefinition.supportsSuggestedValues()) { + return Settings.EMPTY_STRING_ARRAY; + } lock.acquire(); try { - Set set = suggestedSettingsValuesMap + Set previouslyUsedSet = previouslyUsedSettingsValuesMap .computeIfAbsent(settingsDefinition.getStorageKey(), n -> generateSuggestions(settingsDefinition)); + // Last-minute additions are not cached since suggested values may change + Set set = new TreeSet<>(previouslyUsedSet); // copy before updating + settingsDefinition.addPreferredValues(this, set); if (set.isEmpty()) { return Settings.EMPTY_STRING_ARRAY; } @@ -3240,7 +3245,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager { fireInvalidated(); updateFavorites(); idsToDataTypeMap.clear(); - suggestedSettingsValuesMap.clear(); } finally { lock.release(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java index 45550df9c0..66ec95c242 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeSettingsDB.java @@ -109,6 +109,25 @@ class DataTypeSettingsDB implements Settings { * @return true if change permitted */ private boolean checkSetting(String type, String name) { + if (!checkImmutableSetting(type, name)) { + return false; + } + if (name != null && allowedSettingPredicate != null && + !allowedSettingPredicate.apply(name)) { + Msg.warn(this, "Ignored disallowed setting '" + name + "'"); + return false; + } + return true; + } + + /** + * Check for immutable settings and log error of modification not permitted. + * Does not check for other setting restrictions. + * @param type setting type or null + * @param name setting name or null + * @return true if change permitted + */ + private boolean checkImmutableSetting(String type, String name) { if (locked) { String typeStr = ""; if (type != null) { @@ -123,11 +142,6 @@ class DataTypeSettingsDB implements Settings { nameStr); return false; } - if (name != null && allowedSettingPredicate != null && - !allowedSettingPredicate.apply(name)) { - Msg.warn(this, "Ignored disallowed setting '" + name + "'"); - return false; - } return true; } @@ -205,14 +219,14 @@ class DataTypeSettingsDB implements Settings { @Override public void clearSetting(String name) { - if (checkSetting(null, name) && dataMgr.clearSetting(dataTypeID, name)) { + if (checkImmutableSetting(null, name) && dataMgr.clearSetting(dataTypeID, name)) { settingsChanged(); } } @Override public void clearAllSettings() { - if (checkSetting(null, null) && dataMgr.clearAllSettings(dataTypeID)) { + if (checkImmutableSetting(null, null) && dataMgr.clearAllSettings(dataTypeID)) { settingsChanged(); } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java index c1ca9ab810..6e9d65b9b3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/TypedefDB.java @@ -415,6 +415,9 @@ class TypedefDB extends DataTypeDB implements TypeDef { @Override public String getDefaultLabelPrefix() { + if (isAutoNamed()) { + return getDataType().getDefaultLabelPrefix(); + } return getName(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java index 0e6f8b35a3..e26edc8ea7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataType.java @@ -21,6 +21,7 @@ import java.util.Collection; import ghidra.docking.settings.Settings; import ghidra.docking.settings.SettingsDefinition; import ghidra.program.model.mem.MemBuffer; +import ghidra.program.model.scalar.Scalar; import ghidra.util.InvalidNameException; import ghidra.util.UniversalID; import ghidra.util.exception.DuplicateNameException; @@ -281,10 +282,11 @@ public interface DataType { public URL getDocs(); /** - * Get the data in the form of the appropriate Object for this DataType. + * Get the interpretted data value in the form of the appropriate Object for this DataType. + * This method must return a value consistent with {@link #getValueClass(Settings)}. *

- * For instance if the datatype is an AddressDT, return an Address object. a Byte, return a - * Scalar* (maybe this should be a Byte) a Float, return a Float + * For instance, if this datatype is a {@link Pointer} an Address object or null should be returned. + * A Byte, returns a {@link Scalar} object. * * @param buf the data buffer. * @param settings the settings to use. @@ -328,7 +330,8 @@ public interface DataType { throws DataTypeEncodeException; /** - * Get the Class of the value to be returned by this datatype. + * Get the Class of the value Object to be returned by this datatype + * (see {@link #getValue(MemBuffer, Settings, int)}). * * @param settings the relevant settings to use or null for default. * @return Class of the value to be returned by this datatype or null if it can vary or is diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java index 408ed7bb0f..6b17e6b6d5 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/PointerDataType.java @@ -16,6 +16,7 @@ package ghidra.program.model.data; import java.util.*; +import java.util.function.Consumer; import ghidra.docking.settings.Settings; import ghidra.program.database.data.DataTypeUtilities; @@ -24,6 +25,7 @@ import ghidra.program.model.listing.*; import ghidra.program.model.mem.*; import ghidra.program.model.symbol.*; import ghidra.util.DataConverter; +import ghidra.util.StringUtilities; /** * Basic implementation for a pointer dataType @@ -37,6 +39,7 @@ public class PointerDataType extends BuiltIn implements Pointer { public static final String POINTER_NAME = "pointer"; public static final String POINTER_LABEL_PREFIX = "PTR"; public static final String POINTER_LOOP_LABEL_PREFIX = "PTR_LOOP"; + public static final String NOT_A_POINTER = "NaP"; // NOTE: order dictates auto-name attribute ordering (order should not be changed) private static TypeDefSettingsDefinition[] POINTER_TYPEDEF_SETTINGS_DEFS = @@ -345,14 +348,16 @@ public class PointerDataType extends BuiltIn implements Pointer { /** * Generate an address value based upon bytes stored at the specified buf - * location. The following settings, if specified, may influence the generated address: + * location. Interpretation of settings may depend on access to a {@link Memory} + * object associated with the specified {@link MemBuffer} buf. + *
+ * The following pointer-typedef settings are supported: *

    *
  • {@link AddressSpaceSettingsDefinition}
  • + *
  • {@link OffsetMaskSettingsDefinition}
  • *
  • {@link OffsetShiftSettingsDefinition}
  • + *
  • {@link PointerTypeSettingsDefinition}
  • *
- * The default address space will be the same as the buffer's associated memory address. - * Interpretation of settings may depend on access to a {@link Memory} object associated - * with the specified {@link MemBuffer} buf. * * @param buf memory buffer positioned to stored pointer * @param size pointer size in bytes @@ -360,31 +365,40 @@ public class PointerDataType extends BuiltIn implements Pointer { * @return address value or null if unusable buf or data */ public static Address getAddressValue(MemBuffer buf, int size, Settings settings) { + return getAddressValue(buf, size, settings, msg -> { + /* ignore */}); + } + /** + * Generate an address value based upon bytes stored at the specified buf + * location. Interpretation of settings may depend on access to a {@link Memory} + * object associated with the specified {@link MemBuffer} buf. + *
+ * The following pointer-typedef settings are supported: + *
    + *
  • {@link AddressSpaceSettingsDefinition}
  • + *
  • {@link OffsetMaskSettingsDefinition}
  • + *
  • {@link OffsetShiftSettingsDefinition}
  • + *
  • {@link PointerTypeSettingsDefinition}
  • + *
+ * + * @param buf memory buffer positioned to stored pointer + * @param size pointer size in bytes + * @param settings settings which may influence address generation + * @param errorHandler if null returned an error may be conveyed to this errorHandler + * @return address value or null if unusable buf or data + */ + public static Address getAddressValue(MemBuffer buf, int size, Settings settings, + Consumer errorHandler) { + + String spaceName = AddressSpaceSettingsDefinition.DEF.getValue(settings); AddressSpace targetSpace = null; Memory mem = buf.getMemory(); - if (mem != null) { - Program program = mem.getProgram(); - String spaceName = AddressSpaceSettingsDefinition.DEF.getValue(settings); - if (spaceName != null) { - // this space may be ignored if pointer type specified - targetSpace = program.getAddressFactory().getAddressSpace(spaceName); - } - } - if (targetSpace == null) { - // default to address space associated with mem buffer - targetSpace = buf.getAddress().getAddressSpace(); - } - - if (targetSpace instanceof SegmentedAddressSpace) { - // ignore other settings with SegmentedAddressSpace use - return getAddressValue(buf, size, targetSpace); - } Long offset = getStoredOffset(buf, size); if (offset == null) { - // Insufficient bytes + errorHandler.accept("Insufficient data"); return null; } @@ -397,7 +411,7 @@ public class PointerDataType extends BuiltIn implements Pointer { int shift = (int) OffsetShiftSettingsDefinition.DEF.getValue(settings); if (shift < 0) { - addrOffset >>= -shift; + addrOffset >>>= -shift; // avoid sign-extension } else { addrOffset <<= shift; @@ -405,42 +419,103 @@ public class PointerDataType extends BuiltIn implements Pointer { try { PointerType choice = PointerTypeSettingsDefinition.DEF.getType(settings); + if (choice != PointerType.DEFAULT && spaceName != null) { + errorHandler.accept("Address Space and Pointer Type settings conflict"); + return null; + } // Address space setting ignored if Pointer Type has been specified - if (choice == PointerType.IMAGE_BASE_RELATIVE && mem != null) { + if (choice == PointerType.IMAGE_BASE_RELATIVE) { if (addrOffset == 0) { // Done for consistency with old ImageBaseOffsetDataType. // A 0 relative offset is considerd invalid (NaP) - return null; + return null; // NaP without error + } + if (mem == null) { + errorHandler.accept("Memory not specified"); } // must ignore AddressSpaceSettingsDefinition Address imageBase = mem.getProgram().getImageBase(); targetSpace = imageBase.getAddressSpace(); - return imageBase.add(addrOffset * targetSpace.getAddressableUnitSize()); + return imageBase.addWrap(addrOffset * targetSpace.getAddressableUnitSize()); } else if (choice == PointerType.RELATIVE) { // must ignore AddressSpaceSettingsDefinition Address base = buf.getAddress(); targetSpace = base.getAddressSpace(); - return base.add(addrOffset * targetSpace.getAddressableUnitSize()); + return base.addWrap(addrOffset * targetSpace.getAddressableUnitSize()); } - if (choice == PointerType.FILE_OFFSET) { - if (mem != null) { + else if (choice == PointerType.FILE_OFFSET) { + if (mem == null) { + errorHandler.accept("Memory not specified"); + } + else if (mem.getAllFileBytes().size() == 0) { + errorHandler.accept("No File bytes used"); + } + else { List
addressList = mem.locateAddressesForFileOffset(addrOffset); if (addressList.size() == 1) { return addressList.get(0); } + if (addressList.size() > 1) { + errorHandler.accept( + "Non-unique File offset mapping: 0x" + Long.toHexString(addrOffset)); + } + else { + errorHandler.accept( + "File offset mapping not found: 0x" + Long.toHexString(addrOffset)); + } } return null; } + else if (choice != PointerType.DEFAULT) { + errorHandler.accept("Unsupported pointer type: " + choice.toString()); + return null; + } + + if (spaceName != null) { + if (mem == null) { + errorHandler.accept("Memory not specified"); + return null; + } + Program program = mem.getProgram(); + targetSpace = program.getAddressFactory().getAddressSpace(spaceName); + if (targetSpace == null) { + errorHandler.accept( + "Address space not defined: " + spaceName + ":" + formatOffset(addrOffset)); + return null; + } + } + if (targetSpace == null) { + targetSpace = buf.getAddress().getAddressSpace(); + } + + if (targetSpace instanceof SegmentedAddressSpace) { + if (size != 2 && size != 4) { + errorHandler.accept("Unsupported segmented address size: " + size); + return null; + } + if (mask != 0 || shift != 0) { + errorHandler.accept("Unsupported mask/shift setting for segmented address"); + return null; + } + return getSegmentedAddressValue(buf, size, addrOffset); + } return targetSpace.getAddress(addrOffset, true); } - catch (AddressOutOfBoundsException e) { - // offset too large + catch (IllegalArgumentException | AddressOutOfBoundsException e) { + errorHandler.accept(e.toString()); } return null; } + private static String formatOffset(long offset) { + String offsetStr = Long.toHexString(offset); + int len = offsetStr.length(); + len = len - (len % 4) + 4; // multiple of 4-digits + return StringUtilities.pad(offsetStr, '0', len); + } + /** * Get signed offset value based upon bytes stored at the specified buf * location @@ -554,7 +629,7 @@ public class PointerDataType extends BuiltIn implements Pointer { Address addr = (Address) getValue(buf, settings, len); if (addr == null) { // could not create address, so return "Not a pointer (NaP)" - return "NaP"; + return NOT_A_POINTER; } return addr.toString(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java index 840fd731d7..2ecfc3d57c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/TypedefDataType.java @@ -122,6 +122,9 @@ public class TypedefDataType extends GenericDataType implements TypeDef { @Override public String getDefaultLabelPrefix() { + if (isAutoNamed()) { + return getDataType().getDefaultLabelPrefix(); + } return getName(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java index 237039f40b..9c867e04ae 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/DataStub.java @@ -294,7 +294,7 @@ public class DataStub implements Data { @Override public Memory getMemory() { - throw new UnsupportedOperationException(); + return null; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/InstructionStub.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/InstructionStub.java index 0c4f3855ca..0d6515cf2e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/InstructionStub.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/InstructionStub.java @@ -290,7 +290,7 @@ public class InstructionStub implements Instruction { @Override public Memory getMemory() { - throw new UnsupportedOperationException(); + return null; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java index dc6dee7627..3fc065c4b9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/ByteMemBufferImpl.java @@ -67,7 +67,7 @@ public class ByteMemBufferImpl implements MemBuffer { @Override public Memory getMemory() { - throw new UnsupportedOperationException("Can't get memory from ByteMemBuffer"); + return null; } @Override diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java index b47f486516..27bad9ac6b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemBuffer.java @@ -114,7 +114,7 @@ public interface MemBuffer { /** * Get the Memory object actually used by the MemBuffer. * - * @return the Memory used by this MemBuffer. + * @return the Memory used by this MemBuffer or null if not available. */ public Memory getMemory();