From b3fbdd3c098ad1089fcc9dce5aeb62bab0c191b8 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 4 Aug 2023 15:43:12 -0400 Subject: [PATCH] Updated Enums to handle old types that have a mix of values that contain negative numbers and high unsigned values --- .../ghidra/program/database/data/EnumDB.java | 23 +++++++++++++--- .../database/data/EnumSignedState.java | 11 ++++---- .../java/ghidra/program/model/data/Enum.java | 7 +++++ .../program/model/data/EnumDataType.java | 26 ++++++++++++++----- 4 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java index 5d32fcd8b1..4e27dbe53c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumDB.java @@ -112,12 +112,16 @@ class EnumDB extends DataTypeDB implements Enum { long minValue = valueMap.firstKey(); long maxValue = valueMap.lastKey(); + if (maxValue > getMaxPossibleValue(length, true)) { + if (minValue < 0) { + return INVALID; + } + return UNSIGNED; + } + if (minValue < 0) { return SIGNED; } - if (maxValue > getMaxPossibleValue(length, true)) { - return UNSIGNED; - } return NONE; // we have no negatives and no large unsigned values } @@ -874,6 +878,19 @@ class EnumDB extends DataTypeDB implements Enum { } } + @Override + public EnumSignedState getSignedState() { + lock.acquire(); + try { + checkIsValid(); + initializeIfNeeded(); + return signedState; + } + finally { + lock.release(); + } + } + @Override public int getMinimumPossibleLength() { lock.acquire(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumSignedState.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumSignedState.java index d0f9838caa..28bb405dfb 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumSignedState.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumSignedState.java @@ -18,13 +18,14 @@ package ghidra.program.database.data; /** * Keeps track of the signed state of an enum datatype. Enum are fundamentally either signed or * unsigned, but sometimes you can't tell based on the values they contain. Once a negative value - * is added, then the enum becomes locked as signed, preventing high unsigned values from being - * added. Once a high value unsigned value is added, then it becomes locked as unsigned value. If - * neither a negative value or high unsigned value has been added, then the enum is not locked as - * either signed or unsigned. + * is added, then the enum becomes locked as signed, preventing high unsigned values (those values + * that are too big for signed value of the enum size) from being added. Once a high value unsigned + * value is added, then it becomes locked as unsigned value. If neither a negative value or high + * unsigned value has been added, then the enum is not locked as either signed or unsigned. */ public enum EnumSignedState { SIGNED, // Enum contains at least 1 negative value, preventing high unsigned values UNSIGNED, // Enum contains at least 1 high unsigned value, preventing negative values - NONE // Enum contains neither a negative or a high unsigned value, so can go either way + NONE, // Enum contains neither a negative or a high unsigned value, so can go either way + INVALID // Enum contains both negative and high unsigned values; can happen with old types } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java index 774a99b631..239737e92e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Enum.java @@ -19,6 +19,7 @@ import java.math.BigInteger; import java.util.NoSuchElementException; import ghidra.docking.settings.Settings; +import ghidra.program.database.data.EnumSignedState; public interface Enum extends DataType { @@ -133,6 +134,12 @@ public interface Enum extends DataType { */ public boolean isSigned(); + /** + * Returns the signed state. + * @return the signed state. + */ + public EnumSignedState getSignedState(); + /** * Returns the maximum value that this enum can represent based on its size and signedness. * @return the maximum value that this enum can represent based on its size and signedness. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java index 192e564c57..60934ecf4d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/EnumDataType.java @@ -148,6 +148,11 @@ public class EnumDataType extends GenericDataType implements Enum { @Override public void add(String valueName, long value, String comment) { + doAdd(valueName, value, comment); + signedState = computeSignedness(); + } + + private void doAdd(String valueName, long value, String comment) { bitGroups = null; checkValue(value); if (nameMap.containsKey(valueName)) { @@ -161,8 +166,6 @@ public class EnumDataType extends GenericDataType implements Enum { if (!StringUtils.isBlank(comment)) { commentMap.put(valueName, comment); } - signedState = computeSignedness(); - } private EnumSignedState computeSignedness() { @@ -172,12 +175,16 @@ public class EnumDataType extends GenericDataType implements Enum { long minValue = valueMap.firstKey(); long maxValue = valueMap.lastKey(); + if (maxValue > getMaxPossibleValue(length, true)) { + if (minValue < 0) { + return INVALID; + } + return UNSIGNED; + } + if (minValue < 0) { return SIGNED; } - if (maxValue > getMaxPossibleValue(length, true)) { - return UNSIGNED; - } return NONE; // we have no negatives and no large unsigned values } @@ -277,6 +284,11 @@ public class EnumDataType extends GenericDataType implements Enum { return signedState == SIGNED; } + @Override + public EnumSignedState getSignedState() { + return signedState; + } + @Override public long getMinPossibleValue() { return getMinPossibleValue(length, signedState != UNSIGNED); @@ -503,10 +515,10 @@ public class EnumDataType extends GenericDataType implements Enum { commentMap = new HashMap<>(); setLength(enumm.getLength()); String[] names = enumm.getNames(); + signedState = enumm.getSignedState(); for (String valueName : names) { - add(valueName, enumm.getValue(valueName), enumm.getComment(valueName)); + doAdd(valueName, enumm.getValue(valueName), enumm.getComment(valueName)); } - computeSignedness(); } @Override