diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEntry.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEntry.java index 6436d5e884..cff8937317 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEntry.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumEntry.java @@ -19,10 +19,12 @@ package ghidra.app.plugin.core.datamgr.editor; public class EnumEntry { private String name; private long value; + private String comment; - public EnumEntry(String name, long value) { + public EnumEntry(String name, long value, String comment) { this.name = name; this.value = value; + this.comment = comment; } public String getName() { @@ -33,6 +35,10 @@ public class EnumEntry { return value; } + public String getComment() { + return comment; + } + public void setName(String newName) { this.name = newName; } @@ -40,4 +46,8 @@ public class EnumEntry { public void setValue(Long newValue) { this.value = newValue; } + + public void setComment(String newComment) { + this.comment = newComment; + } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumTableModel.java index f0d2c7d6f3..ce352784a3 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/datamgr/editor/EnumTableModel.java @@ -29,10 +29,12 @@ class EnumTableModel extends AbstractSortedTableModel { final static int NAME_COL = 0; final static int VALUE_COL = 1; + final static int COMMENT_COL = 2; final static String NAME = "Name"; final static String VALUE = "Value"; - private static String[] columnNames = { NAME, VALUE }; + final static String COMMENT = "Comment"; + private static String[] columnNames = { NAME, VALUE, COMMENT }; private EnumDataType enuum; private List enumEntryList; @@ -98,6 +100,9 @@ class EnumTableModel extends AbstractSortedTableModel { } return "0x" + Long.toHexString(v.getValue() & mask); + + case COMMENT_COL: + return v.getComment(); } return null; } @@ -119,13 +124,14 @@ class EnumTableModel extends AbstractSortedTableModel { EnumEntry entry = enumEntryList.get(rowIndex); Long oldValue = entry.getValue(); String oldName = entry.getName(); + String oldComment = entry.getComment(); switch (columnIndex) { case NAME_COL: String newName = (String) aValue; if (!oldName.equals(newName) && isNameValid(newName)) { enuum.remove(oldName); - enuum.add(newName, oldValue); + enuum.add(newName, oldValue, oldComment); entry.setName(newName); notifyListener = true; } @@ -143,12 +149,12 @@ class EnumTableModel extends AbstractSortedTableModel { if (!oldValue.equals(newValue)) { enuum.remove(oldName); try { - enuum.add(oldName, newValue); + enuum.add(oldName, newValue, oldComment); entry.setValue(newValue); notifyListener = true; } catch (IllegalArgumentException e) { - enuum.add(oldName, oldValue); + enuum.add(oldName, oldValue, oldComment); editorPanel.setStatusMessage(e.getMessage()); } } @@ -157,6 +163,16 @@ class EnumTableModel extends AbstractSortedTableModel { editorPanel.setStatusMessage("Invalid number entered"); } break; + + case COMMENT_COL: + String newComment = (String) aValue; + if (!oldComment.equals(newComment) && newComment != null) { + enuum.remove(oldName); + enuum.add(oldName, oldValue, newComment); + entry.setComment(newComment); + notifyListener = true; + } + break; } if (notifyListener) { editorPanel.stateChanged(null); @@ -228,9 +244,10 @@ class EnumTableModel extends AbstractSortedTableModel { int addEntry(int afterRow) { Long value = findNextValue(afterRow); String name = getUniqueName(); - EnumEntry newEntry = new EnumEntry(name, value); + String comment = ""; + EnumEntry newEntry = new EnumEntry(name, value, comment); try { - enuum.add(name, value.longValue()); + enuum.add(name, value.longValue(), comment); int index = getIndexForRowObject(newEntry); if (index < 0) { index = -index - 1; @@ -300,7 +317,7 @@ class EnumTableModel extends AbstractSortedTableModel { enumEntryList = new ArrayList<>(); String[] names = enuum.getNames(); for (String name : names) { - enumEntryList.add(new EnumEntry(name, enuum.getValue(name))); + enumEntryList.add(new EnumEntry(name, enuum.getValue(name), enuum.getComment(name))); } fireTableDataChanged(); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/prototype/dataArchiveUtilities/ArchiveConverterPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/prototype/dataArchiveUtilities/ArchiveConverterPlugin.java index ffe7328370..312acc404b 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/prototype/dataArchiveUtilities/ArchiveConverterPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/prototype/dataArchiveUtilities/ArchiveConverterPlugin.java @@ -408,13 +408,15 @@ public class ArchiveConverterPlugin extends ProgramPlugin { else if (fieldId.compareToIgnoreCase("ENUM") == 0) { ArrayList fNames = new ArrayList<>(); ArrayList fValues = new ArrayList<>(); + ArrayList fComments = new ArrayList<>(); while (tokenizer.hasMoreElements()) { fNames.add(tokenizer.nextToken()); fValues.add(tokenizer.nextToken()); + fComments.add(tokenizer.nextToken()); } dt = new EnumDataType(cName.getCategoryPath(), cName.getName(), fNames.size(), null); for (int i = 0; i < fNames.size(); i++) { - ((EnumDataType) dt).add(fNames.get(i), new Long(fValues.get(i)).longValue()); + ((EnumDataType) dt).add(fNames.get(i), new Long(fValues.get(i)).longValue(), fComments.get(i)); } } else if (fieldId.compareToIgnoreCase("SYMBOL") == 0) { 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 bf151a9912..1a5743f02b 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 @@ -2506,7 +2506,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { long enumID = record.getKey(); String[] enumNames = enumm.getNames(); for (String enumName : enumNames) { - enumValueAdapter.createRecord(enumID, enumName, enumm.getValue(enumName)); + enumValueAdapter.createRecord(enumID, enumName, enumm.getValue(enumName), enumm.getComment(enumName)); } EnumDB enumDB = new EnumDB(this, dtCache, enumAdapter, enumValueAdapter, record); return enumDB; 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 85895556a0..d2eb415322 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 @@ -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. @@ -44,6 +44,7 @@ class EnumDB extends DataTypeDB implements Enum { private EnumValueDBAdapter valueAdapter; private Map nameMap; // name to value private Map> valueMap; // value to names + private Map commentMap; // name to comment private List bitGroups; EnumDB(DataTypeManagerDB dataMgr, DBObjectCache cache, EnumDBAdapter adapter, @@ -84,6 +85,7 @@ class EnumDB extends DataTypeDB implements Enum { bitGroups = null; nameMap = new HashMap<>(); valueMap = new HashMap<>(); + commentMap = new HashMap<>(); Field[] ids = valueAdapter.getValueIdsInEnum(key); @@ -91,14 +93,16 @@ class EnumDB extends DataTypeDB implements Enum { DBRecord rec = valueAdapter.getRecord(id.getLongValue()); String valueName = rec.getString(EnumValueDBAdapter.ENUMVAL_NAME_COL); long value = rec.getLongValue(EnumValueDBAdapter.ENUMVAL_VALUE_COL); - addToCache(valueName, value); + String valueNameComment = rec.getString(EnumValueDBAdapter.ENUMVAL_COMMENT_COL); + addToCache(valueName, value, valueNameComment); } } - private void addToCache(String valueName, long value) { + private void addToCache(String valueName, long value, String valueNameComment) { nameMap.put(valueName, value); List list = valueMap.computeIfAbsent(value, v -> new ArrayList<>()); list.add(valueName); + commentMap.put(valueName, valueNameComment); } private boolean removeFromCache(String valueName) { @@ -117,6 +121,10 @@ class EnumDB extends DataTypeDB implements Enum { if (list.isEmpty()) { valueMap.remove(value); } + String comment = commentMap.remove(valueName); + if (comment == null) { + return false; + } return true; } @@ -159,6 +167,23 @@ class EnumDB extends DataTypeDB implements Enum { return false; } + @Override + public String getComment(String valueName) throws NoSuchElementException { + lock.acquire(); + try { + checkIsValid(); + initializeIfNeeded(); + String comment = commentMap.get(valueName); + if (comment == null) { + comment = ""; + } + return comment; + } + finally { + lock.release(); + } + } + @Override public long[] getValues() { lock.acquire(); @@ -189,6 +214,19 @@ class EnumDB extends DataTypeDB implements Enum { } } + @Override + public String[] getComments() { + lock.acquire(); + try { + checkIsValid(); + initializeIfNeeded(); + return commentMap.keySet().toArray(new String[commentMap.size()]); + } + finally { + lock.release(); + } + } + @Override public int getCount() { lock.acquire(); @@ -204,6 +242,12 @@ class EnumDB extends DataTypeDB implements Enum { @Override public void add(String valueName, long value) { + String valueNameComment = ""; + add(valueName, value, valueNameComment); + } + + @Override + public void add(String valueName, long value, String valueNameComment) { lock.acquire(); try { checkDeleted(); @@ -213,11 +257,10 @@ class EnumDB extends DataTypeDB implements Enum { throw new IllegalArgumentException(valueName + " already exists in this enum"); } bitGroups = null; - valueAdapter.createRecord(key, valueName, value); + valueAdapter.createRecord(key, valueName, value, valueNameComment); adapter.updateRecord(record, true); - addToCache(valueName, value); + addToCache(valueName, value, valueNameComment); dataMgr.dataTypeChanged(this, false); - } catch (IOException e) { dataMgr.dbError(e); @@ -286,6 +329,7 @@ class EnumDB extends DataTypeDB implements Enum { bitGroups = null; nameMap = new HashMap<>(); valueMap = new HashMap<>(); + commentMap = new HashMap<>(); Field[] ids = valueAdapter.getValueIdsInEnum(key); for (Field id : ids) { @@ -303,9 +347,10 @@ class EnumDB extends DataTypeDB implements Enum { String[] names = enumm.getNames(); for (String name2 : names) { long value = enumm.getValue(name2); - valueAdapter.createRecord(key, name2, value); + String comment = enumm.getComment(name2); + valueAdapter.createRecord(key, name2, value, comment); adapter.updateRecord(record, true); - addToCache(name2, value); + addToCache(name2, value, comment); } if (oldLength != newLength) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java index e9557df4af..863e8c2552 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapter.java @@ -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. @@ -38,9 +38,10 @@ abstract class EnumValueDBAdapter { static final int ENUMVAL_NAME_COL = EnumValueDBAdapterV0.V0_ENUMVAL_NAME_COL; static final int ENUMVAL_VALUE_COL = EnumValueDBAdapterV0.V0_ENUMVAL_VALUE_COL; static final int ENUMVAL_ID_COL = EnumValueDBAdapterV0.V0_ENUMVAL_ID_COL; + static final int ENUMVAL_COMMENT_COL = EnumValueDBAdapterV0.V0_ENUMVAL_COMMENT_COL; /** - * Gets an adapter for working with the enumeration data type values database table. The adapter is based + * Gets an adapter for working with the enumeration data type values database table. The adapter is based * on the version of the database associated with the specified database handle and the openMode. * @param handle handle to the database to be accessed. * @param openMode the mode this adapter is to be opened for (CREATE, UPDATE, READ_ONLY, UPGRADE). @@ -87,10 +88,12 @@ abstract class EnumValueDBAdapter { * Create new enum value record corresponding to specified enum datatype ID * @param enumID enum datatype ID * @param name value name - * @param value numeric value + * @param value numeric value + * @param comment the field comment * @throws IOException if IO error occurs */ - abstract void createRecord(long enumID, String name, long value) throws IOException; + abstract void createRecord(long enumID, String name, long value, String comment) + throws IOException; /** * Get enum value record which corresponds to specified value record ID diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java index 51e676ed79..ef709967a3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterNoTable.java @@ -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. @@ -34,7 +34,8 @@ class EnumValueDBAdapterNoTable extends EnumValueDBAdapter { } @Override - public void createRecord(long enumID, String name, long value) throws IOException { + public void createRecord(long enumID, String name, long value, String comment) + throws IOException { throw new UnsupportedOperationException(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java index 90b4243971..e23903e5a8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/EnumValueDBAdapterV0.java @@ -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. @@ -18,11 +18,12 @@ package ghidra.program.database.data; import java.io.IOException; import db.*; +import ghidra.program.model.lang.ConstantPool.Record; import ghidra.util.exception.VersionException; /** * Version 0 implementation for the enumeration tables adapter. - * + * */ class EnumValueDBAdapterV0 extends EnumValueDBAdapter { static final int VERSION = 0; @@ -31,11 +32,16 @@ class EnumValueDBAdapterV0 extends EnumValueDBAdapter { static final int V0_ENUMVAL_NAME_COL = 0; static final int V0_ENUMVAL_VALUE_COL = 1; static final int V0_ENUMVAL_ID_COL = 2; + static final int V0_ENUMVAL_COMMENT_COL = 3; static final Schema V0_ENUM_VALUE_SCHEMA = new Schema(0, "Enum Value ID", new Field[] { StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE }, new String[] { "Name", "Value", "Enum ID" }); +// static final Schema V1_ENUM_VALUE_SCHEMA = new Schema(0, "Enum Value ID", +// new Class[] { StringField.class, LongField.class, LongField.class, StringField.class }, +// new String[] { "Name", "Value", "Enum ID", "Comment" }); + private Table valueTable; /** @@ -71,11 +77,13 @@ class EnumValueDBAdapterV0 extends EnumValueDBAdapter { } @Override - public void createRecord(long enumID, String name, long value) throws IOException { - DBRecord record = V0_ENUM_VALUE_SCHEMA.createRecord(valueTable.getKey()); + public void createRecord(long enumID, String name, long value, String comment) + throws IOException { + Record record = V0_ENUM_VALUE_SCHEMA.createRecord(valueTable.getKey()); record.setLongValue(V0_ENUMVAL_ID_COL, enumID); record.setString(V0_ENUMVAL_NAME_COL, name); record.setLongValue(V0_ENUMVAL_VALUE_COL, value); + record.setString(V0_ENUMVAL_COMMENT_COL, comment); valueTable.putRecord(record); } 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 98f0b69b89..299df2c259 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 @@ -37,6 +37,14 @@ public interface Enum extends DataType { */ public String getName(long value); + /** + * Get the comment for the given name. + * @param name name of the entry + * @return the comment + * @throws NoSuchElementException if the name does not exist in this Enum + */ + public String getComment(String name) throws NoSuchElementException; + /** * Get the values of the enum entries. * @return values sorted in ascending order @@ -48,6 +56,11 @@ public interface Enum extends DataType { */ public String[] getNames(); + /** + * Get the comments of the enum entries. + */ + public String[] getComments(); + /** * Get the number of entries in this Enum. */ @@ -60,6 +73,14 @@ public interface Enum extends DataType { */ public void add(String name, long value); + /** + * Add a enum entry. + * @param name name of the new entry + * @param value value of the new entry + * @param comment comment of the new entry + */ + public void add(String name, long value, String comment); + /** * Remove the enum entry with the given name. * @param name name of entry to remove. 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 02a6b08145..81be3e7d7f 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 @@ -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. @@ -33,6 +33,7 @@ public class EnumDataType extends GenericDataType implements Enum { private Map nameMap; // name to value private Map> valueMap; // value to names + private Map commentMap; // name to comment private int length; private String description; private List bitGroups; @@ -52,6 +53,7 @@ public class EnumDataType extends GenericDataType implements Enum { } nameMap = new HashMap<>(); valueMap = new HashMap<>(); + commentMap = new HashMap<>(); this.length = length; } @@ -65,6 +67,7 @@ public class EnumDataType extends GenericDataType implements Enum { } nameMap = new HashMap<>(); valueMap = new HashMap<>(); + commentMap = new HashMap<>(); this.length = length; } @@ -91,6 +94,15 @@ public class EnumDataType extends GenericDataType implements Enum { return list.get(0); } + @Override + public String getComment(String valueName) throws NoSuchElementException { + String valueNameComment = commentMap.get(valueName); + if (valueNameComment == null) { + valueNameComment = ""; + } + return valueNameComment; + } + @Override public long[] getValues() { long[] values = valueMap.keySet().stream().mapToLong(Long::longValue).toArray(); @@ -105,6 +117,11 @@ public class EnumDataType extends GenericDataType implements Enum { return names; } + @Override + public String[] getComments() { + return commentMap.values().toArray(new String[commentMap.size()]); + } + @Override public int getCount() { return nameMap.size(); @@ -112,6 +129,12 @@ public class EnumDataType extends GenericDataType implements Enum { @Override public void add(String valueName, long value) { + String valueNameComment = ""; + add(valueName, value, valueNameComment); + } + + @Override + public void add(String valueName, long value, String valueNameComment) { bitGroups = null; checkValue(value); if (nameMap.containsKey(valueName)) { @@ -124,6 +147,10 @@ public class EnumDataType extends GenericDataType implements Enum { valueMap.put(value, list); } list.add(valueName); + if (valueNameComment == null) { + valueNameComment = ""; + } + commentMap.put(valueName, valueNameComment); } private void checkValue(long value) { @@ -166,6 +193,7 @@ public class EnumDataType extends GenericDataType implements Enum { if (list.isEmpty()) { valueMap.remove(value); } + commentMap.remove(valueName); } } @@ -356,7 +384,10 @@ public class EnumDataType extends GenericDataType implements Enum { for (int i = 0; i < names.length; i++) { long value = getValue(names[i]); long otherValue = enumm.getValue(names[i]); - if (!names[i].equals(otherNames[i]) || value != otherValue) { + String comment = getComment(names[i]); + String otherComment = enumm.getComment(names[i]); + if (!names[i].equals(otherNames[i]) || value != otherValue || + !comment.equals(otherComment)) { return false; } } @@ -376,10 +407,11 @@ public class EnumDataType extends GenericDataType implements Enum { Enum enumm = (Enum) dataType; nameMap = new HashMap<>(); valueMap = new HashMap<>(); + commentMap = new HashMap<>(); setLength(enumm.getLength()); String[] names = enumm.getNames(); for (String name2 : names) { - add(name2, enumm.getValue(name2)); + add(name2, enumm.getValue(name2), enumm.getComment(name2)); } stateChanged(null); }