From 2aee17ba31d3b3e1713b5f1ca6b5af3b5d23b4d9 Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Fri, 13 Dec 2019 09:47:12 -0500 Subject: [PATCH 01/36] GT-3299: Fixed stackshift/extrapop for 8051 and 6805. --- Ghidra/Processors/6805/data/languages/6805.cspec | 2 +- Ghidra/Processors/8051/data/languages/8051.cspec | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Ghidra/Processors/6805/data/languages/6805.cspec b/Ghidra/Processors/6805/data/languages/6805.cspec index 2c60effd58..73d046698c 100644 --- a/Ghidra/Processors/6805/data/languages/6805.cspec +++ b/Ghidra/Processors/6805/data/languages/6805.cspec @@ -6,7 +6,7 @@ - + diff --git a/Ghidra/Processors/8051/data/languages/8051.cspec b/Ghidra/Processors/8051/data/languages/8051.cspec index ab1b88383f..67911b49c8 100644 --- a/Ghidra/Processors/8051/data/languages/8051.cspec +++ b/Ghidra/Processors/8051/data/languages/8051.cspec @@ -10,7 +10,7 @@ - + From 6ca9eafd1dcc1a9904d18efe6c53f1dc0f76621a Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Fri, 17 Jan 2020 11:38:46 -0500 Subject: [PATCH 02/36] GT-933: Corrected AVR8 atmega256 memory layout in .pspec --- .../Atmel/data/languages/atmega256.pspec | 171 +++++++++++++++--- 1 file changed, 142 insertions(+), 29 deletions(-) diff --git a/Ghidra/Processors/Atmel/data/languages/atmega256.pspec b/Ghidra/Processors/Atmel/data/languages/atmega256.pspec index 4cae35f0f7..c69c8cf17b 100644 --- a/Ghidra/Processors/Atmel/data/languages/atmega256.pspec +++ b/Ghidra/Processors/Atmel/data/languages/atmega256.pspec @@ -76,7 +76,6 @@ - @@ -134,14 +133,19 @@ + + + + + - + @@ -154,9 +158,10 @@ - - + + + @@ -224,7 +229,8 @@ - + + @@ -245,22 +251,63 @@ - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + @@ -277,21 +324,87 @@ - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + From 5ea27f70e96f41dbad9d523c583e204767881f6a Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Mon, 27 Jan 2020 14:51:54 -0500 Subject: [PATCH 03/36] GT-3299: Corrected stackshift and extrapop in cspecs. --- Ghidra/Processors/8051/data/languages/8051.cspec | 2 +- Ghidra/Processors/8085/data/languages/8085.cspec | 2 +- Ghidra/Processors/Toy/data/languages/toyPosStack.cspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Ghidra/Processors/8051/data/languages/8051.cspec b/Ghidra/Processors/8051/data/languages/8051.cspec index 67911b49c8..ab1b88383f 100644 --- a/Ghidra/Processors/8051/data/languages/8051.cspec +++ b/Ghidra/Processors/8051/data/languages/8051.cspec @@ -10,7 +10,7 @@ - + diff --git a/Ghidra/Processors/8085/data/languages/8085.cspec b/Ghidra/Processors/8085/data/languages/8085.cspec index 6f98c13568..cfd08b5c40 100644 --- a/Ghidra/Processors/8085/data/languages/8085.cspec +++ b/Ghidra/Processors/8085/data/languages/8085.cspec @@ -6,7 +6,7 @@ - + diff --git a/Ghidra/Processors/Toy/data/languages/toyPosStack.cspec b/Ghidra/Processors/Toy/data/languages/toyPosStack.cspec index 297fbaf2d7..795ba37e3a 100644 --- a/Ghidra/Processors/Toy/data/languages/toyPosStack.cspec +++ b/Ghidra/Processors/Toy/data/languages/toyPosStack.cspec @@ -6,7 +6,7 @@ - + From dcd78c4d162c5770ca0c51386f11bd7bf3c2f9a4 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 29 Jan 2020 13:01:06 -0500 Subject: [PATCH 04/36] GT-3511 revised fix for branch to self with invalid delay slot --- .../main/java/ghidra/program/disassemble/Disassembler.java | 4 ++-- .../java/ghidra/program/disassemble/DisassemblerQueue.java | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java index cf7ba7be7c..741312f4ca 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java @@ -1152,12 +1152,12 @@ public class Disassembler implements DisassemblerConflictHandler { throws InsufficientBytesException, UnknownInstructionException, AddressOverflowException, NestedDelaySlotException { + List delaySlotList = parseDelaySlots(inst, blockMemBuffer, block); + if (followFlow) { processInstructionFlows(inst, block); } - List delaySlotList = parseDelaySlots(inst, blockMemBuffer, block); - block.addInstruction(inst); if (delaySlotList != null) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java index 2159d7313e..779690348c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java @@ -174,9 +174,6 @@ class DisassemblerQueue { branchFlow = currentBranchQueue.first(); currentBranchQueue.remove(branchFlow); } - if (processedBranchFlows.contains(branchFlow)) { - continue; - } processedBranchFlows.add(branchFlow); Address blockAddr = branchFlow.getDestinationAddress(); From 491c4e466a87eea6ef3d75a0cd2675cd8347b4c0 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 30 Jan 2020 15:24:11 -0500 Subject: [PATCH 05/36] GT-3515 - Updated documentation for column constraints special text filtering section; updated runtime type discovery to examine interfaces --- .../constraint/MappedColumnConstraint.java | 8 +- .../constraint/dialog/ColumnFilterData.java | 46 +++++-- .../dialog/ColumnFilterDialogModel.java | 6 +- .../util/table/column/GColumnRenderer.java | 10 +- .../reflection/ReflectionUtilitiesTest.java | 112 ++++++++++++++++++ .../util/reflection/ReflectionUtilities.java | 112 ++++++++++++++---- 6 files changed, 255 insertions(+), 39 deletions(-) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/MappedColumnConstraint.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/MappedColumnConstraint.java index 5a55333eb7..5467ea784a 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/MappedColumnConstraint.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/MappedColumnConstraint.java @@ -22,11 +22,11 @@ import ghidra.util.SystemUtilities; /** * Class that maps one type of column constraint into another. Typically, these are created * automatically based on {@link ColumnTypeMapper} that are discovered by the system. For example, - *{@literal if you have a column type of "Foo", and you create a ColumnTypeMapper, then all the} - * string constraints would now be available that column. + * {@literal if you have a column type of "Foo", and you create a ColumnTypeMapper, + * then all the} string constraints would now be available that column. * - * @param The column type. - * @param the converted (mapped) type. + * @param The column type + * @param the converted (mapped) type */ public class MappedColumnConstraint implements ColumnConstraint { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java index eb3d62cdab..035af40adf 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java @@ -27,10 +27,14 @@ import ghidra.util.table.column.GColumnRenderer; import ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode; /** - * Class for maintaining information about a table's column for the purpose of configuring filters - * based on that columns values. These are generated by examining a table's column types and finding - * out if there are any ColumnConstraints that support that type. If so, a ColumnFilterData is - * created for that column which then allows filtering on that columns data. + * This class provides all known {@link ColumnConstraint}s for a given table column. + * + *

Class for maintaining information about a particular table's column for the purpose of + * configuring filters based on that column's values. Instances of this class are generated + * by examining a table's column types and finding any {@link ColumnConstraint}s that support + * that type. If column constraints are found, a {@link ColumnFilterData} is created for that column + * which then allows filtering on that columns data via the column constraints mechanism (which + * is different than the traditional text filter). * * @param the column type. */ @@ -61,12 +65,20 @@ public class ColumnFilterData implements Comparable> { private List> initializeConstraints(RowObjectFilterModel model, Class columnClass) { + // + // Case 1: the column is not dynamic and thus has no way of overriding the column + // constraint filtering mechanism. + // Collection> defaultConstraints = DiscoverableTableUtils.getColumnConstraints(columnClass); if (!(model instanceof DynamicColumnTableModel)) { return new ArrayList<>(defaultConstraints); } + // + // Case 2: the column is dynamic, but does not supply a specialized column renderer, + // which is the means for overriding the column constraint filtering mechanism. + // DynamicColumnTableModel columnBasedModel = (DynamicColumnTableModel) model; DynamicTableColumn column = columnBasedModel.getColumn(modelIndex); GColumnRenderer columnRenderer = column.getColumnRenderer(); @@ -74,19 +86,31 @@ public class ColumnFilterData implements Comparable> { return new ArrayList<>(defaultConstraints); } + // + // Case 3: the column renderer has signaled that it uses only column constraint filtering + // and does not support the traditional text based filtering. + // ColumnConstraintFilterMode mode = columnRenderer.getColumnConstraintFilterMode(); if (mode == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY) { return new ArrayList<>(defaultConstraints); } - @SuppressWarnings("unchecked") + // + // Case 4: the column supports text filtering. Find any column constraints for the + // column's type. Then, create string-based constraints that will filter on + // the column's conversion from its type to a string (via + // GColumnRenderer.getFilterString()). + // + @SuppressWarnings("unchecked") // See type note on the class below GColumnRenderer asT = (GColumnRenderer) columnRenderer; ColumnRendererMapper mapper = new ColumnRendererMapper(asT, columnBasedModel, modelIndex); Collection> rendererStringConstraints = DiscoverableTableUtils.getColumnConstraints(mapper); + // + // Case 5: the renderer supports both text filtering and column constraint filtering. + // List> results = new ArrayList<>(rendererStringConstraints); - if (mode == ColumnConstraintFilterMode.USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS) { // also use the normal constraints with the renderer constraints results.addAll(defaultConstraints); @@ -213,6 +237,13 @@ public class ColumnFilterData implements Comparable> { * This class allows us to turn client columns of type T to a String. We use * the renderer provided at construction time to generate a filter string when * {@link #convert(Object)} is called. + * + *

Implementation Note: the type 'T' here is used to satisfy the external client's + * expected list of constraints. We will not be able to identify 'T' at runtime. Rather, + * our parent's {@link #getSourceType()} will simply be {@link Object}. This is fine, as + * this particular class will not have {@link #getSourceType()} called, due to how we + * are using it. (Normally, the source type is used to find compatible constraints; we + * are not using the discovery mechanism with this private class.) */ private class ColumnRendererMapper extends ColumnTypeMapper { @@ -229,14 +260,13 @@ public class ColumnFilterData implements Comparable> { @Override public String convert(T value) { - Settings settings = model.getColumnSettings(columnModelIndex); if (value == null) { return null; } + Settings settings = model.getColumnSettings(columnModelIndex); String s = renderer.getFilterString(value, settings); return s; } - } } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java index 3c0b0891da..c89ca9195b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java @@ -102,9 +102,9 @@ public class ColumnFilterDialogModel { } /** - * Creates a new filter fow (a new major row in the dialog filter panel) - * @param logicOperation the logical operation for how this row interacts with the rows before it - * @return the new filter row that represents a major row in the dialog filter panel. + * Creates a new filter for (a new major row in the dialog filter panel) + * @param logicOperation the logical operation for how this row interacts with preceding rows + * @return the new filter row that represents a major row in the dialog filter panel */ public DialogFilterRow createFilterRow(LogicOperation logicOperation) { diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java index 35eab0293b..57d59d5011 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java @@ -36,12 +36,12 @@ import ghidra.util.exception.AssertException; * columns. The specifics of how the text filter works are defined by the * {@link RowFilterTransformer}, which is controlled by the user via the button at the right * of the filter field. (In the absence of this button, filters are typically a 'contains' - * filter. + * filter.) * *

The default transformer turns items to strings by, in order,: *

    - *
  1. checking the the renderer's {@link #getFilterString(Object, Settings)}, - * if a renderer is installed + *
  2. checking the the column renderer's + * {@link #getFilterString(Object, Settings)},if a column renderer is installed *
  3. *
  4. checking to see if the column value is an instance of {@link DisplayStringProvider} *
  5. @@ -68,6 +68,10 @@ import ghidra.util.exception.AssertException; * *
* + *

Note: The default filtering behavior of this class is to only filter on the aforementioned + * filter text field. That is, column constraints will not be enabled by default. To + * change this, change the value returned by {@link #getColumnConstraintFilterMode()}. + * * @param the column type */ public interface GColumnRenderer extends TableCellRenderer { diff --git a/Ghidra/Framework/Generic/src/test/java/utilities/util/reflection/ReflectionUtilitiesTest.java b/Ghidra/Framework/Generic/src/test/java/utilities/util/reflection/ReflectionUtilitiesTest.java index a2389bdf44..bc54ce7233 100644 --- a/Ghidra/Framework/Generic/src/test/java/utilities/util/reflection/ReflectionUtilitiesTest.java +++ b/Ghidra/Framework/Generic/src/test/java/utilities/util/reflection/ReflectionUtilitiesTest.java @@ -18,6 +18,7 @@ package utilities.util.reflection; import static org.hamcrest.CoreMatchers.*; import static org.junit.Assert.*; +import java.util.ArrayList; import java.util.List; import org.junit.Test; @@ -153,6 +154,84 @@ public class ReflectionUtilitiesTest { babyTypeArguments.get(1)); } + @Test(expected = NullPointerException.class) + public void testRuntimeTypeDiscovery_Null() { + ReflectionUtilities.getTypeArguments(List.class, null); + } + + @Test + public void testRumtimeTypeDiscovery_AnonymousClass() { + + List myList = new ArrayList() { + // stub + }; + List> types = ReflectionUtilities.getTypeArguments(List.class, myList.getClass()); + assertEquals(1, types.size()); + assertEquals(String.class, types.get(0)); + } + + @Test + public void testRumtimeTypeDiscovery_LocalVariable() { + + List myList = new ArrayList(); + List> types = ReflectionUtilities.getTypeArguments(List.class, myList.getClass()); + assertEquals(1, types.size()); + assertNull(types.get(0)); + } + + @Test + public void testRuntimeTypeDiscovery_MixedHierarchy_AbstractClassAndInterfaceBothDefineValues() { + + // + // Test to make sure that we get not only a directly hierarchy, but the lateral one + // as well, where we pursue interfaces that may have defined some types. + // + + List> types = ReflectionUtilities.getTypeArguments(RuntimeBaseInterface.class, + ChildExtendingPartiallyDefinedTypes.class); + assertEquals(2, types.size()); + assertEquals(String.class, types.get(0)); + assertEquals(Double.class, types.get(1)); + } + + @Test + public void testRuntimeTypeDiscovery_SubInterfaceDefinesValues() { + + // + // Test to make sure that we get not only a directly hierarchy, but the lateral one + // as well, where we pursue interfaces that may have defined some types. + // + + List> types = ReflectionUtilities.getTypeArguments(RuntimeBaseInterface.class, + ChildExtendingWhollyDefinedTypes.class); + assertEquals(2, types.size()); + assertEquals(String.class, types.get(0)); + assertEquals(Double.class, types.get(1)); + } + + @Test + public void testRuntimeTypeDiscovery_MixedHierarchy_UnrelatedParents() { + + // + // Test to make sure that we get not only a directly hierarchy, but the lateral one + // as well, where we pursue interfaces that may have defined some types. + // + // This test also verifies that in a mixed type hierarchy, we can correctly locate types + // depending upon the parent type we pass in. + // + + List> types = ReflectionUtilities.getTypeArguments(RuntimeBaseInterface.class, + ChildWithMixedParentTypes.class); + assertEquals(2, types.size()); + assertEquals(String.class, types.get(0)); + assertEquals(Double.class, types.get(1)); + + types = ReflectionUtilities.getTypeArguments(List.class, + ChildWithMixedParentTypes.class); + assertEquals(1, types.size()); + assertEquals(Integer.class, types.get(0)); + } + //================================================================================================== // Inner Classes //================================================================================================== @@ -179,6 +258,39 @@ public class ReflectionUtilitiesTest { } } + private interface RuntimeBaseInterface { + // stub + } + + private interface PartiallyDefinedInterface extends RuntimeBaseInterface { + // stub + } + + private interface WhollyDefinedInterface extends RuntimeBaseInterface { + // stub + } + + private class AbstractPartiallyDefinedClass implements RuntimeBaseInterface { + // stub + } + + private class ChildExtendingPartiallyDefinedTypes + extends AbstractPartiallyDefinedClass + implements PartiallyDefinedInterface { + // stub + } + + private class ChildExtendingWhollyDefinedTypes + implements WhollyDefinedInterface { + // stub + } + + private class ChildWithMixedParentTypes + extends ArrayList + implements WhollyDefinedInterface { + // stub + } + private class RuntimeBaseType { // stub } diff --git a/Ghidra/Framework/Utility/src/main/java/utilities/util/reflection/ReflectionUtilities.java b/Ghidra/Framework/Utility/src/main/java/utilities/util/reflection/ReflectionUtilities.java index 022b87d659..d1b5a56693 100644 --- a/Ghidra/Framework/Utility/src/main/java/utilities/util/reflection/ReflectionUtilities.java +++ b/Ghidra/Framework/Utility/src/main/java/utilities/util/reflection/ReflectionUtilities.java @@ -560,15 +560,46 @@ public class ReflectionUtilities { } } + /** + * Returns the type arguments for the given base class and extension. + * + *

Caveat: this lookup will only work if the given child class is a concrete class that + * has its type arguments specified. For example, these cases will work: + *

+	 * 		// anonymous class definition
+	 * 		List<String> myList = new ArrayList<String>() {
+	 *			...
+	 *		};
+	 *
+	 *		// class definition
+	 *		public class MyList implements List<String> {
+	 * 
+ * + * Whereas this case will not work: + *
+	 * 		// local variable with the type specified
+	 * 		List<String> myList = new ArrayList<String>();
+	 * 
+ * + *

Note: a null entry in the result list will exist for any type that was unrecoverable + * + * + * @param the type of the base and child class + * @param baseClass the base class + * @param childClass the child class + * @return the type arguments + */ public static List> getTypeArguments(Class baseClass, Class childClass) { - Map resolvedTypesDictionary = new HashMap<>(); + Objects.requireNonNull(baseClass); + Objects.requireNonNull(childClass); + + Map resolvedTypesDictionary = new HashMap<>(); Type baseClassAsType = walkClassHierarchyAndResolveTypes(baseClass, resolvedTypesDictionary, childClass); - // now see if we can resolve the type arguments defined by 'baseClass' to the raw runtime - // class that is in use + // try to resolve type arguments defined by 'baseClass' to the raw runtime class Type[] baseClassDeclaredTypeArguments = getDeclaredTypeArguments(baseClassAsType); return resolveBaseClassTypeArguments(resolvedTypesDictionary, baseClassDeclaredTypeArguments); @@ -577,29 +608,69 @@ public class ReflectionUtilities { private static Type walkClassHierarchyAndResolveTypes(Class baseClass, Map resolvedTypes, Type type) { - while (!getClass(type).equals(baseClass)) { - if (type instanceof Class) { - type = ((Class) type).getGenericSuperclass(); - } - else { - ParameterizedType parameterizedType = (ParameterizedType) type; - Class rawType = (Class) parameterizedType.getRawType(); - Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); - TypeVariable[] typeParameters = rawType.getTypeParameters(); - for (int i = 0; i < actualTypeArguments.length; i++) { - resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); - } + if (type == null) { + return null; + } - if (!rawType.equals(baseClass)) { - type = rawType.getGenericSuperclass(); + if (equals(type, baseClass)) { + return type; + } + + if (type instanceof Class) { + + Class clazz = (Class) type; + Type[] interfaceTypes = clazz.getGenericInterfaces(); + Set toCheck = new HashSet<>(); + toCheck.addAll(Arrays.asList(interfaceTypes)); + + Type parentType = clazz.getGenericSuperclass(); + toCheck.add(parentType); + + for (Type t : toCheck) { + Type result = walkClassHierarchyAndResolveTypes(baseClass, resolvedTypes, t); + if (equals(result, baseClass)) { + return result; } } - if (type == null) { - return type; + return parentType; + } + + ParameterizedType parameterizedType = (ParameterizedType) type; + Class rawType = (Class) parameterizedType.getRawType(); + Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); + TypeVariable[] typeParameters = rawType.getTypeParameters(); + for (int i = 0; i < actualTypeArguments.length; i++) { + resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); + } + + if (rawType.equals(baseClass)) { + return rawType; + } + + Type[] interfaceTypes = rawType.getGenericInterfaces(); + Set toCheck = new HashSet<>(); + toCheck.addAll(Arrays.asList(interfaceTypes)); + + Type parentType = rawType.getGenericSuperclass(); + toCheck.add(parentType); + + for (Type t : toCheck) { + Type result = walkClassHierarchyAndResolveTypes(baseClass, resolvedTypes, t); + if (equals(result, baseClass)) { + return result; } } - return type; + + return parentType; + } + + private static boolean equals(Type type, Class c) { + Class typeClass = getClass(type); + if (typeClass == null) { + return false; + } + return typeClass.equals(c); } private static Class getClass(Type type) { @@ -637,7 +708,6 @@ public class ReflectionUtilities { return typeArgumentsAsClasses; } - // we checked private static Type[] getDeclaredTypeArguments(Type type) { if (type instanceof Class) { return ((Class) type).getTypeParameters(); From 370152ad6c92763df083e3b0e0f629d01ec4bbda Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 31 Jan 2020 15:06:07 -0500 Subject: [PATCH 06/36] GT-3514 - Fixed exception when right-clicking an operation structure field reference in the Listing --- .../codebrowser/ListingHighlightProvider.java | 14 ++++++------ .../LocationReferencesPlugin.java | 3 ++- .../locationreferences/ReferenceUtils.java | 9 +------- .../program/model/listing/VariableOffset.java | 22 +++++++++++++++---- 4 files changed, 28 insertions(+), 20 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java index b4eb2ad3a8..ec521a8159 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/codebrowser/ListingHighlightProvider.java @@ -24,6 +24,8 @@ import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.apache.commons.lang3.StringUtils; + import docking.widgets.fieldpanel.field.FieldElement; import docking.widgets.fieldpanel.support.FieldLocation; import docking.widgets.fieldpanel.support.Highlight; @@ -450,16 +452,14 @@ public class ListingHighlightProvider text = StringUtilities.findWord(text, pos, UNDERSCORE_AND_PERIOD_OK); } - if (text != null) { - text = text.trim(); - if (text.length() == 0) { - text = null; - } + if (StringUtils.isBlank(text)) { + text = null; } - - if (text != null) { + else { + text = text.trim(); currentHighlightPattern = Pattern.compile(text, Pattern.LITERAL); } + return text; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin.java index 23116c835f..582c26b387 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesPlugin.java @@ -125,7 +125,8 @@ public class LocationReferencesPlugin extends Plugin private void displayProviderForLocation(ProgramLocation location, Navigatable navigatable) { LocationDescriptor locationDescriptor = getLocationDescriptor(location); if (locationDescriptor == null) { - throw new IllegalArgumentException("Unable to display provider - unknown location"); + throw new IllegalArgumentException( + "Unable to display provider - unknown location: " + location); } LocationReferencesProvider provider = findProvider(locationDescriptor, navigatable); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java index eb496abf77..81c306cc02 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/ReferenceUtils.java @@ -711,16 +711,9 @@ public final class ReferenceUtils { return null; } - List objects = variableOffset.getObjects(); - Object object = objects.get((int) variableOffset.getOffset()); - if (!(object instanceof LabelString)) { - return null; - } - Variable variable = variableOffset.getVariable(); DataType type = variable.getDataType(); - LabelString label = (LabelString) object; - String string = label.toString(); + String string = variableOffset.getDataTypeDisplayText(); GenericDataTypeLocationDescriptor descriptor = createGenericDataTypeLocationDescriptor(program, type, string); return descriptor; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableOffset.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableOffset.java index 00ec030f64..83c0865d18 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableOffset.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/listing/VariableOffset.java @@ -120,16 +120,22 @@ public class VariableOffset { } /** - * Get list of markup objects - * @return list of markup objects + * Returns the data type access portion of this variable offset as a string + * @return the text */ - public List getObjects() { + public String getDataTypeDisplayText() { + List objects = getObjects(false); + LabelString labelString = (LabelString) objects.get(0); + return labelString.toString(); + } + + private List getObjects(boolean showScalarAdjustment) { DataType dt = variable.getDataType(); StringBuffer name = new StringBuffer(variable.getName()); long scalarAdjustment = 0; - if (includeScalarAdjustment && (replacedElement instanceof Scalar)) { + if (showScalarAdjustment && (replacedElement instanceof Scalar)) { Scalar s = (Scalar) replacedElement; scalarAdjustment = variable.isStackVariable() ? s.getSignedValue() : s.getValue(); scalarAdjustment -= offset; @@ -214,6 +220,14 @@ public class VariableOffset { return list; } + /** + * Get list of markup objects + * @return list of markup objects + */ + public List getObjects() { + return getObjects(includeScalarAdjustment); + } + public Variable getVariable() { return variable; } From 7a01b8b3e04a127ae3b40222aa27fd6876d17218 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 31 Jan 2020 16:25:00 -0500 Subject: [PATCH 07/36] GT-3515 - Column constraint docs review fixes --- .../examples/graph/SampleGraphProvider.java | 4 ++-- .../core/script/GhidraScriptTableModel.java | 2 +- .../VTFunctionAssociationTableModel.java | 2 +- .../MatchesFilterDialogComponentProvider.java | 11 +++++----- .../table/DefaultRowFilterTransformer.java | 2 +- .../constraint/dialog/ColumnFilterData.java | 12 +++++----- .../dialog/ColumnFilterDialogModel.java | 2 +- .../ColumnRenderedValueBackupComparator.java | 5 +++-- .../table/threaded/ThreadedTableModel.java | 22 +++++++++---------- .../AbstractWrapperTypeColumnRenderer.java | 2 +- .../util/table/column/GColumnRenderer.java | 15 ++++--------- .../graph/VisualGraphComponentProvider.java | 2 +- .../ghidra/graph/job/FilterVerticesJob.java | 7 +++--- 13 files changed, 40 insertions(+), 48 deletions(-) diff --git a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphProvider.java b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphProvider.java index 12256aa7e3..84afb81ae6 100644 --- a/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphProvider.java +++ b/Ghidra/Extensions/sample/src/main/java/ghidra/examples/graph/SampleGraphProvider.java @@ -314,7 +314,7 @@ public class SampleGraphProvider extends ComponentProviderAdapter { return mainPanel; } - private void showFitlerPanel(boolean selected) { + private void showFilterPanel(boolean selected) { if (selected) { mainPanel.add(filterPanel, BorderLayout.SOUTH); } @@ -331,7 +331,7 @@ public class SampleGraphProvider extends ComponentProviderAdapter { @Override public void actionPerformed(ActionContext context) { - showFitlerPanel(isSelected()); + showFilterPanel(isSelected()); } }; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java index 5d7ba8d2e3..fa86f78462 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/script/GhidraScriptTableModel.java @@ -537,7 +537,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel { @@ -58,9 +57,9 @@ public class MatchesFilterDialogComponentProvider extends // Row 1 - Right Component // association status filter - AssociationStatusFilter associationStatusFitler = new AssociationStatusFilter(); - addFilter(associationStatusFitler); - rowOnePanel.add(associationStatusFitler.getComponent()); + AssociationStatusFilter associationStatusFilter = new AssociationStatusFilter(); + addFilter(associationStatusFilter); + rowOnePanel.add(associationStatusFilter.getComponent()); // Row 2 - Left Component // symbol type filter diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/DefaultRowFilterTransformer.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/DefaultRowFilterTransformer.java index 6466c06d11..4ee704490c 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/DefaultRowFilterTransformer.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/DefaultRowFilterTransformer.java @@ -116,7 +116,7 @@ public class DefaultRowFilterTransformer implements RowFilterTransfo } ColumnConstraintFilterMode mode = renderer.getColumnConstraintFilterMode(); - return mode == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY; + return mode == ColumnConstraintFilterMode.ALLOW_CONSTRAINTS_FILTER_ONLY; } private String getRenderedColumnValue(Object columnValue, int columnIndex) { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java index 035af40adf..4796483f72 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterData.java @@ -91,7 +91,7 @@ public class ColumnFilterData implements Comparable> { // and does not support the traditional text based filtering. // ColumnConstraintFilterMode mode = columnRenderer.getColumnConstraintFilterMode(); - if (mode == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY) { + if (mode == ColumnConstraintFilterMode.ALLOW_CONSTRAINTS_FILTER_ONLY) { return new ArrayList<>(defaultConstraints); } @@ -106,16 +106,16 @@ public class ColumnFilterData implements Comparable> { ColumnRendererMapper mapper = new ColumnRendererMapper(asT, columnBasedModel, modelIndex); Collection> rendererStringConstraints = DiscoverableTableUtils.getColumnConstraints(mapper); + if (mode == ColumnConstraintFilterMode.ALLOW_RENDERER_STRING_FILTER_ONLY) { + return new ArrayList<>(rendererStringConstraints); + } // // Case 5: the renderer supports both text filtering and column constraint filtering. // + // assume: mode == ColumnConstraintFilterMode.ALLOW_ALL_FILTERS List> results = new ArrayList<>(rendererStringConstraints); - if (mode == ColumnConstraintFilterMode.USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS) { - // also use the normal constraints with the renderer constraints - results.addAll(defaultConstraints); - } - + results.addAll(defaultConstraints); return results; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java index c89ca9195b..026898d72d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/constraint/dialog/ColumnFilterDialogModel.java @@ -102,7 +102,7 @@ public class ColumnFilterDialogModel { } /** - * Creates a new filter for (a new major row in the dialog filter panel) + * Creates a new filter row (a new major row in the dialog filter panel) * @param logicOperation the logical operation for how this row interacts with preceding rows * @return the new filter row that represents a major row in the dialog filter panel */ diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/sort/ColumnRenderedValueBackupComparator.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/sort/ColumnRenderedValueBackupComparator.java index b138db74c1..99ce034375 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/sort/ColumnRenderedValueBackupComparator.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/sort/ColumnRenderedValueBackupComparator.java @@ -15,12 +15,13 @@ */ package docking.widgets.table.sort; +import static ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode.*; + import java.util.Comparator; import docking.widgets.table.*; import ghidra.docking.settings.Settings; import ghidra.util.table.column.GColumnRenderer; -import ghidra.util.table.column.GColumnRenderer.ColumnConstraintFilterMode; /** * A special version of the backup comparator that uses the column's rendered value for @@ -47,7 +48,7 @@ public class ColumnRenderedValueBackupComparator implements Comparator renderer = (GColumnRenderer) column.getColumnRenderer(); if (renderer != null) { - if (renderer.getColumnConstraintFilterMode() == ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY) { + if (renderer.getColumnConstraintFilterMode() == ALLOW_CONSTRAINTS_FILTER_ONLY) { // this implies that the column has signaled that it does not support // filtering/sorting using its rendered value supportsColumnSorting = false; diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/ThreadedTableModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/ThreadedTableModel.java index 3c34063ab6..549e41fc14 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/ThreadedTableModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/threaded/ThreadedTableModel.java @@ -74,9 +74,9 @@ public abstract class ThreadedTableModel * This variable can be in one of three states: *
    *
  • null - signals that there is no filter change taking place
  • - *
  • An instance of NullTableFitler - the client has removed the current + *
  • An instance of NullTableFilter - the client has removed the current * filter by calling {@link #setTableFilter(TableFilter)} with a null value
  • - *
  • An instance of a custom TableFitler - the client has changed the + *
  • An instance of a custom TableFilter - the client has changed the * filter to a non-null value by calling {@link #setTableFilter(TableFilter)}
  • *
*/ @@ -399,7 +399,7 @@ public abstract class ThreadedTableModel * * @return true if there is a table filter set. */ - public boolean hasFitler() { + public boolean hasFilter() { TableFilter currentFilter = getTableFilter(); return !currentFilter.isEmpty(); } @@ -429,7 +429,7 @@ public abstract class ThreadedTableModel return data; } - if (!hasFitler()) { + if (!hasFilter()) { return data; } @@ -463,14 +463,14 @@ public abstract class ThreadedTableModel } /** - * Sets the given TableFitler on this model. This table filter will then be used + * Sets the given TableFilter on this model. This table filter will then be used * by this model in the default {@link #doFilter(List, TableSortingContext, TaskMonitor)} * method. - * @param tableFitler The filter to use for table filtering. + * @param tableFilter The filter to use for table filtering. */ @Override - public void setTableFilter(TableFilter tableFitler) { - this.pendingTableFilter = tableFitler; + public void setTableFilter(TableFilter tableFilter) { + this.pendingTableFilter = tableFilter; if (pendingTableFilter == null) { // Don't allow the pending filter to be null in this case. The client has changed // the filter. If we use null, then we don't know the difference between a client @@ -480,8 +480,8 @@ public abstract class ThreadedTableModel reFilter(); } - private void setAppliedTableFitler(TableFilter tableFitler) { - if (tableFitler == null) { + private void setAppliedTableFilter(TableFilter tableFilter) { + if (tableFilter == null) { // null means there was no change to the text filter--so don't set it (see the // javadoc for the filter variables) return; @@ -532,7 +532,7 @@ public abstract class ThreadedTableModel this.allData = allData; this.filteredData = filteredData; - setAppliedTableFitler(pendingTableFilter); + setAppliedTableFilter(pendingTableFilter); pendingSortContext = null; TableSortingContext newSortingContext = filteredData.getSortContext(); diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/AbstractWrapperTypeColumnRenderer.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/AbstractWrapperTypeColumnRenderer.java index 5a183c50dc..4255911ce2 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/AbstractWrapperTypeColumnRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/AbstractWrapperTypeColumnRenderer.java @@ -36,7 +36,7 @@ public interface AbstractWrapperTypeColumnRenderer extends GColumnRenderer // Overridden to only allow the constraint filtering mechanism. @Override public default ColumnConstraintFilterMode getColumnConstraintFilterMode() { - return ColumnConstraintFilterMode.USE_COLUMN_CONSTRAINTS_ONLY; + return ColumnConstraintFilterMode.ALLOW_CONSTRAINTS_FILTER_ONLY; } @Override diff --git a/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java b/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java index 57d59d5011..73f9b2f4fb 100644 --- a/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java +++ b/Ghidra/Framework/Docking/src/main/java/ghidra/util/table/column/GColumnRenderer.java @@ -83,21 +83,14 @@ public interface GColumnRenderer extends TableCellRenderer { public enum ColumnConstraintFilterMode { //@formatter:off - /** - * Signals that the programmer didn't make a decision about how filtering for this - * column should work. This currently will treat all filtering as if - * {@link #USE_COLUMN_RENDERER_FITLER_STRING_ONLY} was chosen. - */ - DEFAULT, - /** Use only {@link GColumnRenderer#getFilterString(Object, Settings)} value; no constraints */ - USE_COLUMN_RENDERER_FITLER_STRING_ONLY, + ALLOW_RENDERER_STRING_FILTER_ONLY, /** Use only column constraints when filtering */ - USE_COLUMN_CONSTRAINTS_ONLY, + ALLOW_CONSTRAINTS_FILTER_ONLY, /** Use both the rendered filter String and any found column constraints */ - USE_BOTH_COLUMN_RENDERER_FITLER_STRING_AND_CONSTRAINTS, + ALLOW_ALL_FILTERS, //@formatter:on } @@ -111,7 +104,7 @@ public interface GColumnRenderer extends TableCellRenderer { * @return the mode */ public default ColumnConstraintFilterMode getColumnConstraintFilterMode() { - return ColumnConstraintFilterMode.DEFAULT; + return ColumnConstraintFilterMode.ALLOW_RENDERER_STRING_FILTER_ONLY; } /** diff --git a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/VisualGraphComponentProvider.java b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/VisualGraphComponentProvider.java index fe1afc08d0..b99aa03264 100644 --- a/Ghidra/Framework/Graph/src/main/java/ghidra/graph/VisualGraphComponentProvider.java +++ b/Ghidra/Framework/Graph/src/main/java/ghidra/graph/VisualGraphComponentProvider.java @@ -165,7 +165,7 @@ public abstract class VisualGraphComponentProvider> passedVertices = matching; // 2) - failedVertices = findCurrentVerticesFailingTheFitler(matching); + failedVertices = findCurrentVerticesFailingTheFilter(matching); failedEdges = filterGraph.getAllEdges(failedVertices); Set allRelatedEdges = filterGraph.getAllEdges(passedVertices); @@ -119,7 +118,7 @@ public class FilterVerticesJob> filterGraph.unfilterVertices(passedVertices); } - private Set findCurrentVerticesFailingTheFitler(Set validVertices) { + private Set findCurrentVerticesFailingTheFilter(Set validVertices) { UnmodifiableIterator nonMatchingIterator = Iterators.filter(filterGraph.getUnfilteredVertices(), v -> !validVertices.contains(v)); From 54e33e60e027acf8cbf7e9d37537cbe5c765933c Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Fri, 31 Jan 2020 17:18:35 -0500 Subject: [PATCH 08/36] GT-3513 - Fixed Location References Provider's 'Make Selection' toolbar action --- .../locationreferences/LocationReferencesProvider.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java index 25e2c74eea..34ffcb2d1c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/navigation/locationreferences/LocationReferencesProvider.java @@ -398,12 +398,7 @@ public class LocationReferencesProvider extends ComponentProviderAdapter @Override public ActionContext getActionContext(MouseEvent event) { - if (event != null) { - if (referencesPanel.selectRow(event)) { - return new ActionContext(this, referencesPanel.getTable()); - } - } - return null; + return new ActionContext(this, referencesPanel.getTable()); } //================================================================================================== From 639d4b98953ef0299682c9b187884dbf4b86e4f8 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 3 Feb 2020 13:35:32 -0500 Subject: [PATCH 09/36] GT-3479 added missing support for structure/union merge of bitfields and trailing flex-array --- .../merge/datatypes/DataTypeMergeManager.java | 905 +++++++++++++----- .../merge/datatypes/DataTypeMerge1Test.java | 285 ++---- .../merge/datatypes/DataTypeMerge3Test.java | 346 ++++++- .../merge/datatypes/DataTypeMerge8Test.java | 7 +- .../database/data/DataTypeComponentDB.java | 2 +- .../program/database/data/StructureDB.java | 61 +- .../ghidra/program/model/data/Structure.java | 5 +- .../program/model/data/StructureDataType.java | 52 +- 8 files changed, 1185 insertions(+), 478 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java index 01caf5eff8..63007cc10c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/merge/datatypes/DataTypeMergeManager.java @@ -82,6 +82,7 @@ public class DataTypeMergeManager implements MergeResolver { private LongObjectHashtable latestResolvedDts; // maps Latest data type key -> resolved Data type private LongObjectHashtable origResolvedDts; // maps Original data type key -> resolved Data type private List fixUpList; // FixUpInfo objects that must be resolved after + private HashSet fixUpIDSet; // track types with fixups // data types have been added and conflicts resolved. private LongObjectHashtable cleanupPlaceHolderList; // placeholders that need to be removed. private int progressIndex; // index for showing progress @@ -509,7 +510,7 @@ public class DataTypeMergeManager implements MergeResolver { sb.append(" Data type name " + dt.getName() + ", component " + compDt.getDisplayName() + "\n"); } - showMessage("Unresolved Data Types", sb.toString()); + showMessage("Unresolved Data Types and Components", sb.toString()); } } @@ -1080,9 +1081,86 @@ public class DataTypeMergeManager implements MergeResolver { return resolvedDt; } + private void removeFixUps(long sourceDtID) { + if (!fixUpIDSet.remove(sourceDtID)) { + return; + } + Iterator iter = fixUpList.iterator(); + while (iter.hasNext()) { + FixUpInfo info = iter.next(); + if (info.id == sourceDtID) { + iter.remove(); + } + } + } + + private void updateFlexArray(long sourceDtID, Structure sourceDt, Structure destStruct, + LongObjectHashtable resolvedDataTypes) { + + DataTypeComponent flexDtc = sourceDt.getFlexibleArrayComponent(); + if (flexDtc == null) { + return; + } + + DataTypeManager sourceDTM = sourceDt.getDataTypeManager(); + + DataType sourceCompDt = flexDtc.getDataType(); + String comment = flexDtc.getComment(); + long sourceComponentID = sourceDTM.getID(sourceCompDt); + + // Try to get a mapping of the source data type to a result data type. + DataType resultCompDt = getResolvedComponent(sourceComponentID, resolvedDataTypes); + + if (resultCompDt == null) { + // We didn't have a map entry for the data type. + + if (!myDtAddedList.contains(Long.valueOf(sourceComponentID))) { + // Not added so should be in result if it wasn't deleted there. + DataType rDt = dtms[RESULT].getDataType(sourceComponentID); + if (rDt != null) { + resultCompDt = rDt; + } + } + if (resultCompDt == null) { + // Not added/resolved yet + // put an entry in the fixup list + fixUpList.add(new FixUpInfo(sourceDtID, sourceComponentID, Integer.MAX_VALUE, + resolvedDataTypes)); + fixUpIDSet.add(sourceDtID); + } + } + try { + if (resultCompDt != null) { + // There is a matching component data type in the result. + try { + // If I have compDt, it should now be from result DTM. + destStruct.setFlexibleArrayComponent(resultCompDt, flexDtc.getFieldName(), + comment); + } + catch (IllegalArgumentException e) { + displayError(destStruct, e); + DataType badDt = Undefined1DataType.dataType; + comment = "Couldn't add " + resultCompDt.getDisplayName() + " here. " + + e.getMessage() + " " + ((comment != null) ? (" " + comment) : ""); + destStruct.setFlexibleArrayComponent(badDt, flexDtc.getFieldName(), comment); + } + } + else { + destStruct.clearFlexibleArrayComponent(); + } + } + catch (IllegalArgumentException e) { + displayError(destStruct, e); + } + } + private void updateStructure(long sourceDtID, Structure sourceDt, Structure destStruct, LongObjectHashtable resolvedDataTypes) { + // NOTE: it is possible for the same destStruct to be updated more than once; + // therefor we must cleanup any previous obsolete fixups + removeFixUps(sourceDtID); + // Get an empty destination structure that is the correct size. destStruct.deleteAll(); @@ -1091,21 +1169,36 @@ public class DataTypeMergeManager implements MergeResolver { DataTypeManager sourceDTM = sourceDt.getDataTypeManager(); boolean aligned = sourceDt.isInternallyAligned(); - if (!aligned) { - destStruct.growStructure(sourceDt.getLength()); - } // Add each of the defined components back in. DataTypeComponent[] comps = sourceDt.getDefinedComponents(); - for (DataTypeComponent comp : comps) { - DataType dt = comp.getDataType(); - String comment = comp.getComment(); + int lastOffset = 0; + if (comps.length != 0) { + lastOffset = comps[comps.length - 1].getOffset(); + } + for (DataTypeComponent sourceComp : comps) { + DataType sourceCompDt = sourceComp.getDataType(); + BitFieldDataType bfDt = null; + String comment = sourceComp.getComment(); DataType resultCompDt = null; - long sourceComponentID = sourceDTM.getID(dt); + + if (sourceComp.isBitFieldComponent()) { + // NOTE: primitive type will be used if unable to resolve base type + bfDt = (BitFieldDataType) sourceCompDt; + sourceCompDt = bfDt.getBaseDataType(); + if (sourceCompDt instanceof AbstractIntegerDataType) { + resultCompDt = sourceCompDt.clone(dtms[RESULT]); + } + } + + long sourceComponentID = sourceDTM.getID(sourceCompDt); boolean deletedInLatest = false; // Try to get a mapping of the source data type to a result data type. - resultCompDt = getResolvedComponent(sourceComponentID, resolvedDataTypes); + if (resultCompDt == null) { + resultCompDt = getResolvedComponent(sourceComponentID, resolvedDataTypes); + } + if (resultCompDt == null) { // We didn't have a map entry for the data type. @@ -1120,74 +1213,142 @@ public class DataTypeMergeManager implements MergeResolver { // must have been deleted in LATEST // put an entry in the fixup list if this is a conflict deletedInLatest = true; - FixUpInfo info = new FixUpInfo(sourceDtID, sourceComponentID, - sourceDt.isInternallyAligned() ? comp.getOrdinal() : comp.getOffset(), - resolvedDataTypes); - fixUpList.add(info); } } - else { + if (resultCompDt == null) { // Not added/resolved yet // put an entry in the fixup list - fixUpList.add(new FixUpInfo(sourceDtID, sourceComponentID, - sourceDt.isInternallyAligned() ? comp.getOrdinal() : comp.getOffset(), + fixUpList.add(new FixUpInfo(sourceDtID, sourceComponentID, sourceComp, resolvedDataTypes)); + fixUpIDSet.add(sourceDtID); + } + if (bfDt != null && + (resultCompDt == null || !BitFieldDataType.isValidBaseDataType(resultCompDt))) { + // use primitive type as fallback (may get fixed-up later) + resultCompDt = bfDt.getPrimitiveBaseDataType(); } } try { if (resultCompDt != null) { + + int length = resultCompDt.getLength(); + if (length <= 0) { + length = sourceComp.getLength(); + } + // There is a matching component data type in the result. if (aligned) { - try { - // If I have compDt, it should now be from result DTM. - destStruct.add(resultCompDt, comp.getLength(), comp.getFieldName(), - comment); + if (bfDt != null) { + destStruct.addBitField(resultCompDt, bfDt.getDeclaredBitSize(), + sourceComp.getFieldName(), comment); } - catch (IllegalArgumentException e) { - displayError(destStruct, e); - DataType badDt = BadDataType.dataType; - comment = "Couldn't add " + resultCompDt.getDisplayName() + " here. " + - e.getMessage() + " " + ((comment != null) ? (" " + comment) : ""); - destStruct.add(badDt, comp.getLength(), comp.getFieldName(), comment); + else { + try { + // If I have compDt, it should now be from result DTM. + destStruct.add(resultCompDt, length, sourceComp.getFieldName(), + comment); + } + catch (IllegalArgumentException e) { + displayError(destStruct, e); + DataType badDt = BadDataType.dataType; + comment = "Couldn't add " + resultCompDt.getDisplayName() + + " here. " + e.getMessage() + " " + + ((comment != null) ? (" " + comment) : ""); + destStruct.add(badDt, sourceComp.getLength(), + sourceComp.getFieldName(), comment); + } } } + else if (bfDt != null) { + destStruct.insertBitFieldAt(sourceComp.getOffset(), sourceComp.getLength(), + bfDt.getBitOffset(), resultCompDt, bfDt.getDeclaredBitSize(), + sourceComp.getFieldName(), comment); + } else { try { // If I have compDt, it should now be from result DTM. - destStruct.replaceAtOffset(comp.getOffset(), resultCompDt, - comp.getLength(), comp.getFieldName(), comment); + // If not last component must constrain length to original component size + int offset = sourceComp.getOffset(); + if (offset < lastOffset && length > sourceComp.getLength()) { + // The data type is too big, so adjust the component length to what will fit. + int extraBytesNeeded = length - sourceComp.getLength(); + length = sourceComp.getLength(); + // Output a warning indicating the structure has a data type that doesn't fit. + String message = + "Structure Merge: Not enough undefined bytes to fit " + + resultCompDt.getPathName() + " in structure " + + destStruct.getPathName() + " at offset 0x" + + Integer.toHexString(offset) + "." + "\nIt needs " + + extraBytesNeeded + " more byte(s) to be able to fit."; + Msg.warn(this, message); + } + destStruct.insertAtOffset(sourceComp.getOffset(), resultCompDt, length, + sourceComp.getFieldName(), comment); } catch (IllegalArgumentException e) { displayError(destStruct, e); DataType badDt = BadDataType.dataType; comment = "Couldn't add " + resultCompDt.getDisplayName() + " here. " + e.getMessage() + " " + ((comment != null) ? (" " + comment) : ""); - destStruct.replaceAtOffset(comp.getOffset(), badDt, comp.getLength(), - comp.getFieldName(), comment); + destStruct.insertAtOffset(sourceComp.getOffset(), badDt, + sourceComp.getLength(), sourceComp.getFieldName(), comment); } } } else if (aligned) { // Add a Bad data type to prevent the ordinal values and component count from changing. // These should get cleaned up later in the conflict cleanup code. - destStruct.add(BadDataType.dataType, comp.getLength(), comp.getFieldName(), - comment); + destStruct.add(BadDataType.dataType, sourceComp.getLength(), + sourceComp.getFieldName(), comment); } else if (!deletedInLatest) { // If the data type wasn't removed and isn't the result, // put a Bad data type to try to keep field name and comment. // If it was deleted, there should already be default data types in place of this component. - destStruct.replaceAtOffset(comp.getOffset(), BadDataType.dataType, - comp.getLength(), comp.getFieldName(), comment); + destStruct.insertAtOffset(sourceComp.getOffset(), BadDataType.dataType, + sourceComp.getLength(), sourceComp.getFieldName(), comment); } + } - catch (IllegalArgumentException e) { + catch (IllegalArgumentException | InvalidDataTypeException e) { displayError(destStruct, e); } } + if (!aligned) { + adjustStructureSize(destStruct, sourceDt.getLength()); + } + + updateFlexArray(sourceDtID, sourceDt, destStruct, resolvedDataTypes); } - private void displayError(Composite destComposite, IllegalArgumentException e) { + /** + * Bitfield insertions can cause excess growth of structure which must be trimmed. + * @param struct structure to be trimmed + * @param preferredSize preferred structure size + */ + private static void adjustStructureSize(Structure struct, int preferredSize) { + + DataTypeComponent dtc = struct.getComponentAt(preferredSize); + if (dtc == null) { + struct.growStructure(preferredSize - struct.getLength()); + return; + } + + int startOrdinal = dtc.getOrdinal(); + if (dtc.getOffset() != preferredSize) { + ++startOrdinal; + } + + for (int i = struct.getNumComponents() - 1; i >= startOrdinal; i--) { + DataTypeComponent comp = struct.getComponent(i); + if (comp.getOffset() < preferredSize || comp.getDataType() != DataType.DEFAULT) { + break; + } + struct.delete(i); + } + } + + private void displayError(Composite destComposite, Exception e) { String msg = "Some of your changes to " + destComposite.getName() + " cannot be merged.\nProblem: " + e.getMessage(); String typeName = (destComposite instanceof Union) ? "Union" : "Structure"; @@ -1197,6 +1358,10 @@ public class DataTypeMergeManager implements MergeResolver { private void updateUnion(long sourceDtID, Union sourceDt, Union destUnion, LongObjectHashtable resolvedDataTypes) { + // NOTE: it is possible for the same destUnion to be updated more than once; + // therefor we must cleanup any previous obsolete fixups + removeFixUps(sourceDtID); + // Remove all the components from the destination union. while (destUnion.getNumComponents() > 0) { destUnion.delete(0); @@ -1208,12 +1373,27 @@ public class DataTypeMergeManager implements MergeResolver { DataTypeManager sourceDTM = sourceDt.getDataTypeManager(); // Add each of the defined components back in. - for (int i = 0; i < sourceDt.getNumComponents(); i++) { - DataTypeComponent sourceComp = sourceDt.getComponent(i); - String comment = sourceComp.getComment(); + for (DataTypeComponent sourceComp : sourceDt.getComponents()) { DataType sourceCompDt = sourceComp.getDataType(); + BitFieldDataType bfDt = null; + String comment = sourceComp.getComment(); + DataType resultCompDt = null; + + if (sourceComp.isBitFieldComponent()) { + // NOTE: primitive type will be used if unable to resolve base type + bfDt = (BitFieldDataType) sourceCompDt; + sourceCompDt = bfDt.getBaseDataType(); + if (sourceCompDt instanceof AbstractIntegerDataType) { + resultCompDt = sourceCompDt.clone(dtms[RESULT]); + } + } + long sourceCompID = sourceDTM.getID(sourceCompDt); - DataType resultCompDt = getResolvedComponent(sourceCompID, resolvedDataTypes); + + // Try to get a mapping of the source data type to a result data type. + if (resultCompDt == null) { + resultCompDt = getResolvedComponent(sourceCompID, resolvedDataTypes); + } if (resultCompDt == null) { if (!myDtAddedList.contains(Long.valueOf(sourceCompID))) { @@ -1228,51 +1408,57 @@ public class DataTypeMergeManager implements MergeResolver { // put an entry in RESULT for later fixup if // it is in conflict FixUpInfo info = - new FixUpInfo(sourceDtID, sourceCompID, i, resolvedDataTypes); + new FixUpInfo(sourceDtID, sourceCompID, sourceComp, resolvedDataTypes); fixUpList.add(info); + fixUpIDSet.add(sourceDtID); } } else { // Not added/resolved yet // put an entry in RESULT for later fixup - fixUpList.add(new FixUpInfo(sourceDtID, sourceCompID, i, resolvedDataTypes)); + fixUpList.add( + new FixUpInfo(sourceDtID, sourceCompID, sourceComp, resolvedDataTypes)); + fixUpIDSet.add(sourceDtID); + } + if (bfDt != null && + (resultCompDt == null || !BitFieldDataType.isValidBaseDataType(resultCompDt))) { + // use primitive type as fallback (may get fixed-up later) + resultCompDt = bfDt.getPrimitiveBaseDataType(); } } - if (resultCompDt != null) { - // There is a matching component data type in the result. - DataTypeComponent resultComp; - try { - try { - int resultCompDtLength = resultCompDt.getLength(); - if (resultCompDtLength > 0) { - resultComp = destUnion.add(resultCompDt); + try { + if (resultCompDt != null) { + if (bfDt != null) { + destUnion.addBitField(resultCompDt, bfDt.getBitSize(), + sourceComp.getFieldName(), comment); + } + else { + // There is a matching component data type in the result. + int compLen = resultCompDt.getLength(); + if (compLen <= 0) { + compLen = sourceComp.getLength(); } - else { - resultComp = destUnion.add(resultCompDt, sourceComp.getLength()); + try { + destUnion.add(resultCompDt, compLen, sourceComp.getFieldName(), + comment); + } + catch (IllegalArgumentException e1) { + displayError(destUnion, e1); + DataType badDt = BadDataType.dataType; + comment = "Couldn't add " + resultCompDt.getDisplayName() + " here. " + + e1.getMessage() + ((comment != null) ? (" " + comment) : ""); + destUnion.add(badDt, sourceComp.getLength(), sourceComp.getFieldName(), + comment); } } - catch (IllegalArgumentException e1) { - displayError(destUnion, e1); - DataType badDt = BadDataType.dataType; - comment = "Couldn't add " + resultCompDt.getDisplayName() + " here. " + - e1.getMessage() + ((comment != null) ? (" " + comment) : ""); - resultComp = destUnion.add(badDt, sourceComp.getLength()); - } - try { - resultComp.setFieldName(sourceComp.getFieldName()); - } - catch (DuplicateNameException e) { - // Since all components were removed originally, shouldn't see this. - } - resultComp.setComment(comment); } - catch (IllegalArgumentException e1) { - displayError(destUnion, e1); + else { + destUnion.add(BadDataType.dataType, sourceComp.getLength(), + sourceComp.getFieldName(), comment); } } - else { - destUnion.add(BadDataType.dataType, sourceComp.getLength(), - sourceComp.getFieldName(), comment); + catch (IllegalArgumentException | InvalidDataTypeException e) { + displayError(destUnion, e); } } } @@ -1309,6 +1495,10 @@ public class DataTypeMergeManager implements MergeResolver { FunctionDefinition sourceFunctionDefDt, FunctionDefinition destDt, LongObjectHashtable resolvedDataTypes) { + // NOTE: it is possible for the same function def to be updated more than once; + // therefor we must cleanup any previous obsolete fixups + removeFixUps(sourceFunctionDefDtID); + long oldLastChangeTime = sourceFunctionDefDt.getLastChangeTime(); long oldLastChangeTimeInSourceArchive = sourceFunctionDefDt.getLastChangeTimeInSourceArchive(); @@ -1344,21 +1534,21 @@ public class DataTypeMergeManager implements MergeResolver { /** * Get the resolved data type for either the return type or a variable. * @param id id of FunctionDefinition - * @param paramID ID of either the return type or a variable + * @param paramDatatypeID ID of either the return or variable dataty type ID * @param index >=0 is the index of the variable; <0 means the paramID is * the return type * @param resolvedDataTypes hashtable to use for resolving * @return resolved data type or the default data type if the data type * has not been resolved yet */ - private DataType getResolvedParam(long id, long paramID, int index, + private DataType getResolvedParam(long id, long paramDatatypeID, int index, LongObjectHashtable resolvedDataTypes) { - DataType resolvedDt = getResolvedComponent(paramID, resolvedDataTypes); + DataType resolvedDt = getResolvedComponent(paramDatatypeID, resolvedDataTypes); if (resolvedDt == null) { - if (!myDtAddedList.contains(Long.valueOf(paramID))) { + if (!myDtAddedList.contains(Long.valueOf(paramDatatypeID))) { // Not added so should be in result if it wasn't deleted there. - DataType resultsDt = dtms[RESULT].getDataType(paramID); + DataType resultsDt = dtms[RESULT].getDataType(paramDatatypeID); if (resultsDt != null) { resolvedDt = resultsDt; } @@ -1367,15 +1557,17 @@ public class DataTypeMergeManager implements MergeResolver { // put an entry in RESULT for later fixup if // it is in conflict resolvedDt = DataType.DEFAULT; - FixUpInfo info = new FixUpInfo(id, paramID, index, resolvedDataTypes); + FixUpInfo info = new FixUpInfo(id, paramDatatypeID, index, resolvedDataTypes); fixUpList.add(info); + fixUpIDSet.add(id); } } else { // Not added/resolved yet // put an entry in RESULT for later fixup resolvedDt = DataType.DEFAULT; - fixUpList.add(new FixUpInfo(id, paramID, index, resolvedDataTypes)); + fixUpList.add(new FixUpInfo(id, paramDatatypeID, index, resolvedDataTypes)); + fixUpIDSet.add(id); } } return resolvedDt; @@ -2058,31 +2250,34 @@ public class DataTypeMergeManager implements MergeResolver { private void fixUpDataTypes() { // fix data types in the fixUpList - ArrayList tempList = new ArrayList<>(fixUpList); - long currentID = -1; - long previousID = -1; + ArrayList unresolvedFixups = new ArrayList<>(); - for (int i = 0; i < tempList.size(); i++) { + for (int i = 0; i < fixUpList.size(); i++) { - FixUpInfo info = tempList.get(i); + FixUpInfo info = fixUpList.get(i); DataType dt = info.ht.get(info.id); - if (dt instanceof Composite) { - previousID = currentID; - currentID = info.id; - - Composite destCdt = (Composite) dt; - - if (dt instanceof Union) { - if (previousID != currentID) { - fixUpUnion(info.id, (Union) destCdt); + if (dt instanceof Union) { + // Fixups for a union are done all at once + // Determine number of applicable fixups (assumes they are sequential) + int count = 1; + for (int n = i + 1; n < fixUpList.size(); n++) { + if (fixUpList.get(n).id != info.id) { + break; } + ++count; } - else { - fixUpStructure(info, (Structure) destCdt); + fixUpUnion(info.id, (Union) dt, i, count, unresolvedFixups); + i += count - 1; + } + else if (dt instanceof Structure) { + if (!fixUpStructure(info, (Structure) dt)) { + unresolvedFixups.add(info); } } else if (dt instanceof FunctionDefinition) { - fixUpFunctionDef(info, (FunctionDefinition) dt); + if (!fixUpFunctionDef(info, (FunctionDefinition) dt)) { + unresolvedFixups.add(info); + } } else { DataTypeManager dtm = info.getDataTypeManager(); @@ -2095,12 +2290,19 @@ public class DataTypeMergeManager implements MergeResolver { // DataType sourceDt = info.getDataTypeManager().getDataType(info.id); // System.out.println("Couldn't fixup " + sourceDt.getPathName()); // } - fixUpList.remove(info); } } + // update fixup list with those that were unresolved + fixUpList = unresolvedFixups; } - private void fixUpFunctionDef(FixUpInfo info, FunctionDefinition fd) { + /** + * Fix up the function definition using the fix up info for a component. + * @param info fixup info + * @param fd function definition to be fixed-up + * @return true if fixup successfully processed else false + */ + private boolean fixUpFunctionDef(FixUpInfo info, FunctionDefinition fd) { long lastChangeTime = fd.getLastChangeTime(); // Don't let the time change. DataType dt = resolve(info.compID, info.getDataTypeManager(), info.ht); @@ -2114,97 +2316,223 @@ public class DataTypeMergeManager implements MergeResolver { } } fd.setLastChangeTime(lastChangeTime); // Reset the last change time to the merged data type's. - fixUpList.remove(info); + return true; } /** - * Fix up the structure using the fix up info for a component. + * Process fixup for aligned structure component or trailing flexible array + * @param info fixup info + * @param struct result structure + * @param dt component datatype + * @return false if component not found, else true */ - private void fixUpStructure(FixUpInfo info, Structure struct) { + private boolean fixUpAlignedStructureComponent(FixUpInfo info, Structure struct, DataType dt) { + int ordinal = info.index; + boolean isFlexArrayFixup = (info.index == Integer.MAX_VALUE); - long lastChangeTime = struct.getLastChangeTime(); // Don't let the time change. - DataType compDt = resolve(info.compID, info.getDataTypeManager(), info.ht); - - if (compDt != null) { - int length = compDt.getLength(); - if (length == 0) { - length = 1; // Don't want 0 sized components. - } - if (struct.isInternallyAligned()) { - int ordinal = info.index; - int numComponents = struct.getNumComponents(); - if (ordinal >= 0 && ordinal < numComponents) { - DataTypeComponent dtc = struct.getComponent(ordinal); - dtc = struct.replace(ordinal, compDt, length, dtc.getFieldName(), - dtc.getComment()); - } - else { - Msg.warn(this, "Data Type Merge: Couldn't get component " + ordinal + " in " + - struct.getPathName() + " data type during fix up."); - return; // Don't remove this FixUpInfo from the fixupList so the user will get notified. - } - } - else { - int offset = info.index; - DataTypeComponent dtc = struct.getComponentAt(offset); - if (dtc != null) { - int ordinal = dtc.getOrdinal(); - int dtcLength = dtc.getLength(); - if (length < 0) { - length = dtcLength; - } - int bytesNeeded = length - dtcLength; - if (bytesNeeded > 0) { - int bytesAvailable = getNumUndefinedBytes(struct, ordinal + 1); - if (bytesAvailable < bytesNeeded) { - // The data type is too big, so adjust the component length to what will fit. - length = dtcLength + bytesAvailable; - // Output a warning indicating the structure has a data type that doesn't fit. - String message = - "Merging Data Types: Not enough undefined bytes to fit " + - compDt.getPathName() + " in structure " + struct.getPathName() + - " at offset 0x" + Integer.toHexString(offset) + "." + - "\nIt needs " + (bytesNeeded - bytesAvailable) + - " more byte(s) to be able to fit."; - Msg.warn(this, message); - } - } - dtc = struct.replaceAtOffset(offset, compDt, length, dtc.getFieldName(), - dtc.getComment()); - } - else { - Msg.warn(this, "Couldn't get component at offset " + offset + " in " + - struct.getPathName()); - } + DataTypeComponent dtc = null; + if (isFlexArrayFixup) { + dtc = struct.getFlexibleArrayComponent(); + } + else { + if (ordinal >= 0 || ordinal < struct.getNumComponents()) { + dtc = struct.getComponent(ordinal); } } - // Check to see if we have a placeholder - if (struct.isInternallyAligned()) { - int ordinal = info.index; - int numComponents = struct.getNumComponents(); - if (ordinal >= 0 && ordinal < numComponents) { - DataTypeComponent component = struct.getComponent(ordinal); - DataType dataType = component.getDataType(); - // Check to see if we have a placeholder, wait to remove it so we don't mess up ordinals. - if (dataType == BadDataType.dataType) { - addToCleanupList(info); + if (dtc == null) { + return false; + } + if (isFlexArrayFixup) { + try { + struct.setFlexibleArrayComponent(dt, dtc.getFieldName(), dtc.getComment()); + } + catch (IllegalArgumentException e) { + displayError(struct, e); + DataType badDt = Undefined1DataType.dataType; + String comment = dtc.getComment(); + comment = "Couldn't add " + dt.getDisplayName() + "[ ] here. " + e.getMessage() + + " " + ((comment != null) ? (" " + comment) : ""); + struct.replace(ordinal, badDt, dtc.getLength(), dtc.getFieldName(), comment); + struct.setFlexibleArrayComponent(badDt, dtc.getFieldName(), comment); + } + } + else if (dtc.isBitFieldComponent()) { + if (BitFieldDataType.isValidBaseDataType(dt)) { + // replace bitfield base datatype - silent if updated type is not a valid base type + BitFieldDataType bfDt = (BitFieldDataType) dtc.getDataType(); + struct.delete(ordinal); + try { + struct.insertBitField(ordinal, bfDt.getLength(), bfDt.getBitOffset(), dt, + bfDt.getDeclaredBitSize(), dtc.getFieldName(), dtc.getComment()); + } + catch (InvalidDataTypeException e) { + Msg.error(this, "Unexpected datatype merge fixup error", e); } } } else { - int offset = info.index; - DataTypeComponent component = struct.getComponentAt(offset); - if (component != null) { - DataType dataType = component.getDataType(); - if (dataType == BadDataType.dataType) { - // Clear the placeholder. - struct.clearComponent(component.getOrdinal()); + // handle non-bitfield component fixup + int length = dt.getLength(); + if (length <= 0) { + length = dtc.getLength(); + } + try { + struct.replace(ordinal, dt, length, dtc.getFieldName(), dtc.getComment()); + } + catch (IllegalArgumentException e) { + displayError(struct, e); + DataType badDt = BadDataType.dataType; + String comment = dtc.getComment(); + comment = "Couldn't add " + dt.getDisplayName() + " here. " + e.getMessage() + " " + + ((comment != null) ? (" " + comment) : ""); + struct.replace(ordinal, badDt, dtc.getLength(), dtc.getFieldName(), comment); + } + } + return true; + } + + /** + * Process fixup for unaligned structure component + * @param info fixup info + * @param struct result structure + * @param dt component datatype + * @return false if component not found, else true + */ + private boolean fixUpUnalignedStructureComponent(FixUpInfo info, Structure struct, + DataType dt) { + int offset = info.index; + DataTypeComponent dtc = struct.getComponentAt(offset); + if (dtc == null) { + return false; + } + if (dtc.isBitFieldComponent()) { + dtc = info.findStructureBitFieldComponentAtOrAfter(struct, dtc); + if (dtc != null) { + if (BitFieldDataType.isValidBaseDataType(dt)) { + // replace bitfield base datatype - silent if updated type is not a valid base type + BitFieldDataType bfDt = (BitFieldDataType) dtc.getDataType(); + struct.delete(dtc.getOrdinal()); + try { + struct.insertBitFieldAt(dtc.getOffset(), bfDt.getLength(), + bfDt.getBitOffset(), dt, bfDt.getDeclaredBitSize(), dtc.getFieldName(), + dtc.getComment()); + } + catch (InvalidDataTypeException e) { + // should never occur + Msg.error(this, "Unexpected bitfield merge fixup error", e); + } + } + } + else { + Msg.error(this, "Structure Merge: failed to identify bitfield fixup component (\n" + + info + ")"); + } + } + else { + // handle non-bitfield component fixup + int ordinal = dtc.getOrdinal(); + int dtcLength = dtc.getLength(); + int length = dt.getLength(); + if (length <= 0) { + length = dtcLength; + } + int bytesNeeded = length - dtcLength; + if (bytesNeeded > 0) { + int bytesAvailable = getNumUndefinedBytes(struct, ordinal + 1); + if (bytesAvailable < bytesNeeded) { + // The data type is too big, so adjust the component length to what will fit. + length = dtcLength + bytesAvailable; + // Output a warning indicating the structure has a data type that doesn't fit. + String message = "Structure Merge: Not enough undefined bytes to fit " + + dt.getPathName() + " in structure " + struct.getPathName() + + " at offset 0x" + Integer.toHexString(offset) + "." + "\nIt needs " + + (bytesNeeded - bytesAvailable) + " more byte(s) to be able to fit."; + Msg.warn(this, message); + } + } + try { + struct.replaceAtOffset(offset, dt, length, dtc.getFieldName(), dtc.getComment()); + } + catch (IllegalArgumentException e) { + displayError(struct, e); + DataType badDt = BadDataType.dataType; + String comment = dtc.getComment(); + comment = "Couldn't add " + dt.getDisplayName() + " here. " + e.getMessage() + " " + + ((comment != null) ? (" " + comment) : ""); + struct.replaceAtOffset(offset, badDt, dtc.getLength(), dtc.getFieldName(), comment); + } + } + return true; + } + + /** + * Fix up the structure using the fix up info for a component. + * @param info fixup info + * @param struct structure to be fixed-up + * @return true if fixup successfully processed else false + */ + private boolean fixUpStructure(FixUpInfo info, Structure struct) { + + long lastChangeTime = struct.getLastChangeTime(); // Don't let the time change. + try { + + DataType compDt = resolve(info.compID, info.getDataTypeManager(), info.ht); + + boolean isFlexArrayFixup = (info.index == Integer.MAX_VALUE); + + if (compDt != null) { + if (struct.isInternallyAligned() || isFlexArrayFixup) { + if (!fixUpAlignedStructureComponent(info, struct, compDt)) { + String msg = + isFlexArrayFixup ? "flex-array component" : ("component " + info.index); + Msg.warn(this, "Structure Merge: Couldn't get " + msg + " in " + + struct.getPathName() + " data type during fix up."); + return false; // Don't remove this FixUpInfo from the fixupList so the user will get notified. + } + return true; + } + + if (!fixUpUnalignedStructureComponent(info, struct, compDt)) { + Msg.warn(this, "Structure Merge: Couldn't get component at offset " + + info.index + " in " + struct.getPathName()); + return false; } } + + // Datatype failed to resolved - check to see if we have a placeholder + else if (isFlexArrayFixup) { + struct.clearFlexibleArrayComponent(); + } + else if (struct.isInternallyAligned()) { + int ordinal = info.index; + int numComponents = struct.getNumComponents(); + if (ordinal >= 0 && ordinal < numComponents) { + DataTypeComponent component = struct.getComponent(ordinal); + DataType dataType = component.getDataType(); + // Check to see if we have a placeholder, wait to remove it so we don't mess up ordinals. + if (dataType == BadDataType.dataType) { + addToCleanupList(info); + } + } + } + else { + int offset = info.index; + DataTypeComponent component = struct.getComponentAt(offset); + if (component != null) { + DataType dataType = component.getDataType(); + if (dataType == BadDataType.dataType) { + // Clear the placeholder. + struct.clearComponent(component.getOrdinal()); + } + + } + } + return true; + } + finally { + struct.setLastChangeTime(lastChangeTime); // Reset the last change time to the merged data type's. } - struct.setLastChangeTime(lastChangeTime); // Reset the last change time to the merged data type's. - fixUpList.remove(info); } /** @@ -2247,74 +2575,108 @@ public class DataTypeMergeManager implements MergeResolver { cleanUpInfo.add(index, ht); } + private void fixUpUnionComponent(Union union, FixUpInfo info) { + int ordinal = info.index; + + DataType compDt = resolve(info.compID, info.getDataTypeManager(), info.ht); + if (compDt != null) { + + DataTypeComponent dtc = union.getComponent(ordinal); + if (dtc != null && dtc.isBitFieldComponent()) { + if (BitFieldDataType.isValidBaseDataType(compDt)) { + // replace bitfield base datatype - silent if updated type is not a valid base type + BitFieldDataType bfDt = (BitFieldDataType) dtc.getDataType(); + union.delete(ordinal); + try { + union.insertBitField(ordinal, compDt, bfDt.getDeclaredBitSize(), + dtc.getFieldName(), dtc.getComment()); + } + catch (InvalidDataTypeException e) { + // should never occur + Msg.error(this, "Unexpected datatype merge fixup error", e); + } + } + } + else { + // handle non-bitfield component fixup + int length = compDt.getLength(); + if (length <= 0) { + length = dtc.getLength(); + } + union.delete(ordinal); + try { + union.insert(ordinal, compDt, length, dtc.getFieldName(), dtc.getComment()); + } + catch (IllegalArgumentException e) { + displayError(union, e); + DataType badDt = BadDataType.dataType; + String comment = dtc.getComment(); + comment = "Couldn't add " + compDt.getDisplayName() + " here. " + + e.getMessage() + " " + ((comment != null) ? (" " + comment) : ""); + union.insert(ordinal, badDt, dtc.getLength(), dtc.getFieldName(), comment); + } + } + } + + // Datatype failed to resolved - check to see if we have a placeholder + else { + DataTypeComponent component = union.getComponent(ordinal); + DataType dataType = component.getDataType(); + if (dataType == BadDataType.dataType) { + addToCleanupList(info); + } + } + } + /** * Fix up the Union by going through all of the fix up info objects that * have the given ID. * @param id id of the Union * @param union union that is updated + * @param firstFixupIndex first applicable fixupList entry index + * @param fixupCount total number of fixup entries to be applied + * @param unresolvedFixups list to which unprocessed fixups should be added */ - private void fixUpUnion(long id, Union union) { + private void fixUpUnion(long id, Union union, int firstFixupIndex, int fixupCount, + ArrayList unresolvedFixups) { + + // presence of fixup implies union is not empty long lastChangeTime = union.getLastChangeTime(); // Don't let the time change. - int preFixupLength = union.getLength(); - DataTypeComponent[] dtcs = union.getComponents(); - // Add a freeze length component to keep the size from changing during fixup. - // Otherwise other datatypes will respond to size change and update their change times. - union.add(BadDataType.dataType, preFixupLength); - // Delete all but the freezeLengthComponent - while (union.getNumComponents() > 1) { - union.delete(0); - } - for (int ordinal = 0; ordinal < dtcs.length; ordinal++) { - DataTypeComponent rdtc = null; - FixUpInfo info = findFixUpInfo(id, ordinal); - if (info != null) { - DataType compDt = resolve(info.compID, info.getDataTypeManager(), info.ht); - if (compDt != null) { - int length = compDt.getLength(); - if (length == 0) { - length = 1; // Don't want 0 sized components. - } - rdtc = union.insert(ordinal, compDt, length); + try { + + int preFixupLength = union.getLength(); + int numComponents = union.getNumComponents(); + + // Add a freeze length component to keep the union size from changing during fixup. + // Otherwise other datatypes will respond to size change and update their change times. + union.add(BadDataType.dataType, preFixupLength); + + // Process all fixups for union + int endIndex = firstFixupIndex + fixupCount; + for (int i = firstFixupIndex; i < endIndex; i++) { + FixUpInfo info = fixUpList.get(i); // assume info applies to union + int ordinal = info.index; + if (ordinal < 0 || ordinal >= numComponents) { + Msg.warn(this, "Union Merge: Couldn't get component " + ordinal + " in " + + union.getPathName() + " data type during fix up."); + unresolvedFixups.add(info); } - // Check to see if we have a placeholder - DataTypeComponent component = union.getComponent(ordinal); - DataType dataType = component.getDataType(); - // Check to see if we have a placeholder, re-insert it so we don't mess up ordinals. - if (dataType == BadDataType.dataType) { - if (rdtc == null) { - rdtc = - union.insert(ordinal, BadDataType.dataType, dtcs[ordinal].getLength()); // Put the placeholder back for now. - } - addToCleanupList(info); + else { + fixUpUnionComponent(union, info); } - fixUpList.remove(info); - } - else { - DataType compDt = dtcs[ordinal].getDataType(); - rdtc = union.insert(ordinal, compDt); } - if (rdtc != null) { - try { - rdtc.setFieldName(dtcs[ordinal].getFieldName()); - } - catch (DuplicateNameException e) { - // Since all components were removed originally, shouldn't see this. - } - rdtc.setComment(dtcs[ordinal].getComment()); + // Remove the freeze length component that is no longer needed. + DataType dataType = union.getComponent(numComponents).getDataType(); + // Check to see if we have a placeholder, wait to remove it so we don't mess up ordinals. + if (dataType == BadDataType.dataType) { + union.delete(numComponents); } } - - // Remove the freeze length component that is no longer needed. - int lastIndex = union.getNumComponents() - 1; - DataType dataType = union.getComponent(lastIndex).getDataType(); - // Check to see if we have a placeholder, wait to remove it so we don't mess up ordinals. - if (dataType == BadDataType.dataType) { - union.delete(lastIndex); + finally { + union.setLastChangeTime(lastChangeTime); // Reset the last change time to the merged data type's. } - - union.setLastChangeTime(lastChangeTime); // Reset the last change time to the merged data type's. } /** @@ -2349,15 +2711,15 @@ public class DataTypeMergeManager implements MergeResolver { return dt; } - private FixUpInfo findFixUpInfo(long id, int index) { - for (int i = 0; i < fixUpList.size(); i++) { - FixUpInfo info = fixUpList.get(i); - if (info.id == id && info.index == index) { - return info; - } - } - return null; - } +// private FixUpInfo findFixUpInfo(long id, int index) { +// for (int i = 0; i < fixUpList.size(); i++) { +// FixUpInfo info = fixUpList.get(i); +// if (info.id == id && info.index == index) { +// return info; +// } +// } +// return null; +// } private void processDataTypeSourceChanged(long id) { if (dataTypeSourceWasChanged(id, dtms[MY])) { @@ -2604,6 +2966,7 @@ public class DataTypeMergeManager implements MergeResolver { origResolvedDts = new LongObjectHashtable<>(); fixUpList = new ArrayList<>(); + fixUpIDSet = new HashSet<>(); totalConflictCount += dtConflictList.size(); cleanupPlaceHolderList = new LongObjectHashtable<>(); @@ -2859,6 +3222,14 @@ public class DataTypeMergeManager implements MergeResolver { return dtms[MY]; } + private static int getComponentFixupIndex(DataTypeComponent dtc) { + Composite composite = (Composite) dtc.getParent(); + if (composite.isInternallyAligned() || (composite instanceof Union)) { + return dtc.getOrdinal(); + } + return dtc.getOffset(); + } + /** * FixUpInfo objects that must be resolved after * data types have been added and conflicts resolved. @@ -2869,13 +3240,18 @@ public class DataTypeMergeManager implements MergeResolver { int index; LongObjectHashtable ht; + // bitfield info + int bitOffset = -1; + int bitSize = -1; + /** * Construct info needed to fix up data types after base types * or components were resolved. * @param id id of data type needed to be fixed up * @param compID id of either component or base type * @param index offset into unaligned structure, or ordinal into union or aligned - * structure; for other data types, offset is not used (specify -1) + * structure; or parameter/return ordinal; for other data types index is not used (specify -1). + * For structure trailing flex-array specify {@link Integer#MAX_VALUE}. * @param resolvedDataTypes hashtable used for resolving the data type */ FixUpInfo(long id, long compID, int index, @@ -2886,6 +3262,53 @@ public class DataTypeMergeManager implements MergeResolver { this.ht = resolvedDataTypes; } + /** + * Construct info needed to fix up data types after base types + * or components were resolved. + * @param id id of data type needed to be fixed up + * @param compID datatype id of either component or base type + * @param sourceDtc associated composite datatype component + * @param resolvedDataTypes hashtable used for resolving the data type + */ + FixUpInfo(long id, long compID, DataTypeComponent sourceDtc, + LongObjectHashtable resolvedDataTypes) { + this(id, compID, getComponentFixupIndex(sourceDtc), resolvedDataTypes); + if (sourceDtc.isBitFieldComponent()) { + BitFieldDataType bfDt = (BitFieldDataType) sourceDtc.getDataType(); + bitSize = bfDt.getDeclaredBitSize(); + bitOffset = bfDt.getBitOffset(); + } + } + + /** + * Find unaligned structure bitfield component at or after specified component + * which matches this info's bitfield data. + * @param struct structure + * @param dtc structure component contained within struct + * @return bitfield component which matches info or null + */ + DataTypeComponent findStructureBitFieldComponentAtOrAfter(Structure struct, + DataTypeComponent dtc) { + if (bitOffset < 0) { + return null; + } + int maxOrdinal = struct.getNumComponents(); + while (dtc != null && dtc.getOffset() <= index) { + if (dtc.isBitFieldComponent()) { + BitFieldDataType bfDt = (BitFieldDataType) dtc.getDataType(); + if (bitSize == bfDt.getDeclaredBitSize() && bitOffset == bfDt.getBitOffset()) { + return dtc; + } + } + int nextOrdinal = dtc.getOrdinal() + 1; + if (nextOrdinal > maxOrdinal) { + break; + } + struct.getComponent(nextOrdinal); + } + return null; + } + @Override public String toString() { String htStr = "MY"; @@ -2898,9 +3321,13 @@ public class DataTypeMergeManager implements MergeResolver { htStr = "LATEST/RESULTS"; dtm = dtms[LATEST]; } - return "\n" + "ID = " + Long.toHexString(id) + ",\n" + "dt = " + dtm.getDataType(id) + - ",\n" + "component ID = " + Long.toHexString(compID) + ",\n" + "component dt = " + - dtm.getDataType(compID) + ",\n" + "offset/index = " + index + ",\n" + "ht = " + + String bitInfo = ""; + if (bitOffset >= 0) { + bitInfo = "\nbitOffset=" + bitOffset + ",\nbitSize = " + bitSize + ",\n"; + } + return "\n" + "ID = " + Long.toHexString(id) + ",\ndt = " + dtm.getDataType(id) + + ",\ncomponent ID = " + Long.toHexString(compID) + ",\ncomponent dt = " + + dtm.getDataType(compID) + ",\noffset/index = " + index + ",\n" + bitInfo + "ht = " + htStr + "\n"; } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java index 2c90b5aa48..eb2f312c7e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge1Test.java @@ -17,6 +17,8 @@ package ghidra.app.merge.datatypes; import static org.junit.Assert.*; +import java.util.concurrent.atomic.AtomicReference; + import org.junit.Assert; import org.junit.Test; @@ -35,38 +37,48 @@ import ghidra.util.task.TaskMonitorAdapter; public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { @Test - public void testCategoryAddRemoveDTAdd() throws Exception { + public void testCategoryAddRemoveDTAdd() throws Exception { + + TypeDef td = new TypedefDataType("BF", IntegerDataType.dataType); + + AtomicReference structRef = new AtomicReference<>(); + mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { // Make no changes to Latest. } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { + boolean commit = false; DataTypeManager dtm = program.getDataTypeManager(); int transactionID = program.startTransaction("test"); Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); try { - c.removeCategory("Category5", TaskMonitorAdapter.DUMMY_MONITOR); - Category c5 = c.createCategory("Category5"); - Structure dt = new StructureDataType("Test", 0); - dt.add(new ByteDataType()); - dt.add(new WordDataType()); - dt = (Structure) c5.addDataType(dt, DataTypeConflictHandler.DEFAULT_HANDLER); - dt.add(new QWordDataType()); + Structure struct = + new StructureDataType("Test", 0, program.getDataTypeManager()); + struct.add(new ByteDataType()); + struct.add(new WordDataType()); + struct.insertBitFieldAt(3, 2, 6, td, 2, "bf1", null); + struct.insertBitFieldAt(3, 2, 4, td, 2, "bf2", null); + struct.add(new QWordDataType()); + + struct.setFlexibleArrayComponent(td, "flex", "my flex"); + + structRef.set(struct); + + c.removeCategory("Category5", TaskMonitorAdapter.DUMMY); + Category c5 = c.createCategory("Category5"); + c5.addDataType(struct, DataTypeConflictHandler.DEFAULT_HANDLER); commit = true; } - catch (InvalidNameException e) { - Assert.fail("got InvalidNameException!"); + catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); } finally { program.endTransaction(transactionID, commit); @@ -79,19 +91,19 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category5")); assertNotNull(c); - assertNotNull(c.getDataType("Test")); + DataType dt = c.getDataType("Test"); + assertNotNull(dt); + assertTrue(structRef.get().isEquivalent(dt)); } @Test - public void testDataTypeAddedInMy() throws Exception { + public void testDataTypeAddedInMy() throws Exception { // A category was added to Category5 in the latest; // in My program, rename Category5 to "My Category5" and add a new data type mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -111,9 +123,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -157,20 +166,19 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeAddedInMy2() throws Exception { + public void testDataTypeAddedInMy2() throws Exception { + + TypeDef td = new TypedefDataType("BF", IntegerDataType.dataType); + + AtomicReference structRef = new AtomicReference<>(); mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { // Make no changes to Latest. } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -179,15 +187,24 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3")); try { Structure s = (Structure) c.getDataType("IntStruct"); - c.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); - s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0); - s.add(new QWordDataType()); + c.remove(s, TaskMonitorAdapter.DUMMY); + s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0, dtm); + s.add(new QWordDataType(), "f1", "my f1"); s.add(new FloatDataType()); s.add(new ByteDataType()); + s.insertBitFieldAt(16, 2, 6, td, 2, "bf1", "my bf1"); + s.insertBitFieldAt(16, 2, 4, td, 2, "bf2", "my bf2"); s.add(new WordDataType()); + + structRef.set(s); + c.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER); commit = true; } + catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } finally { program.endTransaction(transactionID, commit); } @@ -199,30 +216,25 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3")); DataType dt = c.getDataType("IntStruct"); assertNotNull(dt); - assertTrue(dt instanceof Structure); - Structure s = (Structure) dt; - assertTrue(new QWordDataType().isEquivalent(s.getComponent(0).getDataType())); - assertTrue(new FloatDataType().isEquivalent(s.getComponent(1).getDataType())); - assertTrue(new ByteDataType().isEquivalent(s.getComponent(2).getDataType())); - assertTrue(new WordDataType().isEquivalent(s.getComponent(3).getDataType())); + assertTrue(structRef.get().isEquivalent(dt)); + Structure s = (Structure) dt; + assertEquals("my f1", s.getComponent(0).getComment()); + DataTypeComponent dtc = s.getComponentAt(17); + assertEquals(7, dtc.getOrdinal()); + assertEquals("my bf1", dtc.getComment()); } @Test - public void testDataTypeAddedInMy3() throws Exception { + public void testDataTypeAddedInMy3() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { // Make no changes to Latest. } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -231,7 +243,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { Category c = dtm.getCategory(new CategoryPath("/Category1/Category2/Category3")); try { Structure s = (Structure) c.getDataType("IntStruct"); - c.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + c.remove(s, TaskMonitorAdapter.DUMMY); s = new StructureDataType(c.getCategoryPath(), "IntStruct", 0); s.add(new QWordDataType()); s.add(new FloatDataType()); @@ -270,15 +282,13 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeAddedInLatest() throws Exception { + public void testDataTypeAddedInLatest() throws Exception { // Add A category to Category5 in the latest, add // add a new data type; // in My program, rename Category5 to "My Category5" mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -303,9 +313,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -341,14 +348,12 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeAddedInLatest2() throws Exception { + public void testDataTypeAddedInLatest2() throws Exception { // A category was added to Category5 in the latest; // in My program, rename Category5 to "My Category5" and add a new data type mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -372,9 +377,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -418,20 +420,15 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeDeletedInMy() throws Exception { + public void testDataTypeDeletedInMy() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { // Make no changes to Latest. } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -443,7 +440,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -461,20 +458,15 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeAddedDeletedInMy() throws Exception { + public void testDataTypeAddedDeletedInMy() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { // Make no changes to Latest. } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -487,7 +479,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { try { DataType dt = dtm.addDataType(s, DataTypeConflictHandler.DEFAULT_HANDLER); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -505,12 +497,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeDeletedChanged() throws Exception { + public void testDataTypeDeletedChanged() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -529,9 +519,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -543,7 +530,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -561,12 +548,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeDeletedChanged2() throws Exception { + public void testDataTypeDeletedChanged2() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -585,9 +570,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -599,7 +581,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "FloatStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -616,12 +598,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeDeletedChanged3() throws Exception { + public void testDataTypeDeletedChanged3() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -631,7 +611,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -639,9 +619,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -669,12 +646,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeDeletedInLatest() throws Exception { + public void testDataTypeDeletedInLatest() throws Exception { mtf.initialize("notepad2", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -684,7 +659,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -692,9 +667,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -728,12 +700,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeDeletedInBoth() throws Exception { + public void testDataTypeDeletedInBoth() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -745,7 +715,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -753,9 +723,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -767,7 +734,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -785,20 +752,15 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDataTypeRenamedInMy() throws Exception { + public void testDataTypeRenamedInMy() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { // Make no changes to Latest. } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -834,12 +796,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testRenamedBoth() throws Exception { + public void testRenamedBoth() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -865,9 +825,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -902,12 +859,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testRenamedBoth2() throws Exception { + public void testRenamedBoth2() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -933,9 +888,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -971,12 +923,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDeletedInMyRenamedInLatest() throws Exception { + public void testDeletedInMyRenamedInLatest() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -1002,9 +952,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -1016,7 +963,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1032,12 +979,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDeletedInLatestRenamedInMy() throws Exception { + public void testDeletedInLatestRenamedInMy() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -1047,7 +992,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { "IntStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1055,9 +1000,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -1090,12 +1032,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDeletedInLatestChangedInMy() throws Exception { + public void testDeletedInLatestChangedInMy() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -1110,7 +1050,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { Structure s = (Structure) dt; s.add(new ByteDataType()); Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2")); - parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY_MONITOR); + parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1118,9 +1058,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -1161,12 +1098,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testDeletedInLatestAddedInMy() throws Exception { + public void testDeletedInLatestAddedInMy() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -1181,7 +1116,7 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { Structure s = (Structure) dt; s.add(new ByteDataType()); Category parent = dtm.getCategory(new CategoryPath("/Category1/Category2")); - parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY_MONITOR); + parent.removeCategory("Category3", TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1189,9 +1124,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; @@ -1230,12 +1162,10 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } @Test - public void testCompositeCommentChanged() throws Exception { + public void testCompositeCommentChanged() throws Exception { mtf.initialize("notepad", new ProgramModifierListener() { - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyLatest(ghidra.program.database.ProgramDB) - */ + @Override public void modifyLatest(ProgramDB program) { boolean commit = false; @@ -1258,9 +1188,6 @@ public class DataTypeMerge1Test extends AbstractDataTypeMergeTest { } } - /* (non-Javadoc) - * @see ghidra.framework.data.ProgramModifierListener#modifyPrivate(ghidra.program.database.ProgramDB) - */ @Override public void modifyPrivate(ProgramDB program) { boolean commit = false; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java index e8ea873e49..fa41507f5e 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java @@ -21,11 +21,11 @@ import org.junit.Assert; import org.junit.Test; import docking.widgets.OptionDialog; -import ghidra.program.database.ProgramDB; -import ghidra.program.database.ProgramModifierListener; +import ghidra.program.database.*; import ghidra.program.model.data.*; import ghidra.program.model.data.Enum; import ghidra.util.exception.DuplicateNameException; +import ghidra.util.task.TaskMonitor; import ghidra.util.task.TaskMonitorAdapter; /** @@ -47,7 +47,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); // 2 components should get removed from CoolUnion commit = true; } @@ -119,7 +119,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); // 2 components should get removed from CoolUnion commit = true; } @@ -191,7 +191,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); // 2 components should get removed from CoolUnion commit = true; } @@ -296,10 +296,9 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { setErrorsExpected(true); - executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); + executeMerge(true); - waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); checkConflictCount(0); @@ -573,7 +572,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -646,7 +645,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); // causes Bar to be marked as changed commit = true; } @@ -720,7 +719,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); // causes Bar to be marked as changed commit = true; } @@ -796,7 +795,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { Structure ms = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "MyStruct"); try { - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); Structure s1 = new StructureDataType( new CategoryPath("/Category1/Category2/Category5"), "s1", 0); s1.add(ms); @@ -884,6 +883,196 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { assertEquals(3, dtcs.length); } + @Test + public void testConflictUpdate5() throws Exception { + + TypeDef td = new TypedefDataType(new CategoryPath("/Category1/Category2"), "BF", + IntegerDataType.dataType); + + mtf.initialize("notepad2", new OriginalProgramModifierListener() { + + @Override + public void modifyOriginal(ProgramDB program) throws Exception { + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + try { + dtm.addDataType(td, null); + } + finally { + program.endTransaction(transactionID, true); + } + } + + @Override + public void modifyLatest(ProgramDB program) { + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "BF"); + try { + dtm.remove(dt, TaskMonitorAdapter.DUMMY); + } + finally { + program.endTransaction(transactionID, true); + } + } + + @Override + public void modifyPrivate(ProgramDB program) { + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), + "Structure_1"); + Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); + try { + s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1"); + s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2"); + foo.add(new FloatDataType()); + } + catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } + finally { + program.endTransaction(transactionID, true); + } + } + }); + + // bitfield silently transitions to int since typedef BF was removed + + executeMerge(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + + Structure s1 = + (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); + assertNotNull(s1); + DataTypeComponent[] dtcs = s1.getComponents(); + assertEquals(7, dtcs.length); + + assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined + assertEquals("bf1", dtcs[3].getFieldName()); + assertEquals("my bf1", dtcs[3].getComment()); + + DataType dt = dtcs[3].getDataType(); + assertTrue(dt instanceof BitFieldDataType); + BitFieldDataType bfDt = (BitFieldDataType) dt; + assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType); + assertEquals(2, bfDt.getDeclaredBitSize()); + assertEquals(6, bfDt.getBitOffset()); + + assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined + assertEquals("bf2", dtcs[4].getFieldName()); + assertEquals("my bf2", dtcs[4].getComment()); + + dt = dtcs[4].getDataType(); + assertTrue(dt instanceof BitFieldDataType); + bfDt = (BitFieldDataType) dt; + assertTrue(bfDt.getBaseDataType() instanceof IntegerDataType); + assertEquals(2, bfDt.getDeclaredBitSize()); + assertEquals(4, bfDt.getBitOffset()); + + Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); + // Structure_1 should contain MY Foo + assertEquals(foo, dtcs[5].getDataType()); + + dtcs = foo.getComponents(); + assertEquals(5, dtcs.length); + assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType())); + checkConflictCount(0); + } + + @Test + public void testConflictUpdate6() throws Exception { + + TypeDef td = new TypedefDataType(new CategoryPath("/Category1/Category2"), "BF", + IntegerDataType.dataType); + + mtf.initialize("notepad2", new ProgramModifierListener() { + + @Override + public void modifyLatest(ProgramDB program) { + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + try { + // add new BF not compatible with BitFields + dtm.addDataType( + new StructureDataType(new CategoryPath("/Category1/Category2"), "BF", 0), + null); + } + finally { + program.endTransaction(transactionID, true); + } + } + + @Override + public void modifyPrivate(ProgramDB program) { + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + Structure s1 = (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), + "Structure_1"); + Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); + try { + s1.insertBitFieldAt(3, 2, 6, td, 2, "bf1", "my bf1"); + s1.insertBitFieldAt(3, 2, 4, td, 2, "bf2", "my bf2"); + foo.add(new FloatDataType()); + } + catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.toString()); + } + finally { + program.endTransaction(transactionID, true); + } + } + }); + + // bitfield silently transitions to BF.conflict since two different BF types were added + + executeMerge(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + + Structure s1 = + (Structure) dtm.getDataType(new CategoryPath("/Category1/Category2"), "Structure_1"); + assertNotNull(s1); + DataTypeComponent[] dtcs = s1.getComponents(); + assertEquals(7, dtcs.length); + + assertEquals(4, dtcs[3].getOffset()); // base on original 2-byte length 1st byte remains undefined + assertEquals("bf1", dtcs[3].getFieldName()); + assertEquals("my bf1", dtcs[3].getComment()); + + DataType dt = dtcs[3].getDataType(); + assertTrue(dt instanceof BitFieldDataType); + BitFieldDataType bfDt = (BitFieldDataType) dt; + DataType bdt = bfDt.getBaseDataType(); + assertEquals("/Category1/Category2/BF.conflict", bdt.getPathName()); + assertTrue(bdt.isEquivalent(td)); + assertEquals(2, bfDt.getDeclaredBitSize()); + assertEquals(6, bfDt.getBitOffset()); + + assertEquals(4, dtcs[4].getOffset()); // base on original 2-byte length 1st byte remains undefined + assertEquals("bf2", dtcs[4].getFieldName()); + assertEquals("my bf2", dtcs[4].getComment()); + + dt = dtcs[4].getDataType(); + assertTrue(dt instanceof BitFieldDataType); + bfDt = (BitFieldDataType) dt; + bdt = bfDt.getBaseDataType(); + assertEquals("/Category1/Category2/BF.conflict", bdt.getPathName()); + assertTrue(bdt.isEquivalent(td)); + assertEquals(2, bfDt.getDeclaredBitSize()); + assertEquals(4, bfDt.getBitOffset()); + + Structure foo = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Foo"); + // Structure_1 should contain MY Foo + assertEquals(foo, dtcs[5].getDataType()); + + dtcs = foo.getComponents(); + assertEquals(5, dtcs.length); + assertTrue(dtcs[4].getDataType().isEquivalent(new FloatDataType())); + checkConflictCount(1); + } + @Test public void testEditUnions() throws Exception { @@ -896,7 +1085,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); // 2 components should get removed from CoolUnion commit = true; } @@ -988,7 +1177,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); // 2 components should get removed from CoolUnion commit = true; } @@ -1070,10 +1259,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1157,10 +1346,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1245,10 +1434,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1332,10 +1521,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1425,10 +1614,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1526,10 +1715,10 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { try { Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); - dtm.remove(s, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(s, TaskMonitorAdapter.DUMMY); DataType dt = dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); - dtm.remove(dt, TaskMonitorAdapter.DUMMY_MONITOR); + dtm.remove(dt, TaskMonitorAdapter.DUMMY); commit = true; } finally { @@ -1624,4 +1813,109 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { checkConflictCount(0); } + @Test + public void testEditUnions9() throws Exception { + + mtf.initialize("notepad", new OriginalProgramModifierListener() { + + @Override + public void modifyOriginal(ProgramDB program) throws Exception { + boolean commit = false; + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + + try { + Enum enumm = new EnumDataType(new CategoryPath("/Category1"), "XYZ", 1); + enumm.add("one", 1); + enumm.add("two", 2); + enumm.add("three", 3); + dtm.addDataType( + new TypedefDataType(new CategoryPath("/Category1"), "TD_MyEnum", enumm), + null); + commit = true; + } + finally { + program.endTransaction(transactionID, commit); + } + } + + @Override + public void modifyLatest(ProgramDB program) { + boolean commit = false; + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + + try { + DataType enumm = dtm.getDataType(new CategoryPath("/Category1"), "XYZ"); + dtm.remove(enumm, TaskMonitor.DUMMY); + + Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), + "CoolUnion"); + // NOTE: bit field component byte sizing is currently auto-sized and packed within unions + union.insertBitField(1, IntegerDataType.dataType, 4, "bf1", "latest bf1"); + union.insertBitField(2, IntegerDataType.dataType, 2, "bf2", "latest bf2"); + commit = true; + } + catch (InvalidDataTypeException e) { + e.printStackTrace(); + Assert.fail(); + } + finally { + program.endTransaction(transactionID, commit); + } + } + + @Override + public void modifyPrivate(ProgramDB program) { + boolean commit = false; + DataTypeManager dtm = program.getDataTypeManager(); + int transactionID = program.startTransaction("test"); + + try { + DataType enumm = dtm.getDataType(new CategoryPath("/Category1"), "XYZ"); + assertTrue(enumm instanceof Enum); + + Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), + "CoolUnion"); + // NOTE: bit field component byte sizing is currently auto-sized and packed within unions + union.insertBitField(1, enumm, 4, "BF1", "my bf1"); + union.insertBitField(2, enumm, 2, "BF2", "my bf2"); + + commit = true; + } + catch (InvalidDataTypeException e) { + e.printStackTrace(); + Assert.fail(); + } + finally { + program.endTransaction(transactionID, commit); + } + } + }); + executeMerge(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + + chooseOption(DataTypeMergeManager.OPTION_MY);// MY bitfields w/ enum + + waitForCompletion(); + + // primitive type of byte used in absence of enum + Union union = + (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); + //@formatter:off + assertEquals("/Category1/Category2/CoolUnion\n" + + "Unaligned\n" + + "Union CoolUnion {\n" + + " 0 qword 8 null \"\"\n" + + " 0 byte:4(4) 1 BF1 \"my bf1\"\n" + + " 0 byte:2(6) 1 BF2 \"my bf2\"\n" + + " 0 word 2 null \"\"\n" + + " 0 undefined * * * * * 4 null \"\"\n" + + " 0 DLL_Table 96 null \"\"\n" + + " 0 DLL_Table * 4 null \"\"\n" + + "}\n" + + "Size = 96 Actual Alignment = 1\n", union.toString()); + //@formatter:on + } + } diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge8Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge8Test.java index 5ecce8cc6f..0747b8e996 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge8Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge8Test.java @@ -15,8 +15,7 @@ */ package ghidra.app.merge.datatypes; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import javax.swing.JLabel; @@ -37,7 +36,7 @@ import ghidra.util.task.TaskMonitorAdapter; public class DataTypeMerge8Test extends AbstractDataTypeMergeTest { @Test - public void testConflictFixUpForNonFittingStruct() throws Exception { + public void testConflictFixUpForNonFittingStruct() throws Exception { final CategoryPath miscPath = new CategoryPath("/MISC"); final CategoryPath rootPath = new CategoryPath("/"); @@ -163,7 +162,7 @@ public class DataTypeMerge8Test extends AbstractDataTypeMergeTest { JLabel label = (JLabel) TestUtils.getInstanceField("label", logPanel); String statusText = label.getText(); String expectedText = - "Merging Data Types: Not enough undefined bytes to fit /XYZ in structure " + + "Structure Merge: Not enough undefined bytes to fit /XYZ in structure " + "/MISC/ABC at offset 0x4.\nIt needs 3 more byte(s) to be able to fit."; assertTrue(statusText.contains(expectedText)); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java index 07be482c11..6661e444b7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/DataTypeComponentDB.java @@ -141,7 +141,7 @@ class DataTypeComponentDB implements InternalDataTypeComponent { } @Override - public DataType getParent() { + public Composite getParent() { return parent; } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java index 1938a75e14..8b70770bf3 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java @@ -25,6 +25,7 @@ import ghidra.program.model.data.*; import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult; import ghidra.program.model.mem.MemBuffer; import ghidra.util.Msg; +import ghidra.util.exception.AssertException; import ghidra.util.exception.InvalidInputException; /** @@ -640,6 +641,13 @@ class StructureDB extends CompositeDB implements Structure { } } + /** + * Create copy of structure for target dtm (source archive information is discarded). + * WARNING! copying unaligned structures which contain bitfields can produce + * invalid results when switching endianess due to the differences in packing order. + * @param dtm target data type manager + * @return cloned structure + */ @Override public DataType copy(DataTypeManager dtm) { StructureDataType struct = @@ -649,6 +657,13 @@ class StructureDB extends CompositeDB implements Structure { return struct; } + /** + * Create cloned structure for target dtm preserving source archive information. + * WARNING! cloning unaligned structures which contain bitfields can produce + * invalid results when switching endianess due to the differences in packing order. + * @param dtm target data type manager + * @return cloned structure + */ @Override public DataType clone(DataTypeManager dtm) { StructureDataType struct = @@ -891,12 +906,28 @@ class StructureDB extends CompositeDB implements Structure { @Override public DataTypeComponent insertAtOffset(int offset, DataType dataType, int length, String name, String comment) { + + if (offset < 0) { + throw new IllegalArgumentException("Offset cannot be negative."); + } + + if (dataType instanceof BitFieldDataType) { + BitFieldDataType bfDt = (BitFieldDataType) dataType; + if (length <= 0) { + length = dataType.getLength(); + } + try { + return insertBitFieldAt(offset, length, bfDt.getBitOffset(), bfDt.getBaseDataType(), + bfDt.getDeclaredBitSize(), name, comment); + } + catch (InvalidDataTypeException e) { + throw new AssertException(e); + } + } + lock.acquire(); try { checkDeleted(); - if (offset < 0) { - throw new IllegalArgumentException("Offset cannot be negative."); - } validateDataType(dataType); dataType = resolve(dataType); @@ -966,6 +997,10 @@ class StructureDB extends CompositeDB implements Structure { if (ordinal < 0 || ordinal >= numComponents) { throw new ArrayIndexOutOfBoundsException(ordinal); } + if (dataType instanceof BitFieldDataType) { + throw new IllegalArgumentException( + "Components may not be replaced with a bit-field"); + } validateDataType(dataType); DataTypeComponent origDtc = getComponent(ordinal); @@ -1085,19 +1120,14 @@ class StructureDB extends CompositeDB implements Structure { componentAdapter.removeRecord(dtc.getKey()); } components.clear(); + numComponents = 0; + structLength = 0; + if (flexibleArrayComponent != null) { flexibleArrayComponent.getDataType().removeParent(this); componentAdapter.removeRecord(flexibleArrayComponent.getKey()); flexibleArrayComponent = null; } - if (struct.isNotYetDefined()) { - numComponents = 0; - structLength = 0; - } - else { - structLength = struct.getLength(); - numComponents = isInternallyAligned() ? 0 : structLength; - } setAlignment(struct, false); @@ -1154,14 +1184,17 @@ class StructureDB extends CompositeDB implements Structure { private void doReplaceWithUnaligned(Structure struct) throws IOException { // assumes components is clear and that alignment characteristics have been set. + if (struct.isNotYetDefined()) { + return; + } - // NOTE: unaligned bitfields should remain unchanged when - // transitioning endianess even though it makes little sense. - // Unaligned structures are not intended to be portable! + structLength = struct.getLength(); + numComponents = structLength; DataTypeComponent[] otherComponents = struct.getDefinedComponents(); for (int i = 0; i < otherComponents.length; i++) { DataTypeComponent dtc = otherComponents[i]; + DataType dt = resolve(dtc.getDataType()); checkAncestry(dt); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java index a47d3402b7..0ac5e88cbc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Structure.java @@ -196,9 +196,8 @@ public interface Structure extends Composite { public void deleteAtOffset(int offset); /** - * Remove all components from this structure, effectively setting the - * length to zero. - * + * Remove all components from this structure (including flex-array), + * effectively setting the length to zero. */ public void deleteAll(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java index 848df1fca3..140a91ff3d 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java @@ -23,6 +23,7 @@ import ghidra.program.model.data.AlignedStructurePacker.StructurePackResult; import ghidra.program.model.mem.MemBuffer; import ghidra.util.Msg; import ghidra.util.UniversalID; +import ghidra.util.exception.AssertException; import ghidra.util.exception.InvalidInputException; /** @@ -292,9 +293,25 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur @Override public DataTypeComponentImpl insertAtOffset(int offset, DataType dataType, int length, String componentName, String comment) { + if (offset < 0) { throw new IllegalArgumentException("Offset cannot be negative."); } + + if (dataType instanceof BitFieldDataType) { + BitFieldDataType bfDt = (BitFieldDataType) dataType; + if (length <= 0) { + length = dataType.getLength(); + } + try { + return insertBitFieldAt(offset, length, bfDt.getBitOffset(), bfDt.getBaseDataType(), + bfDt.getDeclaredBitSize(), componentName, comment); + } + catch (InvalidDataTypeException e) { + throw new AssertException(e); + } + } + validateDataType(dataType); dataType = dataType.clone(dataMgr); @@ -519,7 +536,7 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur } @Override - public DataTypeComponent insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset, + public DataTypeComponentImpl insertBitFieldAt(int byteOffset, int byteWidth, int bitOffset, DataType baseDataType, int bitSize, String componentName, String comment) throws InvalidDataTypeException { @@ -842,6 +859,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur return available; } + /** + * Create copy of structure for target dtm (source archive information is discarded). + * WARNING! copying unaligned structures which contain bitfields can produce + * invalid results when switching endianess due to the differences in packing order. + * @param dtm target data type manager + * @return cloned structure + */ @Override public DataType copy(DataTypeManager dtm) { StructureDataType struct = new StructureDataType(categoryPath, getName(), getLength(), dtm); @@ -850,6 +874,13 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur return struct; } + /** + * Create cloned structure for target dtm preserving source archive information. + * WARNING! cloning unaligned structures which contain bitfields can produce + * invalid results when switching endianess due to the differences in packing order. + * @param dtm target data type manager + * @return cloned structure + */ @Override public DataType clone(DataTypeManager dtm) { if (dataMgr == dtm) { @@ -902,15 +933,9 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur int oldLength = structLength; components.clear(); + structLength = 0; + numComponents = 0; flexibleArrayComponent = null; - if (struct.isNotYetDefined()) { - structLength = 0; - numComponents = 0; - } - else { - structLength = struct.getLength(); - numComponents = isInternallyAligned() ? 0 : structLength; - } setAlignment(struct); @@ -945,14 +970,17 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur private void doReplaceWithUnaligned(Structure struct) { // assumes components is clear and that alignment characteristics have been set. + if (struct.isNotYetDefined()) { + return; + } - // NOTE: unaligned bitfields should remain unchanged when - // transitioning endianess even though it makes little sense. - // Unaligned structures are not intended to be portable! + structLength = struct.getLength(); + numComponents = structLength; DataTypeComponent[] otherComponents = struct.getDefinedComponents(); for (int i = 0; i < otherComponents.length; i++) { DataTypeComponent dtc = otherComponents[i]; + DataType dt = dtc.getDataType().clone(dataMgr); checkAncestry(dt); From 4973b0bd99542eb83fb578ae7c8ce96af18c7a12 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 3 Feb 2020 14:15:01 -0500 Subject: [PATCH 10/36] GT-3519 corrected structure editor save button enablement when editing bitfields --- .../app/plugin/core/compositeeditor/CompositeEditorPanel.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java index a928905f67..4c0ae6ab43 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/CompositeEditorPanel.java @@ -162,8 +162,7 @@ public abstract class CompositeEditorPanel extends JPanel BitFieldEditorDialog dlg = new BitFieldEditorDialog(model.viewComposite, provider.dtmService, editingRow, ordinal -> { - model.fireTableDataChanged(); - model.compositeInfoChanged(); + model.notifyCompositeChanged(); }); Component c = provider.getComponent(); Window w = SwingUtilities.windowForComponent(c); From d73c362790cdb4b2bb62a773ede0ba0c698d2107 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 29 Jan 2020 13:01:06 -0500 Subject: [PATCH 11/36] GT-3511 revised fix for branch to self with invalid delay slot --- .../main/java/ghidra/program/disassemble/Disassembler.java | 4 ++-- .../java/ghidra/program/disassemble/DisassemblerQueue.java | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java index 9e28359eb3..d19e5e70a7 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/Disassembler.java @@ -1150,12 +1150,12 @@ public class Disassembler implements DisassemblerConflictHandler { throws InsufficientBytesException, UnknownInstructionException, AddressOverflowException, NestedDelaySlotException { + List delaySlotList = parseDelaySlots(inst, blockMemBuffer, block); + if (followFlow) { processInstructionFlows(inst, block); } - List delaySlotList = parseDelaySlots(inst, blockMemBuffer, block); - block.addInstruction(inst); if (delaySlotList != null) { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java index 2159d7313e..779690348c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/disassemble/DisassemblerQueue.java @@ -174,9 +174,6 @@ class DisassemblerQueue { branchFlow = currentBranchQueue.first(); currentBranchQueue.remove(branchFlow); } - if (processedBranchFlows.contains(branchFlow)) { - continue; - } processedBranchFlows.add(branchFlow); Address blockAddr = branchFlow.getDestinationAddress(); From 4f73af4c92398c5842d33da8d01c4459567ffe94 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 3 Feb 2020 16:42:35 -0500 Subject: [PATCH 12/36] Correct divide-by-zero test issue --- .../core/equate/AbstractConvertAction.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java index 776a4c35ba..0c09879c3c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java @@ -42,10 +42,6 @@ public abstract class AbstractConvertAction extends ListingContextAction { this.isSigned = isSigned; setPopupMenuData(new MenuData(new String[] { "Convert", "" }, "Convert")); setEnabled(true); - JMenuItem item = new JMenuItem(); - Font font = item.getFont(); - metrics = plugin.getTool().getActiveWindow().getFontMetrics(font); - } @Override @@ -132,14 +128,28 @@ public abstract class AbstractConvertAction extends ListingContextAction { return isSigned; } + private int stringWidth(String s) { + if (metrics == null) { + JMenuItem item = new JMenuItem(); + Font font = item.getFont(); + metrics = plugin.getTool().getActiveWindow().getFontMetrics(font); + } + int w = metrics.stringWidth(s); + if (w == 0) { + // use default computation if metrics report 0 + return 10 * s.length(); + } + return w; + } + String getStandardLengthString(String baseString) { - int baseWidth = metrics.stringWidth(baseString); - int spaceWidth = metrics.stringWidth(" "); + int baseWidth = stringWidth(baseString); + int spaceWidth = stringWidth(" "); int paddingSize = (140 - baseWidth) / spaceWidth; if (paddingSize <= 0) { return baseString; } - StringBuffer buf = new StringBuffer(baseString); + StringBuilder buf = new StringBuilder(baseString); for (int i = 0; i < paddingSize; i++) { buf.append(" "); } From 15468c7b1a92d8f1daf4e5af53d66aff9611da14 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 3 Feb 2020 16:52:12 -0500 Subject: [PATCH 13/36] Corrected ProgramExaminer NPE --- .../ghidra/app/util/importer/LcsHintLoadSpecChooser.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/LcsHintLoadSpecChooser.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/LcsHintLoadSpecChooser.java index d773088664..7019dc5d39 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/LcsHintLoadSpecChooser.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/LcsHintLoadSpecChooser.java @@ -37,16 +37,18 @@ public class LcsHintLoadSpecChooser implements LoadSpecChooser { * {@link CompilerSpec}. * * @param language The {@link Language} to use (should not be null) - * @param compilerSpec The {@link CompilerSpec} to use (should not be null) + * @param compilerSpec The {@link CompilerSpec} to use (f null default compiler spec will be used) */ public LcsHintLoadSpecChooser(Language language, CompilerSpec compilerSpec) { this.languageID = language.getLanguageID(); - this.compilerSpecID = compilerSpec.getCompilerSpecID(); + this.compilerSpecID = + (compilerSpec == null) ? language.getDefaultCompilerSpec().getCompilerSpecID() + : compilerSpec.getCompilerSpecID(); } @Override public LoadSpec choose(LoaderMap loaderMap) { - + // Use the highest priority loader (it will be the first one) Loader loader = loaderMap.keySet().stream().findFirst().orElse(null); if (loader == null) { From 46d267309daa8875c4f02266d16236335d691888 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 4 Feb 2020 12:12:22 -0500 Subject: [PATCH 14/36] Corrected stack frame editor test issues and default favorite action enablement --- .../core/compositeeditor/FavoritesAction.java | 5 ++-- .../core/stackeditor/StackEditorModel.java | 23 ++++++++++--------- .../stackeditor/StackEditorActions4Test.java | 2 +- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java index a4d4f24c7b..c686e0b2b4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/compositeeditor/FavoritesAction.java @@ -60,7 +60,8 @@ public class FavoritesAction extends CompositeEditorTableAction { @Override public void adjustEnablement() { - // Do nothing since we always want it enabled so the user gets a "doesn't fit" message. + // we always want it enabled so the user gets a "doesn't fit" message. + setEnabled(true); } @Override @@ -75,6 +76,6 @@ public class FavoritesAction extends CompositeEditorTableAction { @Override public boolean isAddToPopup(ActionContext context) { - return super.isEnabledForContext(context); + return isEnabledForContext(context); } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java index 1cd7b7f990..d4417e963d 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/stackeditor/StackEditorModel.java @@ -633,17 +633,18 @@ class StackEditorModel extends CompositeEditorModel { newLength = compDt.getLength(); } int offset = comp.getOffset(); - if (((StackFrameDataType) viewComposite).growsNegative()) { - if (offset >= 0 && offset < getParameterOffset()) { - return false; - } - } - else { - if (offset < 0 && offset > getParameterOffset()) { - return false; - } - - } +// TODO: not sure we need to prevent creating local variables in 'save' area, +// since doing so just leads to confusion when using stack frame editor +// if (((StackFrameDataType) viewComposite).growsNegative()) { +// if (offset >= 0 && offset < getParameterOffset()) { +// return false; +// } +// } +// else { +// if (offset < 0 && offset > getParameterOffset()) { +// return false; +// } +// } int maxBytes = ((StackFrameDataType) viewComposite).getMaxLength(offset); if (newLength > maxBytes) { return false; diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorActions4Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorActions4Test.java index 4475ebd414..a695cb8d14 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorActions4Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/stackeditor/StackEditorActions4Test.java @@ -315,7 +315,7 @@ public class StackEditorActions4Test extends AbstractStackEditorTest { assertEquals(0xa, getOffset(model.getNumComponents() - 1)); FavoritesAction fav = getFavorite("word"); - assertTrue(fav.isEnabled()); + assertTrue(fav.isEnabledForContext(null)); // context not utilized assertEquals("", model.getStatus()); invoke(fav); assertEquals("", model.getStatus()); From 5b1d6217b34fd592f5787c1a3925221f740ed8e5 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 4 Feb 2020 12:47:46 -0500 Subject: [PATCH 15/36] Corrected improper scalar reference markup for negative values --- .../main/java/ghidra/program/model/listing/CodeUnitFormat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 1d23a6e51d..2bf413cddd 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 @@ -802,7 +802,7 @@ public class CodeUnitFormat { long originalValue = (addr.isStackAddress() && originalScalar.bitLength() == addr.getAddressSpace().getSize()) ? originalScalar.getSignedValue() - : originalScalar.getValue(); + : originalScalar.getUnsignedValue(); long addrOffset; if (addr instanceof SegmentedAddress) { addrOffset = ((SegmentedAddress) addr).getSegmentOffset(); From 06a88e0c634bd38514fbf4711581d08f9113c9a1 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 4 Feb 2020 13:28:19 -0500 Subject: [PATCH 16/36] Tests - fixed test failing due to recent Decompiler changes --- .../extension/datatype/finder/DecompilerVariable.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java index e20b59157d..576b92fd30 100644 --- a/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java +++ b/Ghidra/Features/DecompilerDependent/src/main/java/ghidra/app/extension/datatype/finder/DecompilerVariable.java @@ -63,6 +63,16 @@ public abstract class DecompilerVariable { return dataType; } + // The parent variable declaration node has the type + ClangNode parent = variable.Parent(); + if (parent instanceof ClangVariableDecl) { + ClangVariableDecl decl = (ClangVariableDecl) parent; + dataType = decl.getDataType(); + if (dataType != null) { + return dataType; + } + } + // Prefer the type of the first input varnode, unless that type is a 'void *'. // Usually, in that special case, the output varnode has the correct type information. PcodeOp op = variable.getPcodeOp(); From 61af96034ed885a24d62796c085d5d50b02c779a Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Tue, 4 Feb 2020 14:28:13 -0500 Subject: [PATCH 17/36] Tests - fixed timing issue; fixed Swing thread access issue --- .../core/bookmark/BookmarkPluginTest.java | 6 +- .../functioncompare/CompareFunctionsTest.java | 183 ++++++++---------- .../decompile/DecompilerNavigationTest.java | 12 ++ .../filechooser/GhidraFileChooserTest.java | 9 +- 4 files changed, 105 insertions(+), 105 deletions(-) diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/bookmark/BookmarkPluginTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/bookmark/BookmarkPluginTest.java index 1bba776d67..345b83e15a 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/bookmark/BookmarkPluginTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/plugin/core/bookmark/BookmarkPluginTest.java @@ -477,12 +477,8 @@ public class BookmarkPluginTest extends AbstractGhidraHeadedIntegrationTest { waitForTable(); selectAllTableRows(); - runSwing(() -> provider.delete()); - - waitForTable(); - - assertEquals(0, table.getRowCount()); + waitForCondition(() -> table.getRowCount() == 0, "Bookmarks not deleted"); } @Test diff --git a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/functioncompare/CompareFunctionsTest.java b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/functioncompare/CompareFunctionsTest.java index e52fc02f12..4e77e8ad6f 100644 --- a/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/functioncompare/CompareFunctionsTest.java +++ b/Ghidra/Features/Base/src/test/java/ghidra/app/plugin/core/functioncompare/CompareFunctionsTest.java @@ -15,8 +15,7 @@ */ package ghidra.app.plugin.core.functioncompare; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.util.Date; import java.util.Set; @@ -57,7 +56,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { private Function five; private FunctionComparisonPlugin plugin; private FunctionComparisonProvider provider; - private FunctionComparisonProvider provider0; + private FunctionComparisonProvider provider2; private FunctionComparisonModel model; @Before @@ -70,23 +69,17 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { model = createTestModel(); } - /** - * - * Tests for {@link FunctionComparisonService#compareFunctions(Set)} - * - */ - @Test public void testSetNoFunctions() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(); - FunctionComparisonProvider provider = plugin.compareFunctions(functions); + provider = compare(functions); assertNull(provider); } @Test public void testSetOneFunction() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo); - provider = plugin.compareFunctions(functions); + provider = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo); } @@ -94,23 +87,23 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testSetDuplicateFunctionDifferentProviders() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo); - provider = plugin.compareFunctions(functions); + provider = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo); - provider0 = plugin.compareFunctions(functions); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, foo, foo); + provider2 = compare(functions); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, foo, foo); } @Test public void testSetDuplicateFunctionSameProvider() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo); - provider = plugin.compareFunctions(functions); + provider = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo); - plugin.compareFunctions(functions, provider); + compare(functions, provider); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo); } @@ -118,7 +111,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testSetMultipleFunctions() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, junk, stuff); - provider = plugin.compareFunctions(functions); + provider = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, junk, stuff); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, junk, stuff); CompareFunctionsTestUtility.checkTargetFunctions(provider, junk, foo, junk, stuff); @@ -130,16 +123,16 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { Set functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(one, two); Set functions2 = CompareFunctionsTestUtility.getFunctionsAsSet(three, four, five); - provider = plugin.compareFunctions(functions1); - provider0 = plugin.compareFunctions(functions2); + provider = compare(functions1); + provider2 = compare(functions2); CompareFunctionsTestUtility.checkSourceFunctions(provider, one, two); CompareFunctionsTestUtility.checkTargetFunctions(provider, one, one, two); CompareFunctionsTestUtility.checkTargetFunctions(provider, two, one, two); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, three, four, five); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, three, three, four, five); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, four, three, four, five); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, five, three, four, five); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, three, four, five); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, three, three, four, five); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, four, three, four, five); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, five, three, four, five); } @Test @@ -147,8 +140,8 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { Set functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(foo, two); Set functions2 = CompareFunctionsTestUtility.getFunctionsAsSet(bar, three, four); - provider = plugin.compareFunctions(functions1); - plugin.compareFunctions(functions2, provider); + provider = compare(functions1); + compare(functions2, provider); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, two, bar, three, four); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, two, bar, three, four); @@ -160,47 +153,35 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { four); } - /** - * - * Tests for {@link FunctionComparisonService#compareFunctions(Set, FunctionComparisonProvider)} - * - */ - @Test public void testSetAddToSpecificProvider() throws Exception { Set functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(foo, two); Set functions2 = CompareFunctionsTestUtility.getFunctionsAsSet(bar, three); Set functions3 = CompareFunctionsTestUtility.getFunctionsAsSet(four); - provider = plugin.compareFunctions(functions1); - provider0 = plugin.compareFunctions(functions2); + provider = compare(functions1); + provider2 = compare(functions2); - plugin.compareFunctions(functions3, provider0); + compare(functions3, provider2); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, two); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, bar, three, four); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, bar, three, four); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, two); CompareFunctionsTestUtility.checkTargetFunctions(provider, two, foo, two); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, bar, bar, three, four); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, three, bar, three, four); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, four, bar, three, four); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, bar, bar, three, four); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, three, bar, three, four); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, four, bar, three, four); } - /** - * - * Tests for {@link FunctionComparisonService#removeFunction(Function)} - * - */ - @Test public void testRemoveFunction() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar); - provider = plugin.compareFunctions(functions); + provider = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar); - plugin.removeFunction(foo); + remove(foo); CompareFunctionsTestUtility.checkSourceFunctions(provider, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, bar); @@ -209,15 +190,17 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunctionTargetOnly() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar); - provider = plugin.compareFunctions(functions); - plugin.compareFunctions(foo, two, provider); // add a target to foo, which is not also a source + provider = compare(functions); + + // add a target to foo, which is not also a source + runSwing(() -> plugin.compareFunctions(foo, two, provider)); // Verify the structure with the new target CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar, two); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar); - plugin.removeFunction(two); + remove(two); // Verify the new target is gone CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); @@ -228,85 +211,67 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testRemoveFunctionMultipleProviders() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar); - provider = plugin.compareFunctions(functions); - provider0 = plugin.compareFunctions(functions); + provider = compare(functions); + provider2 = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo, bar); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo, bar); - plugin.removeFunction(foo); + remove(foo); CompareFunctionsTestUtility.checkSourceFunctions(provider, bar); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, bar); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, bar); } @Test public void testRemoveNonexistentFunction() throws Exception { Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar); - provider = plugin.compareFunctions(functions); + provider = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar); - plugin.removeFunction(two); // nothing should happen + remove(two); // nothing should happen CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar); } - /** - * - * Tests for {@link FunctionComparisonService#removeFunction(Function, FunctionComparisonProvider)} - * - */ - @Test public void testRemoveFunctionFromSpecificProvider() throws Exception { - Set functions1 = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar); - provider = plugin.compareFunctions(functions1); - provider0 = plugin.compareFunctions(functions1); + Set functions = CompareFunctionsTestUtility.getFunctionsAsSet(foo, bar); + provider = compare(functions); + provider2 = compare(functions); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, foo, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, foo, bar); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo, bar); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, foo, foo, bar); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, bar, foo, bar); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo, bar); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, foo, foo, bar); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, bar, foo, bar); - plugin.removeFunction(foo, provider); + remove(foo, provider); CompareFunctionsTestUtility.checkSourceFunctions(provider, bar); CompareFunctionsTestUtility.checkTargetFunctions(provider, bar, bar); - CompareFunctionsTestUtility.checkSourceFunctions(provider0, foo, bar); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, foo, foo, bar); - CompareFunctionsTestUtility.checkTargetFunctions(provider0, bar, foo, bar); + CompareFunctionsTestUtility.checkSourceFunctions(provider2, foo, bar); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, foo, foo, bar); + CompareFunctionsTestUtility.checkTargetFunctions(provider2, bar, foo, bar); } - /** - * - * Tests for {@link FunctionComparisonService#compareFunctions(Function, Function)} - * - */ - @Test public void testDualCompare() { - provider = plugin.compareFunctions(foo, bar); + provider = compare(foo, bar); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, bar); } - /** - * - * Tests for {@link FunctionComparisonService#compareFunctions(Function, Function, FunctionComparisonProvider)} - * - */ - @Test public void testDualCompareAddToExisting() { - provider = plugin.compareFunctions(foo, bar); - plugin.compareFunctions(foo, two, provider); + provider = compare(foo, bar); + runSwing(() -> plugin.compareFunctions(foo, two, provider)); CompareFunctionsTestUtility.checkSourceFunctions(provider, foo); CompareFunctionsTestUtility.checkTargetFunctions(provider, foo, bar, two); @@ -321,7 +286,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testGetTargets() { Set targets = model.getTargetFunctions(); - assertTrue(targets.size() == 6); + assertEquals(6, targets.size()); assertTrue(targets.contains(bar)); assertTrue(targets.contains(two)); assertTrue(targets.contains(three)); @@ -333,7 +298,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void testGetTargetsForSource() { Set targets = model.getTargetFunctions(bar); - assertTrue(targets.size() == 3); + assertEquals(3, targets.size()); assertTrue(targets.contains(three)); assertTrue(targets.contains(four)); assertTrue(targets.contains(five)); @@ -342,7 +307,7 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { @Test public void getSources() { Set sources = model.getSourceFunctions(); - assertTrue(sources.size() == 3); + assertEquals(3, sources.size()); assertTrue(sources.contains(foo)); assertTrue(sources.contains(bar)); assertTrue(sources.contains(junk)); @@ -353,19 +318,39 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { model.removeFunction(bar); Set sources = model.getSourceFunctions(); - assertTrue(sources.size() == 2); + assertEquals(2, sources.size()); assertTrue(sources.contains(foo)); assertTrue(sources.contains(junk)); Set targets = model.getTargetFunctions(foo); - assertTrue(targets.size() == 1); + assertEquals(1, targets.size()); assertTrue(targets.contains(two)); targets = model.getTargetFunctions(junk); - assertTrue(targets.size() == 1); + assertEquals(1, targets.size()); assertTrue(targets.contains(stuff)); } + private void remove(Function f) { + runSwing(() -> plugin.removeFunction(f)); + } + + private void remove(Function f, FunctionComparisonProvider fp) { + runSwing(() -> plugin.removeFunction(f, fp)); + } + + private void compare(Set functions, FunctionComparisonProvider fp) { + runSwing(() -> plugin.compareFunctions(functions, fp)); + } + + private FunctionComparisonProvider compare(Set functions) { + return runSwing(() -> plugin.compareFunctions(functions)); + } + + private FunctionComparisonProvider compare(Function f1, Function f2) { + return runSwing(() -> plugin.compareFunctions(f1, f2)); + } + private ProgramBuilder buildTestProgram1() throws Exception { ProgramBuilder builder = new ProgramBuilder("TestPgm1", ProgramBuilder._TOY_BE); builder.createMemory(".text", "0x1001000", 0x6600); @@ -404,26 +389,26 @@ public class CompareFunctionsTest extends AbstractGhidraHeadedIntegrationTest { } private FunctionComparisonModel createTestModel() { - FunctionComparisonModel model = new FunctionComparisonModel(); + FunctionComparisonModel newModel = new FunctionComparisonModel(); FunctionComparison c1 = new FunctionComparison(); c1.setSource(foo); c1.addTarget(bar); c1.addTarget(two); - model.addComparison(c1); + newModel.addComparison(c1); FunctionComparison c2 = new FunctionComparison(); c2.setSource(bar); c2.addTarget(three); c2.addTarget(four); c2.addTarget(five); - model.addComparison(c2); + newModel.addComparison(c2); FunctionComparison c3 = new FunctionComparison(); c3.setSource(junk); c3.addTarget(stuff); - model.addComparison(c3); + newModel.addComparison(c3); - return model; + return newModel; } } diff --git a/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/DecompilerNavigationTest.java b/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/DecompilerNavigationTest.java index 5e2ebfba7a..2f5ee8d530 100644 --- a/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/DecompilerNavigationTest.java +++ b/Ghidra/Features/Decompiler/src/test.slow/java/ghidra/app/plugin/core/decompile/DecompilerNavigationTest.java @@ -228,6 +228,18 @@ public class DecompilerNavigationTest extends AbstractDecompilerTest { "The Listing is not at the expected address"); } + @Override + public void assertCurrentAddress(Address expected) { + codeBrowser.updateNow(); + waitForSwing(); + + waitForCondition(() -> { + ProgramLocation loc = codeBrowser.getCurrentLocation(); + Address actual = loc.getAddress(); + return expected.equals(actual); + }, "Listing is not at the expected address"); + } + private void assertExternalNavigationPerformed() { // going to the 'external linkage' means we went to the thunk function and not the // external program diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java index a1158054c7..4ce3cfa3eb 100644 --- a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java +++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java @@ -1752,9 +1752,11 @@ public class GhidraFileChooserTest extends AbstractDockingTest { pressUp(); selectFile(getListView(), 1); + assertSelectedIndex(getListView(), 1); pressUp(); selectFile(getListView(), 2); + assertSelectedIndex(getListView(), 2); pressBack(); assertSelectedIndex(getListView(), 1); @@ -1914,7 +1916,12 @@ public class GhidraFileChooserTest extends AbstractDockingTest { private void assertSelectedIndex(DirectoryList list, int expected) { int actual = runSwing(() -> list.getSelectedIndex()); - assertEquals("Wrong list index selected", expected, actual); + + // debug code + if (expected != actual) { + waitForCondition(() -> expected == actual, + "Wrong list index selected "); + } } private void assertSelectedIndex(GTable table, int expected) { From 30da09cce2eba36468e9b4c315fbd9256fddba1b Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 4 Feb 2020 12:47:46 -0500 Subject: [PATCH 18/36] Corrected improper scalar reference markup for negative values --- .../main/java/ghidra/program/model/listing/CodeUnitFormat.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 a091bb3d66..b6536cd3f5 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 @@ -802,7 +802,7 @@ public class CodeUnitFormat { long originalValue = (addr.isStackAddress() && originalScalar.bitLength() == addr.getAddressSpace().getSize()) ? originalScalar.getSignedValue() - : originalScalar.getValue(); + : originalScalar.getUnsignedValue(); long addrOffset; if (addr instanceof SegmentedAddress) { addrOffset = ((SegmentedAddress) addr).getSegmentOffset(); From 4342b5b9a9178ff2219e9d6d857465485184ee64 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Wed, 5 Feb 2020 11:37:08 -0500 Subject: [PATCH 19/36] GT-3521 fix problem with "Method is not Remote" when connecting A recent change in java's RemoteObjectInvocationHandler added an additional check to ensure that the interface a method was declared on was also marked with the Remote marker interface. Previously the check was looser and only checked if the entire proxied object implemented Remote. The change was made in commit be35f9ef53774a87662ad7a0bb978986ea56ca78: https://github.com/openjdk/jdk/commit/be35f9ef53774a87662ad7a0bb978986ea56ca78 The error the user would encounter would say something about "Method is not Remote" and something about "RepositoryServerHandle.isReadOnly()". --- .../db/buffers/RemoteBufferFileHandle.java | 63 ++++++++++- .../RemoteManagedBufferFileHandle.java | 104 ++++++++++++++++- .../remote/RemoteRepositoryHandle.java | 106 ++++++++++++++++++ .../remote/RemoteRepositoryServerHandle.java | 39 +++++++ 4 files changed, 310 insertions(+), 2 deletions(-) diff --git a/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteBufferFileHandle.java b/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteBufferFileHandle.java index 8d9dbe624f..3e0b840029 100644 --- a/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteBufferFileHandle.java +++ b/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteBufferFileHandle.java @@ -15,12 +15,73 @@ */ package db.buffers; +import java.io.IOException; import java.rmi.Remote; +import java.util.NoSuchElementException; /** * RemoteBufferFileHandle facilitates access to a remote BufferFile * via RMI. + *

+ * Methods from {@link BufferFileHandle} must be re-declared here to mark them as rmi-able. */ public interface RemoteBufferFileHandle extends BufferFileHandle, Remote { - // provides combined interface + @Override + public boolean isReadOnly() throws IOException; + + @Override + public boolean setReadOnly() throws IOException; + + @Override + public int getParameter(String name) throws NoSuchElementException, IOException; + + @Override + public void setParameter(String name, int value) throws IOException; + + @Override + public void clearParameters() throws IOException; + + @Override + public String[] getParameterNames() throws IOException; + + @Override + public int getBufferSize() throws IOException; + + @Override + public int getIndexCount() throws IOException; + + @Override + public int[] getFreeIndexes() throws IOException; + + @Override + public void setFreeIndexes(int[] indexes) throws IOException; + + @Override + public void close() throws IOException; + + @Override + public boolean delete() throws IOException; + + @Override + public DataBuffer get(int index) throws IOException; + + @Override + public void put(DataBuffer buf, int index) throws IOException; + + @Override + public void dispose() throws IOException; + + @Override + public InputBlockStream getInputBlockStream() throws IOException; + + @Override + public OutputBlockStream getOutputBlockStream(int blockCount) throws IOException; + + @Override + public BlockStreamHandle getInputBlockStreamHandle() throws IOException; + + @Override + public BlockStreamHandle getOutputBlockStreamHandle(int blockCount) + throws IOException; + } diff --git a/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteManagedBufferFileHandle.java b/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteManagedBufferFileHandle.java index 11860c07c9..edbd377bae 100644 --- a/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteManagedBufferFileHandle.java +++ b/Ghidra/Framework/DB/src/main/java/db/buffers/RemoteManagedBufferFileHandle.java @@ -15,12 +15,114 @@ */ package db.buffers; +import java.io.IOException; import java.rmi.Remote; +import java.util.NoSuchElementException; /** * RemoteManagedBufferFileHandle facilitates access to a ManagedBufferFile * via RMI. + *

+ * Methods from {@link BufferFileHandle} and {@link ManagedBufferFile} must be re-declared + * here to mark them as rmi-able. + * */ public interface RemoteManagedBufferFileHandle extends ManagedBufferFileHandle, Remote { - // provides combined interface + + //-------------------------------------------------------------------------- + // BufferFileHandle methods + //-------------------------------------------------------------------------- + @Override + public boolean isReadOnly() throws IOException; + + @Override + public boolean setReadOnly() throws IOException; + + @Override + public int getParameter(String name) throws NoSuchElementException, IOException; + + @Override + public void setParameter(String name, int value) throws IOException; + + @Override + public void clearParameters() throws IOException; + + @Override + public String[] getParameterNames() throws IOException; + + @Override + public int getBufferSize() throws IOException; + + @Override + public int getIndexCount() throws IOException; + + @Override + public int[] getFreeIndexes() throws IOException; + + @Override + public void setFreeIndexes(int[] indexes) throws IOException; + + @Override + public void close() throws IOException; + + @Override + public boolean delete() throws IOException; + + @Override + public DataBuffer get(int index) throws IOException; + + @Override + public void put(DataBuffer buf, int index) throws IOException; + + @Override + public void dispose() throws IOException; + + @Override + public InputBlockStream getInputBlockStream() throws IOException; + + @Override + public OutputBlockStream getOutputBlockStream(int blockCount) throws IOException; + + @Override + public BlockStreamHandle getInputBlockStreamHandle() throws IOException; + + @Override + public BlockStreamHandle getOutputBlockStreamHandle(int blockCount) + throws IOException; + + //-------------------------------------------------------------------------- + // ManagedBufferFileHandle methods + //-------------------------------------------------------------------------- + + @Override + public ManagedBufferFileHandle getSaveFile() throws IOException; + + @Override + public void saveCompleted(boolean commit) throws IOException; + + @Override + public boolean canSave() throws IOException; + + @Override + public void setVersionComment(String comment) throws IOException; + + @Override + public BufferFileHandle getNextChangeDataFile(boolean getFirst) throws IOException; + + @Override + public BufferFileHandle getSaveChangeDataFile() throws IOException; + + @Override + public long getCheckinID() throws IOException; + + @Override + public byte[] getForwardModMapData(int oldVersion) throws IOException; + + @Override + public InputBlockStream getInputBlockStream(byte[] changeMapData) throws IOException; + + @Override + public BlockStreamHandle getInputBlockStreamHandle(byte[] changeMapData) + throws IOException; + } diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryHandle.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryHandle.java index c7ff89ddba..8c4938a35c 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryHandle.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryHandle.java @@ -15,11 +15,117 @@ */ package ghidra.framework.remote; +import java.io.IOException; import java.rmi.Remote; +import db.buffers.ManagedBufferFileHandle; +import ghidra.framework.store.*; +import ghidra.util.InvalidNameException; + /** * RepositoryHandle provides access to a remote repository via RMI. + *

+ * Methods from {@link RepositoryHandle} must be re-declared here to mark them as rmi-able. */ public interface RemoteRepositoryHandle extends RepositoryHandle, Remote { + @Override + String getName() throws IOException; + + @Override + User getUser() throws IOException; + + @Override + User[] getUserList() throws IOException; + + @Override + boolean anonymousAccessAllowed() throws IOException; + + @Override + String[] getServerUserList() throws IOException; + + @Override + void setUserList(User[] users, boolean anonymousAccessAllowed) throws IOException; + + @Override + String[] getSubfolderList(String folderPath) throws IOException; + + @Override + int getItemCount() throws IOException; + + @Override + RepositoryItem[] getItemList(String folderPath) throws IOException; + + @Override + RepositoryItem getItem(String parentPath, String name) throws IOException; + + @Override + RepositoryItem getItem(String fileID) throws IOException; + + @Override + ManagedBufferFileHandle createDatabase(String parentPath, String itemName, String fileID, + int bufferSize, String contentType, String projectPath) + throws IOException, InvalidNameException; + + @Override + ManagedBufferFileHandle openDatabase(String parentPath, String itemName, int version, + int minChangeDataVer) throws IOException; + + @Override + ManagedBufferFileHandle openDatabase(String parentPath, String itemName, long checkoutId) + throws IOException; + + @Override + Version[] getVersions(String parentPath, String itemName) throws IOException; + + @Override + void deleteItem(String parentPath, String itemName, int version) throws IOException; + + @Override + void moveFolder(String oldParentPath, String newParentPath, String oldFolderName, + String newFolderName) throws InvalidNameException, IOException; + + @Override + void moveItem(String oldParentPath, String newParentPath, String oldItemName, + String newItemName) throws InvalidNameException, IOException; + + @Override + ItemCheckoutStatus checkout(String parentPath, String itemName, CheckoutType checkoutType, + String projectPath) throws IOException; + + @Override + void terminateCheckout(String parentPath, String itemName, long checkoutId, boolean notify) + throws IOException; + + @Override + ItemCheckoutStatus getCheckout(String parentPath, String itemName, long checkoutId) + throws IOException; + + @Override + ItemCheckoutStatus[] getCheckouts(String parentPath, String itemName) throws IOException; + + @Override + boolean folderExists(String folderPath) throws IOException; + + @Override + boolean fileExists(String parentPath, String itemName) throws IOException; + + @Override + long getLength(String parentPath, String itemName) throws IOException; + + @Override + boolean hasCheckouts(String parentPath, String itemName) throws IOException; + + @Override + boolean isCheckinActive(String parentPath, String itemName) throws IOException; + + @Override + void updateCheckoutVersion(String parentPath, String itemName, long checkoutId, + int checkoutVersion) throws IOException; + + @Override + RepositoryChangeEvent[] getEvents() throws IOException; + + @Override + void close() throws IOException; } diff --git a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryServerHandle.java b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryServerHandle.java index 996aa05c46..d743e2e6a0 100644 --- a/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryServerHandle.java +++ b/Ghidra/Framework/FileSystem/src/main/java/ghidra/framework/remote/RemoteRepositoryServerHandle.java @@ -15,11 +15,50 @@ */ package ghidra.framework.remote; +import java.io.IOException; import java.rmi.Remote; /** * RepositoryServerHandle provides access to a remote repository server via RMI. + *

+ * Methods from {@link RepositoryServerHandle} must be re-declared here to mark them as rmi-able. */ public interface RemoteRepositoryServerHandle extends RepositoryServerHandle, Remote { + @Override + boolean anonymousAccessAllowed() throws IOException; + + @Override + boolean isReadOnly() throws IOException; + + @Override + RepositoryHandle createRepository(String name) throws IOException; + + @Override + RepositoryHandle getRepository(String name) throws IOException; + + @Override + void deleteRepository(String name) throws IOException; + + @Override + String[] getRepositoryNames() throws IOException; + + @Override + String getUser() throws IOException; + + @Override + String[] getAllUsers() throws IOException; + + @Override + boolean canSetPassword() throws IOException; + + @Override + long getPasswordExpiration() throws IOException; + + @Override + boolean setPassword(char[] saltedSHA256PasswordHash) throws IOException; + + @Override + void connected() throws IOException; + } From 4c31ac66ce3d80d7b0aabfa8fa7a6267b3ef60b6 Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Wed, 5 Feb 2020 13:36:31 -0500 Subject: [PATCH 20/36] GT-3489 Updated x86.idx with latest AMD and Intel instruction set manuals --- Ghidra/Processors/x86/data/manuals/x86.idx | 3018 ++++++++++---------- 1 file changed, 1539 insertions(+), 1479 deletions(-) diff --git a/Ghidra/Processors/x86/data/manuals/x86.idx b/Ghidra/Processors/x86/data/manuals/x86.idx index 59df1f12a3..a5ed32ee68 100644 --- a/Ghidra/Processors/x86/data/manuals/x86.idx +++ b/Ghidra/Processors/x86/data/manuals/x86.idx @@ -1,4 +1,4 @@ -@Intel64_IA32_SoftwareDevelopersManual.pdf [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z, Sep 2016 (325383-060US)] +@325383-sdm-vol-2abcd.pdf [Intel 64 and IA-32 Architectures Software Developer's Manual Volume 2 (2A, 2B, 2C & 2D): Instruction Set Reference, A-Z, Oct 2019 (325383-071US)] AAA, 120 AAD, 122 BLENDPS, 123 @@ -72,1483 +72,1543 @@ BTR, 219 BTS, 221 BZHI, 223 CALL, 224 -CBW, 237 -CWDE, 237 -CDQE, 237 -CLAC, 238 -CLC, 239 -CLD, 240 -CLFLUSH, 241 -CLFLUSHOPT, 243 -CLI, 245 -CLTS, 247 -CLWB, 248 -CMC, 250 -CMOV, 251 -CMOVA, 251 -CMOVAE, 251 -CMOVB, 251 -CMOVBE, 251 -CMOVC, 251 -CMOVE, 251 -CMOVG, 251 -CMOVGE, 251 -CMOVL, 251 -CMOVLE, 251 -CMOVNA, 251 -CMOVNAE, 251 -CMOVNB, 251 -CMOVNBE, 251 -CMOVNC, 251 -CMOVNE, 251 -CMOVNG, 251 -CMOVNGE, 251 -CMOVNL, 251 -CMOVNLE, 251 -CMOVNO, 251 -CMOVNP, 251 -CMOVNS, 251 -CMOVNZ, 251 -CMOVO, 251 -CMOVP, 251 -CMOVPE, 251 -CMOVPO, 251 -CMOVS, 251 -CMOVZ, 251 -CMP, 255 -CMPPD, 257 -VCMPPD, 257 -CMPEQPD, 259 -CMPLTPD, 259 -CMPLEPD, 259 -CMPUNORDPD, 259 -CMPNEQPD, 259 -CMPNLTPD, 259 -CMPNLEPD, 259 -CMPORDPD, 259 -VCMPEQPD, 260 -VCMPLTPD, 260 -VCMPLEPD, 260 -VCMPUNORDPD, 260 -VCMPNEPD, 260 -VCMPNLTPD, 260 -VCMPNLEPD, 260 -VCMPORDPD, 260 -VCMPEQ_UQPD, 260 -VCMPNGEPD, 260 -VCMPNGTPD, 260 -VCMPFALSEPD, 260 -VCMPNEQ_OQPD, 260 -VCMPGEPD, 260 -VCMPGTPD, 260 -VCMPTRUEPD, 260 -VCMPEQ_OSPD, 260 -VCMPLT_OQPD, 260 -VCMPLE_OQPD, 260 -VCMPUNORD_SPD, 260 -VCMPNEQ_USPD, 260 -VCMPNLT_UQPD, 260 -VCMPNLE_UQPD, 260 -VCMPORD_SPD, 260 -VCMPEQ_USPD, 260 -VCMPNGE_UQPD, 260 -VCMPNGT_UQPD, 260 -VCMPFALSE_OSPD, 260 -VCMPNEQ_OSPD, 260 -VCMPGE_OQPD, 260 -VCMPGT_OQPD, 260 -VCMPTRUE_USPD, 260 -CMPPS, 264 -VCMPPS, 264 -CMPEQPS, 265 -CMPLTPS, 265 -CMPLEPS, 265 -CMPUNORDPS, 265 -CMPNEQPS, 265 -CMPNLTPS, 265 -CMPNLEPS, 265 -CMPORDPS, 265 -VCMPEQPS, 266 -VCMPLTPS, 266 -VCMPLEPS, 266 -VCMPUNORDPS, 266 -VCMPNEQPS, 266 -VCMPNLTPS, 266 -VCMPNLEPS, 266 -VCMPORDPS, 266 -VCMPEQ_UQPS, 266 -VCMPNGEPS, 266 -VCMPNGTPS, 266 -VCMPFALSEPS, 266 -VCMPNEQ_OQPS, 266 -VCMPGEPS, 266 -VCMPGTPS, 266 -VCMPTRUEPS, 266 -VCMPEQ_OSPS, 266 -VCMPLT_OQPS, 266 -VCMPLE_OQPS, 266 -VCMPUNORD_SPS, 266 -VCMPNEQ_USPS, 266 -VCMPNLT_UQPS, 266 -VCMPNLE_UQPS, 266 -VCMPORD_SPS, 266 -VCMPEQ_USPS, 266 -VCMPNGE_UQPS, 266 -VCMPNGT_UQPS, 266 -VCMPFALSE_OSPS, 266 -VCMPNEQ_OSPS, 266 -VCMPGE_OQPS, 266 -VCMPGT_OQPS, 266 -VCMPTRUE_USPS, 266 -CMPS, 271 -CMPSB, 271 -CMPSW, 271 -CMPSQ, 271 -CMPSD, 275 -VCMPSD, 275 -CMPEQSD, 276 -CMPLTSD, 276 -CMPLESD, 276 -CMPUNORDSD, 276 -CMPNEQSD, 276 -CMPNLTSD, 276 -CMPNLESD, 276 -CMPORDSD, 276 -VCMPEQSD, 276 -VCMPLTSD, 276 -VCMPLESD, 276 -VCMPUNORDSD, 276 -VCMPNEQSD, 276 -VCMPNLTSD, 276 -VCMPNLESD, 276 -VCMPORDSD, 276 -VCMPEQ_UQSD, 276 -VCMPNGESD, 276 -VCMPNGTSD, 276 -VCMPFALSESD, 276 -VCMPNEQ_OQSD, 276 -VCMPGESD, 276 -VCMPGTSD, 277 -VCMPTRUESD, 277 -VCMPEQ_OSSD, 277 -VCMPLT_OQSD, 277 -VCMPLE_OQSD, 277 -VCMPUNORD_SSD, 277 -VCMPNEQ_USSD, 277 -VCMPNLT_UQSD, 277 -VCMPNLE_UQSD, 277 -VCMPORD_SSD, 277 -VCMPEQ_USSD, 277 -VCMPNGE_UQSD, 277 -VCMPNGT_UQSD, 277 -VCMPFALSE_OSSD, 277 -VCMPNEQ_OSSD, 277 -VCMPGE_OQSD, 277 -VCMPGT_OQSD, 277 -VCMPTRUE_USSD, 277 -CMPSS, 279 -VCMPSS, 279 -CMPEQSS, 280 -CMPLTSS, 280 -CMPLESS, 280 -CMPUNORDSS, 280 -CMPNEQSS, 280 -CMPNLTSS, 280 -CMPNLESS, 280 -CMPORDSS, 280 -VCMPEQSS, 280 -VCMPLTSS, 280 -VCMPLESS, 280 -VCMPUNORDSS, 280 -VCMPNEQSS, 280 -VCMPNLTSS, 280 -VCMPNLESS, 280 -VCMPORDSS, 280 -VCMPEQ_UQSS, 280 -VCMPNGESS, 280 -VCMPNGTSS, 280 -VCMPFALSESS, 280 -VCMPNEQ_OQSS, 280 -VCMPGESS, 280 -VCMPGTSS, 281 -VCMPTRUESS, 281 -VCMPEQ_OSSS, 281 -VCMPLT_OQSS, 281 -VCMPLE_OQSS, 281 -VCMPUNORD_SSS, 281 -VCMPNEQ_USSS, 281 -VCMPNLT_UQSS, 281 -VCMPNLE_UQSS, 281 -VCMPORD_SSS, 281 -VCMPEQ_USSS, 281 -VCMPNGE_UQSS, 281 -VCMPNGT_UQSS, 281 -VCMPFALSE_OSSS, 281 -VCMPNEQ_OSSS, 281 -VCMPGE_OQSS, 281 -VCMPGT_OQSS, 281 -VCMPTRUE_USSS, 281 -CMPXCHG, 283 -CMPXCHG8B, 285 -CMPXCHG16B, 285 -COMISD, 288 -VCOMISD, 288 -COMISS, 290 -VCOMISS, 290 -CPUID, 292 -CRC32, 327 -CVTDQ2PD, 330 -VCVTDQ2PD, 330 -CVTDQ2PS, 334 -VCVTDQ2PS, 334 -CVTPD2DQ, 337 -VCVTPD2DQ, 337 -CVTPD2PI, 341 -CVTPD2PS, 342 -VCVTPD2PS, 342 -CVTPI2PD, 346 -CVTPI2PS, 347 -CVTPS2DQ, 348 -VCVTPS2DQ, 348 -CVTPS2PD, 351 -VCVTPS2PD, 351 -CVTPS2PI, 354 -CVTSD2SI, 355 -VCVTSD2SI, 355 -CVTSD2SS, 357 -VCVTSD2SS, 357 -CVTSI2SD, 359 -VCVTSI2SD, 359 -CVTSI2SS, 361 -VCVTSI2SS, 361 -CVTSS2SD, 363 -VCVTSS2SD, 363 -CVTSS2SI, 365 -VCVTSS2SI, 365 -CVTTPD2DQ, 367 -VCVTTPD2DQ, 367 -CVTTPD2PI, 371 -CVTTPS2DQ, 372 -VCVTTPS2DQ, 372 -CVTTPS2PI, 375 -CVTTSD2SI, 376 -VCVTTSD2SI, 376 -CVTTSS2SI, 378 -VCVTTSS2SI, 378 -CWD, 380 -CDQ, 380 -CQO, 380 -DAA, 381 -DAS, 383 -DEC, 385 -DIV, 387 -DIVPD, 390 -VDIVPD, 390 -DIVPS, 393 -VDIVPS, 393 -DIVSD, 396 -VDIVSD, 396 -DIVSS, 398 -VDIVSS, 398 -DPPD, 400 -VDPPD, 400 -DPPS, 402 -VDPPS, 402 -EMMS, 405 -ENTER, 406 -EXTRACTPS, 409 -VEXTRACTPS, 409 -F2XM1, 411 -FABS, 413 -FADD, 414 -FADDP, 414 -FIADD, 414 -FBLD, 417 -FBSTP, 419 -FCHS, 421 -FCLEX, 423 -FNCLEX, 423 -FCMOV, 425 -FCMOVB, 425 -FCMOVE, 425 -FCMOVBE, 425 -FCMOVU, 425 -FCMOVNB, 425 -FCMOVNE, 425 -FCMOVNBE, 425 -FCMOVNU, 425 -FCOM, 427 -FCOMP, 427 -FCOMPP, 427 -FCOMI, 430 -FCOMIP, 430 -FUCOMI, 430 -FUCOMIP, 430 -FCOS, 433 -FDECSTP, 435 -FDIV, 436 -FDIVP, 436 -FIDIV, 436 -FDIVR, 439 -FDIVRP, 439 -FIDIVR, 439 -FFREE, 442 -FICOM, 443 -FICOMP, 443 -FILD, 445 -FINCSTP, 447 -FINIT, 448 -FNINIT, 448 -FIST, 450 -FISTP, 450 -FISTTP, 453 -FLD, 455 -FLD1, 457 -FLDL2T, 457 -FLDL2E, 457 -FLDPI, 457 -FLDLG2, 457 -FLDLN2, 457 -FLDZ, 457 -FLDCW, 459 -FLDENV, 461 -FMUL, 463 -FMULP, 463 -FIMUL, 463 -FNOP, 466 -FPATAN, 467 -FPREM, 469 -FPREM1, 471 -FPTAN, 473 -FRNDINT, 475 -FRSTOR, 476 -FSAVE, 478 -FNSAVE, 478 -FSCALE, 481 -FSIN, 483 -FSINCOS, 485 -FSQRT, 487 -FST, 489 -FSTP, 489 -FSTCW, 491 -FNSTCW, 491 -FSTENV, 493 -FNSTENV, 493 -FSTSW, 495 -FNSTSW, 495 -FSUB, 497 -FSUBP, 497 -FISUB, 497 -FSUBR, 500 -FSUBRP, 500 -FISUBR, 500 -FTST, 503 -FUCOM, 505 -FUCOMP, 505 -FUCOMPP, 505 -FXAM, 508 -FXCH, 510 -FXRSTOR, 512 -FXRSTOR64, 512 -FXSAVE, 515 -FXSAVE64, 515 -FXTRACT, 523 -FYL2X, 525 -FYL2XP1, 527 -HADDPD, 529 -VHADDPD, 529 -HADDPS, 532 -VHADDPS, 532 -HLT, 535 -HSUBPD, 536 -VHSUBPD, 536 -HSUBPS, 539 -VHSUBPS, 539 -IDIV, 542 -IMUL, 545 -IN, 549 -INC, 551 -INS, 553 -INSB, 553 -INSW, 553 -INSD, 553 -INSERTPS, 556 -VINSERTPS, 556 -INT, 559 -INTO, 559 -INT3, 559 -INVD, 571 -INVLPG, 573 -INVPCID, 575 -IRET, 578 -IRETD, 578 -IRETQ, 578 -J, 585 -JA, 585 -JAE, 585 -JB, 585 -JBE, 585 -JC, 585 -JCXZ, 585 -JECXZ, 585 -JRCXZ, 585 -JE, 585 -JG, 585 -JGE, 585 -JL, 585 -JLE, 585 -JNA, 585 -JNAE, 585 -JNB, 585 -JNBE, 585 -JNC, 585 -JNE, 585 -JNG, 585 -JNGE, 585 -JNL, 585 -JNLE, 585 -JNO, 585 -JNP, 585 -JNS, 585 -JNZ, 585 -JO, 585 -JP, 585 -JPE, 585 -JPO, 585 -JS, 585 -JZ, 585 -JMP, 590 -KADDW, 598 -KADDB, 598 -KADDQ, 598 -KADDD, 598 -KANDW, 599 -KANDB, 599 -KANDQ, 599 -KANDD, 599 -KANDNW, 600 -KANDNB, 600 -KANDNQ, 600 -KANDND, 600 -KMOVW, 601 -KMOVB, 601 -KMOVQ, 601 -KMOVD, 601 -KNOTW, 603 -KNOTB, 603 -KNOTQ, 603 -KNOTD, 603 -KORW, 604 -KORB, 604 -KORQ, 604 -KORD, 604 -KORTESTW, 605 -KORTESTB, 605 -KORTESTQ, 605 -KORTESTD, 605 -KSHIFTLW, 607 -KSHIFTLB, 607 -KSHIFTLQ, 607 -KSHIFTLD, 607 -KSHIFTRW, 609 -KSHIFTRB, 609 -KSHIFTRQ, 609 -KSHIFTRD, 609 -KTESTW, 611 -KTESTB, 611 -KTESTQ, 611 -KTESTD, 611 -KUNPCKBW, 613 -KUNPCKWD, 613 -KUNPCKDQ, 613 -KXNORW, 614 -KXNORB, 614 -KXNORQ, 614 -KXNORD, 614 -KXORW, 615 -KXORB, 615 -KXORQ, 615 -KXORD, 615 -LAHF, 616 -LAR, 617 -LDDQU, 620 -VLDDQU, 620 -LDMXCSR, 622 -VLDMXCSR, 622 -LDS, 623 -LES, 623 -LFS, 623 -LGS, 623 -LSS, 623 -LEA, 627 -LEAVE, 629 -LFENCE, 631 -LGDT, 632 -LIDT, 632 -LLDT, 635 -LMSW, 637 -LOCK, 639 -LODS, 641 -LODSB, 641 -LODSW, 641 -LODSD, 641 -LODSQ, 641 -LOOP, 644 -LOOPE, 644 -LOOPNE, 644 -LSL, 646 -LTR, 649 -LZCNT, 651 -MASKMOVDQU, 660 -VMASKMOVDQU, 660 -MASKMOVQ, 662 -MAXPD, 664 -VMAXPD, 664 -MAXPS, 667 -VMAXPS, 667 -MAXSD, 670 -VMAXSD, 670 -MAXSS, 672 -VMAXSS, 672 -MFENCE, 674 -MINPD, 675 -VMINPD, 675 -MINPS, 678 -VMINPS, 678 -MINSD, 681 -VMINSD, 681 -MINSS, 683 -VMINSS, 683 -MONITOR, 685 -MOV, 687 -MOVAPD, 697 -VMOVPAD, 697 -MOVAPS, 701 -VMOVAPS, 701 -MOVBE, 705 -MOVD, 707 -VMOVD, 707 -MOVQ, 707 -VMOVQ, 707 -MOVDDUP, 711 -VMOVDDUP, 711 -MOVDQA, 714 -VMOVDQA, 714 -VMOVDQA32, 714 -VMOVDQA64, 714 -MOVDQU, 719 -VMOVDQU, 719 -VMOVDQU8, 719 -VMOVDQU16, 719 -VMOVDQU32, 719 -VMOVDQU64, 719 -MOVDQ2Q, 727 -MOVHLPS, 728 -VMOVHLPS, 728 -MOVHPD, 730 -VMOVHPD, 730 -MOVHPS, 732 -VMOVHPS, 732 -MOVLHPS, 734 -VMOVLHPS, 734 -MOVLPD, 736 -VMOVLPD, 736 -MOVLPS, 738 -VMOVLPS, 738 -MOVMSKPD, 740 -VMOVMSKPD, 740 -MOVMSKPS, 742 -VMOVMSKPS, 742 -MOVNTDQA, 744 -VMOVNTDQA, 744 -MOVNTDQ, 746 -VMOVNTDQ, 746 -MOVNTI, 748 -MOVNTPD, 750 -VMOVNTPD, 750 -MOVNTPS, 752 -VMOVNTPS, 752 -MOVNTQ, 754 -MOVQ, 755 -VMOVQ, 755 -MOVQ2DQ, 758 -MOVS, 759 -MOVSB, 759 -MOVSW, 759 -MOVSQ, 759 -MOVSD, 763 -VMOVSD, 763 -MOVSHDUP, 766 -VMOVSHDUP, 766 -MOVSLDUP, 769 -VMOVSLDUP, 769 -MOVSS, 772 -VMOVSS, 772 -MOVSX, 776 -MOVSXD, 776 -MOVUPD, 778 -VMOVUPD, 778 -MOVUPS, 782 -VMOVUPS, 782 -MOVZX, 786 -MPSADBW, 788 -VMPSADBW, 788 -MUL, 796 -MULPD, 798 -VMULPD, 798 -MULPS, 801 -VMULPS, 801 -MULSD, 804 -VMULSD, 804 -MULSS, 806 -VMULSS, 806 -MULX, 808 -MWAIT, 810 -NEG, 813 -NOP, 815 -NOT, 816 -OR, 818 -ORPD, 820 -VORPD, 820 -ORPS, 823 -VORPS, 823 -OUT, 826 -OUTS, 828 -OUTSB, 828 -OUTSW, 828 -OUTSD, 828 -PABSB, 832 -VPABSB, 832 -PABSW, 832 -VPABSW, 832 -PABSD, 832 -VPABSD, 832 -PABSQ, 832 -VPABSQ, 832 -PACKSSWB, 838 -VPACKSSWB, 838 -PACKSSDW, 838 -VPACKSSDW, 838 -PACKUSDW, 846 -VPACKUSDW, 846 -PACKUSWB, 851 -VPACKUSWB, 851 -PADDB, 856 -VPADDB, 856 -PADDW, 856 -VPADDW, 856 -PADDD, 856 -VPADDD, 856 -PADDQ, 856 -VPADDQ, 856 -PADDSB, 863 -VPADDSB, 863 -PADDSW, 863 -VPADDSW, 863 -PADDUSB, 867 -VPADDUSB, 867 -PADDUSW, 867 -VPADDUSW, 867 -PALIGNR, 871 -VPALIGNR, 871 -PAND, 875 -VPAND, 875 -VPANDD, 875 -VPANDQ, 875 -PANDN, 878 -VPANDN, 878 -VPANDND, 878 -VPANDNQ, 878 -PAUSE, 881 -PAVGB, 882 -VPAVGB, 882 -PAVGW, 882 -VPAVGW, 882 -PBLENDVB, 886 -VPBLENDVB, 886 -PBLENDW, 890 -VPBLENDW, 890 -PCLMULQDQ, 893 -VPCLMULQDQ, 893 -PCMPEQB, 896 -VPCMPEQB, 896 -PCMPEQW, 896 -VPCMPEQW, 896 -PCMPEQD, 896 -VPCMPEQD, 896 -PCMPEQQ, 902 -VPCMPEQQ, 902 -PCMPESTRI, 905 -VPCMPESTRI, 905 -PCMPESTRM, 907 -VPCMPESTRM, 907 -PCMPGTB, 909 -VPCMPGTB, 909 -PCMPGTW, 909 -VPCMPGTW, 909 -PCMPGTD, 909 -VPCMPGTD, 909 -PCMPGTQ, 915 -VPCMPGTQ, 915 -PCMPISTRI, 918 -VPCMPISTRI, 918 -PCMPISTRM, 920 -VPCMPISTRM, 920 -PDEP, 922 -PEXT, 924 -PEXTRB, 926 -VPEXTRB, 926 -PEXTRD, 926 -VPEXTRD, 926 -PEXTRQ, 926 -VPEXTRQ, 926 -PEXTRW, 929 -VPEXTRW, 929 -PHADDW, 932 -VPHADDW, 932 -PHADDD, 932 -VPHADDD, 932 -PHADDSW, 936 -VPHADDSW, 936 -PHMINPOSUW, 938 -VPHMINPOSUW, 938 -PHSUBW, 940 -VPHSUBW, 940 -PHSUBD, 940 -PHSUBSW, 943 -VPHSUBSW, 943 -PINSRB, 945 -VPINSRB, 945 -PINSRD, 945 -VPINSRD, 945 -PINSRQ, 945 -VPINSRQ, 945 -PINSRW, 948 -VPINSRW, 948 -PMADDUBSW, 950 -VPMADDUBSW, 950 -PMADDWD, 953 -VPMADDWD, 953 -PMAXSB, 956 -VPMAXSB, 956 -PMAXSW, 956 -VPMAXSW, 956 -PMAXSD, 956 -VPMAXSD, 956 -PMAXSQ, 956 -VPMAXSQ, 956 -PMAXUB, 963 -VPMAXUB, 963 -PMAXUW, 963 -VPMAXUW, 963 -PMAXUD, 968 -VPMAXUD, 968 -PMAXUQ, 968 -VPMAXUQ, 968 -PMINSB, 972 -VPMINSB, 972 -PMINSW, 972 -VPMINSW, 972 -PMINSD, 977 -VPMINSD, 977 -PMINSQ, 977 -VPMINSQ, 977 -PMINUB, 981 -VPMINUB, 981 -PMINUW, 981 -VPMINUW, 981 -PMINUD, 986 -VPMINUD, 986 -PMINUQ, 986 -VPMINUQ, 986 -PMOVMSKB, 990 -VPMOVMSKB, 990 -PMOVSX, 992 -PMOVSXBW, 992 -VPMOVSXBW, 992 -PMOVSXBD, 992 -VPMOVSXBD, 992 -PMOVSXBQ, 992 -VPMOVSXBQ, 992 -PMOVSXWD, 992 -VPMOVSXWD, 992 -PMOVSXWQ, 992 -VPMOVSXWQ, 992 -PMOVSXDQ, 992 -VPMOVSXDQ, 992 -PMOVZX, 1002 -PMOVZXBW, 1002 -VPMOVZXBW, 1002 -PMOVZXBD, 1002 -VPMOVZXBD, 1002 -PMOVZXBQ, 1002 -VPMOVZXBQ, 1002 -PMOVZXWD, 1002 -VPMOVZXWD, 1002 -PMOVZXWQ, 1002 -VPMOVZXWQ, 1002 -PMOVZXDQ, 1002 -VPMOVZXDQ, 1002 -PMULDQ, 1011 -VPMULDQ, 1011 -PMULHRSW, 1014 -VPMULHRSW, 1014 -PMULHUW, 1018 -VPMULHUW, 1018 -PMULHW, 1022 -VPMULHW, 1022 -PMULLD, 1026 -VPMULLD, 1026 -PMULLQ, 1026 -VPMULLQ, 1026 -PMULLW, 1030 -VPMULLW, 1030 -PMULUDQ, 1034 -VPMULUDQ, 1034 -POP, 1037 -POPA, 1042 -POPAD, 1042 -POPCNT, 1044 -POPF, 1046 -POPFD, 1046 -POPFQ, 1046 -POR, 1051 -PREFETCHT0, 1054 -PREFETCHT1, 1054 -PREFETCHT2, 1054 -PREFETCHNTA, 1054 -PREFETCHW, 1056 -PREFETCHWT1, 1058 -PSADBW, 1060 -VPSADBW, 1060 -PSHUFB, 1064 -VPSHUFB, 1064 -PSHUFD, 1068 -VPSHUFD, 1068 -PSHUFHW, 1072 -VPSHUFHW, 1072 -PSHUFLW, 1075 -VPSHUFLW, 1075 -PSHUFW, 1078 -PSIGNB, 1079 -VPSIGNB, 1079 -PSIGNW, 1079 -VPSIGNW, 1079 -PSIGND, 1079 -VPSIGND, 1079 -PSLLDQ, 1083 -VPSLLDQ, 1083 -PSLLW, 1085 -VPSLLW, 1085 -PSLLD, 1085 -VPSLLD, 1085 -PSLLQ, 1085 -VPSLLQ, 1085 -PSRAW, 1097 -VPSRAW, 1097 -PSRAD, 1097 -VPSRAD, 1097 -VPSRAQ, 1097 -PSRLDQ, 1107 -VPSRLDQ, 1107 -PSRLW, 1109 -VPSRLW, 1109 -PSRLD, 1109 -VPSRLD, 1109 -PSRLQ, 1109 -VPSRLQ, 1109 -PSUBB, 1121 -VPSUBB, 1121 -PSUBW, 1121 -VPSUBW, 1121 -PSUBD, 1121 -VPSUBD, 1121 -PSUBQ, 1128 -VPSUBQ, 1128 -PSUBSB, 1131 -VPSUBSB, 1131 -PSUBSW, 1131 -VPSUBSW, 1131 -PSUBUSB, 1135 -VPSUBUSB, 1135 -PSUBUSW, 1135 -VPSUBUSW, 1135 -PTEST, 1139 -VPTEST, 1139 -PTWRITE, 1141 -PUNPCKHBW, 1143 -VPUNPCKHBW, 1143 -PUNPCKHWD, 1143 -VPUNPCKHWD, 1143 -PUNPCKHDQ, 1143 -VPUNPCKHDQ, 1143 -PUNPCKHQDQ, 1143 -VPUNPCKHQDQ, 1143 -PUNPCKLBW, 1153 -VPUNPCKLBW, 1153 -PUNPCKLWD, 1153 -VPUNPCKLWD, 1153 -PUNPCKLDQ, 1153 -VPUNPCKLDQ, 1153 -PUNPCKLQDQ, 1153 -VPUNPCKLQDQ, 1153 -PUSH, 1163 -PUSHA, 1166 -PUSHAD, 1166 -PUSHF, 1168 -PUSHFD, 1168 -PUSHFQ, 1168 -PXOR, 1170 -VPXOR, 1170 -VPXORD, 1170 -VPXORQ, 1170 -RCL, 1173 -RCR, 1173 -ROL, 1173 -ROR, 1173 -RCPPS, 1178 -VRCPPS, 1178 -RCPSS, 1180 -VRCPSS, 1180 -RDFSBASE, 1182 -RDGSBASE, 1182 -RDMSR, 1184 -RDPID, 1186 -RDPKRU, 1187 -RDPMC, 1189 -RDRAND, 1193 -RDSEED, 1195 -RDTSC, 1197 -RDTSCP, 1199 -REP, 1201 -REPE, 1201 -REPZ, 1201 -REPNE, 1201 -REPNZ, 1201 -RET, 1205 -RORX, 1215 -ROUNDPD, 1216 -VROUNDPD, 1216 -ROUNDPS, 1219 -VROUNDPS, 1219 -ROUNDSD, 1222 -VROUNDSD, 1222 -ROUNDSS, 1224 -VROUNDSS, 1224 -RSM, 1226 -RSQRTPS, 1228 -VRSQRTPS, 1228 -RSQRTSS, 1130 -VRSQRTSS, 1130 -SAHF, 1232 -SAL, 1234 -SAR, 1234 -SHL, 1234 -SHR, 1234 -SARX, 1239 -SHLX, 1239 -SHRX, 1239 -SBB, 1241 -SCAS, 1244 -SCASB, 1244 -SCASW, 1244 -SCASD, 1244 -SCASQ, 1244 -SET, 1248 -SETA, 1248 -SETAE, 1248 -SETB, 1248 -SETBE, 1248 -SETC, 1248 -SETE, 1248 -SETG, 1248 -SETGE, 1248 -SETL, 1248 -SETLE, 1248 -SETNA, 1248 -SETNAE, 1248 -SETNB, 1248 -SETNBE, 1248 -SETNC, 1248 -SETNE, 1248 -SETNG, 1248 -SETNGE, 1248 -SETNL, 1248 -SETNLE, 1248 -SETNO, 1248 -SETNP, 1248 -SETNS, 1248 -SETNZ, 1248 -SETO, 1248 -SETP, 1248 -SETPE, 1248 -SETPO, 1248 -SETS, 1248 -SETZ, 1248 -SFENCE, 1251 -SGDT, 1252 -SHA1RNDS4, 1254 -SHA1NEXTE, 1256 -SHA1MSG1, 1257 -SHA1MSG2, 1258 -SHA256RNDS2, 1259 -SHA256MSG1, 1261 -SHA256MSG2, 1262 -SHLD, 1263 -SHRD, 1266 -SHUFPD, 1269 -VSHUFPD, 1269 -SHUFPS, 1274 -VSHUFPS, 1274 -SIDT, 1278 -SLDT, 1280 -SMSW, 1282 -SQRTPD, 1284 -VSQRTPD, 1284 -SQRTPS, 1287 -VSQRTPS, 1287 -SQRTSD, 1290 -VSQRTSD, 1290 -SQRTSS, 1292 -VSQRTSS, 1292 -STAC, 1294 -STC, 1295 -STD, 1296 -STI, 1297 -STMXCSR, 1299 -STOS, 1300 -STOSB, 1300 -STOSW, 1300 -STOSD, 1300 -STOSQ, 1300 -STR, 1304 -SUB, 1306 -SUBPD, 1308 -VSUBPD, 1308 -SUBPS, 1311 -VSUBPS, 1311 -SUBSD, 1314 -VSUBSD, 1314 -SUBSS, 1316 -VSUBSS, 1316 -SWAPGS, 1318 -SYSCALL, 1320 -SYSENTER, 1322 -SYSEXIT, 1325 -SYSRET, 1328 -TEST, 1331 -TZCNT, 1333 -UCOMISD, 1335 -VUCOMISD, 1335 -UCOMISS, 1337 -VUCOMISS, 1337 -UD2, 1339 -UNPCKHPD, 1340 -VUNPCKHPD, 1340 -UNPCKHPS, 1344 -VUNPCKHPS, 1344 -UNPCKLPD, 1348 -VUNPCKLPD, 1348 -UNPCKLPS, 1352 -VUNPCKLPS, 1352 -VALIGND, 1361 -VALIGNQ, 1361 -VBLENDMPD, 1365 -VBLENDMPS, 1365 -VBROADCAST, 1368 -VBROADCASTSS, 1368 -VBROADCASTSD, 1368 -VBROADCASTF128, 1368 -VBROADCASTF32X2, 1368 -VBROADCASTF32X4, 1368 -VBROADCASTF64X2, 1368 -VBROADCASTF32X8, 1368 -VBROADCASTF64X4, 1368 -VPBROADCASTM, 1375 -VPBROADCASTMB2Q, 1375 -VPBROADCASTMW2D, 1375 -VCOMPRESSPD, 1377 -VCOMPRESSPS, 1379 -VCVTPD2QQ, 1381 -VCVTPD2UDQ, 1384 -VCVTPD2UQQ, 1387 -VCVTPH2PS, 1390 -VCVTPS2PH, 1393 -VCVTPS2UDQ, 1397 -VCVTPS2QQ, 1400 -VCVTPS2UQQ, 1403 -VCVTQQ2PD, 1406 -VCVTQQ2PS, 1408 -VCVTSD2USI, 1410 -VCVTSS2USI, 1411 -VCVTTPD2QQ, 1413 -VCVTTPD2UDQ, 1415 -VCVTTPD2UQQ, 1418 -VCVTTPS2UDQ, 1420 -VCVTTPS2QQ, 1422 -VCVTTPS2UQQ, 1424 -VCVTTSD2USI, 1426 -VCVTTSS2USI, 1427 -VCVTUDQ2PD, 1429 -VCVTUDQ2PS, 1431 -VCVTUQQ2PD, 1433 -VCVTUQQ2PS, 1435 -VCVTUSI2SD, 1437 -VCVTUSI2SS, 1439 -VDBPSADBW, 1441 -VEXPANDPD, 1445 -VEXPANDPS, 1447 -VERR, 1449 -VERW, 1449 -VEXP2PD, 1451 -VEXP2PS, 1453 -VEXTRACTF128, 1455 -VEXTRACTF32X4, 1455 -VEXTRACTF64X2, 1455 -VEXTRACTF32X8, 1455 -VEXTRACTF64X4, 1455 -VEXTRACTI128, 1462 -VEXTRACTI32X4, 1462 -VEXTRACTI64X2, 1462 -VEXTRACTI32X8, 1462 -VEXTRACTI64X4, 1462 -VFIXUPIMMPD, 1468 -VFIXUPIMMPS, 1472 -VFIXUPIMMSD, 1476 -VFIXUPIMMSS, 1479 -VFMADD132PD, 1482 -VFMADD213PD, 1482 -VFMADD231PD, 1482 -VFMADD132PS, 1489 -VFMADD213PS, 1489 -VFMADD231PS, 1489 -VFMADD132SD, 1496 -VFMADD213SD, 1496 -VFMADD231SD, 1496 -VFMADD132SS, 1499 -VFMADD213SS, 1499 -VFMADD231SS, 1499 -VFMADDSUB132PD, 1502 -VFMADDSUB213PD, 1502 -VFMADDSUB231PD, 1502 -VFMADDSUB132PS, 1512 -VFMADDSUB213PS, 1512 -VFMADDSUB231PS, 1512 -VFMSUBADD132PD, 1521 -VFMSUBADD213PD, 1521 -VFMSUBADD231PD, 1521 -VFMSUBADD132PS, 1531 -VFMSUBADD213PS, 1531 -VFMSUBADD231PS, 1531 -VFMSUB132PD, 1541 -VFMSUB213PD, 1541 -VFMSUB231PD, 1541 -VFMSUB132PS, 1548 -VFMSUB213PS, 1548 -VFMSUB231PS, 1548 -VFMSUB132SD, 1555 -VFMSUB213SD, 1555 -VFMSUB231SD, 1555 -VFMSUB132SS, 1558 -VFMSUB213SS, 1558 -VFMSUB231SS, 1558 -VFNMADD132PD, 1561 -VFNMADD213PD, 1561 -VFNMADD231PD, 1561 -VFNMADD132PS, 1568 -VFNMADD213PS, 1568 -VFNMADD231PS, 1568 -VFNMADD132SD, 1574 -VFNMADD213SD, 1574 -VFNMADD231SD, 1574 -VFNMADD132SS, 1577 -VFNMADD213SS, 1577 -VFNMADD231SS, 1577 -VFNMSUB132PD, 1580 -VFNMSUB213PD, 1580 -VFNMSUB231PD, 1580 -VFNMSUB132PS, 1586 -VFNMSUB213PS, 1586 -VFNMSUB231PS, 1586 -VFNMSUB132SD, 1592 -VFNMSUB213SD, 1592 -VFNMSUB231SD, 1592 -VFNMSUB132SS, 1595 -VFNMSUB213SS, 1595 -VFNMSUB231SS, 1595 -VFPCLASSPD, 1598 -VFPCLASSPS, 1601 -VFPCLASSSD, 1603 -VFPCLASSSS, 1605 -VGATHERDPD, 1607 -VGATHERQPD, 1607 -VGATHERDPS, 1612 -VGATHERQPS, 1612 -VGATHERDPD, 1617 -VGATHERPFODPS, 1620 -VGATHERPFOQPS, 1620 -VGATHERPFODPD, 1620 -VGATHERPFOQPD, 1620 -VGATHERPF1DPS, 1623 -VGATHERPF1QPS, 1623 -VGATHERPF1DPD, 1623 -VGATHERPF1QPD, 1623 -VGATHERQPS, 1626 -VGATHERQPD, 1626 -VPGATHERDD, 1629 -VPGATHERQD, 1629 -VPGATHERDQ, 1633 -VPGATHERQQ, 1636 -VGETEXPPD, 1644 -VGETEXPPS, 1647 -VGETEXPSD, 1651 -VGETEXPSS, 1653 -VGETMANTPD, 1655 -VGETMANTPS, 1659 -VGETMANTSD, 1662 -VGETMANTSS, 1664 -VINSERTF128, 1666 -VINSERTF32X4, 1666 -VINSERTF64X2, 1666 -VINSERTF32X8, 1666 -VINSERTF64X4, 1666 -VINSERTI128, 1670 -VINSERTI32X4, 1670 -VINSERTI64X2, 1670 -VINSERTI32X8, 1670 -VINSERTI64X4, 1670 -VMASKMOV, 1674 -VMASKMOVPS, 1674 -VMASKMOVPD, 1674 -VBLENDD, 1677 -VPBLENDMB, 1679 -VPBLENDMW, 1679 -VPBLENDMD, 1681 -VPBLENDMQ, 1681 -VPBROADCASTB, 1684 -VPBROADCASTW, 1684 -VPBROADCASTD, 1684 -VPBROADCASTQ, 1684 -VPBROADCASTI32X2, 1687 -VPBROADCASTI128, 1687 -VPBROADCASTI32X4, 1687 -VPBROADCASTI64X2, 1687 -VPBROADCASTI32X8, 1687 -VPBROADCASTI64X4, 1687 -VPCMPB, 1695 -VPCMPUB, 1695 -VPCMPD, 1698 -VPCMPUD, 1698 -VPCMPQ, 1701 -VPCMPUQ, 1701 -VPCMPW, 1704 -VPCMPUW, 1704 -VCOMPRESSD, 1707 -VCOMPRESSQ, 1709 -VPCONFLICTD, 1711 -VPCONFLICTQ, 1711 -VPERM2F128, 1714 -VPERM2I128, 1716 -VPERMD, 1718 -VPERMW, 1718 -VPERMI2W, 1721 -VPERMI2D, 1721 -VPERMI2Q, 1721 -VPERMI2PS, 1721 -VPERMI2PD, 1721 -VPERMILPD, 1727 -VPERMILPS, 1732 -VPERMPD, 1737 -VPERMPS, 1740 -VPERMQ, 1743 -VEXPANDD, 1746 -VEXPANDQ, 1748 -VPLZCNTD, 1750 -VPLZCNTQ, 1750 -VPMASKMOVD, 1753 -VPMASKMOVQ, 1753 -VPMOVM2B, 1756 -VPMOVM2W, 1756 -VPMOVM2D, 1756 -VPMOVM2Q, 1756 -VPMOVB2M, 1759 -VPMOVW2M, 1759 -VPMOVD2M, 1759 -VPMOVQ2M, 1759 -VPMOVQB, 1762 -VPMOVSQB, 1762 -VPMOVUSQB, 1762 -VPMOVQW, 1766 -VPMOVSQW, 1766 -VPMOVUSQW, 1766 -VPMOVQD, 1770 -VPMOVSQD, 1770 -VPMOVUSQD, 1770 -VPMOVDB, 1774 -VPMOVSDB, 1774 -VPMOVUSDB, 1774 -VPMOVDW, 1778 -VPMOVSDW, 1778 -VPMOVUSDW, 1778 -VPMOVWB, 1782 -VPMOVSWB, 1782 -VPMOVUSWB, 1782 -PROLD, 1786 -VPROLD, 1786 -PROLVD, 1786 -VPROLVD, 1786 -PROLVQ, 1786 -VPROLVQ, 1786 -PRORD, 1791 -VPRORD, 1791 -PRORVD, 1791 -VPRORVD, 1791 -PRORQ, 1791 -VPRORQ, 1791 -PRORVQ, 1791 -VPRORVQ, 1791 -VPSCATTERDD, 1796 -VPSCATTERDQ, 1796 -VPSCATTERQD, 1796 -VPSCATTERQQ, 1796 -VPSLLVW, 1801 -VPSLLVD, 1801 -VPSLLVQ, 1801 -VPSRAVW, 1806 -VPSRAVD, 1806 -VPSRAVQ, 1806 -VPSRLVW, 1811 -VPSRLVD, 1811 -VPSRLVQ, 1811 -VPTERNLOGD, 1816 -VPTERNLOGQ, 1816 -VPTESTMB, 1819 -VPTESTMW, 1819 -VPTESTMD, 1819 -VPTESTMQ, 1819 -VPTESTNMB, 1822 -VPTESTNMW, 1822 -VPTESTNMD, 1822 -VPTESTNMQ, 1822 -VRANGEPD, 1826 -VRANGEPS, 1831 -VRANGESD, 1385 -VRANGESS, 1838 -VRCP14PD, 1841 -VRCP14SD, 1843 -VRCP14PS, 1845 -VRCP14SS, 1847 -VRCP28PD, 1849 -VRCP28SD, 1851 -VRCP28PS, 1853 -VRCP28SS, 1855 -VREDUCEPD, 1857 -VREDUCESD, 1860 -VREDUCEPS, 1862 -VREDUCESS, 1864 -VRNDSCALEPD, 1866 -VRNDSCALESD, 1870 -VRNDSCALEPS, 1872 -VRNDSCALESS, 1875 -VRSQRT14PD, 1877 -VRSQRT14SD, 1879 -VRSQRT14PS, 1881 -VRSQRT14SS, 1883 -VRSQRT28PD, 1885 -VRSQRT28SD, 1887 -VRSQRT28PS, 1889 -VRSQRT28SS, 1891 -VSCALEFPD, 1893 -VSCALEFSD, 1896 -VSCALEFPS, 1898 -VSCALEFSS, 1900 -VSCATTERDPS, 1902 -VSCATTERDPD, 1902 -VSCATTERQPS, 1902 -VSCATTERQPD, 1902 -VSCATTERPFODPS, 1907 -VSCATTERPFOQPS, 1907 -VSCATTERPFODPD, 1907 -VSCATTERPFOQPD, 1907 -VSCATTERPF1DPS, 1909 -VSCATTERPF1QPS, 1909 -VSCATTERPF1DPD, 1909 -VSCATTERPF1QPD, 1909 -VSHUFF32X4, 1911 -VSHUFF64X2, 1911 -VSHUFI32X4, 1911 -VSHUFI64X2, 1911 -VTESTPD, 1916 -VTESTPS, 1916 -VZEROALL, 1919 -VZEROUPPER, 1921 -WAIT, 1923 -FWAIT, 1923 -WBINVD, 1924 -WRFSBASE, 1926 -WRGSBASE, 1926 -WRMSR, 1928 -WRPKRU, 1930 -XACQUIRE, 1931 -XRELEASE, 1931 -XABORT, 1935 -XADD, 1937 -XBEGIN, 1939 -XCHG, 1942 -XEND, 1944 -XGETBV, 1946 -XLAT, 1948 -XLATB, 1948 -XOR, 1950 -XORPD, 1952 -VXORPD, 1952 -XORPS, 1955 -VXORPS, 1955 -XRSTOR, 1958 -XRSTOR64, 1958 -XSTORS, 1962 -XSTORS64, 1962 -XSAVE, 1966 -XSAVE64, 1966 -XSAVEC, 1969 -XSAVEC64, 1969 -XSAVEOPT, 1972 -XSAVEOPT64, 1972 -XSAVES, 1975 -XSAVES64, 1975 -XSETBV, 1978 -XTEST, 1980 -@AMD64_ProgrammersManual_vol3.pdf [AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions, Rev 3.26 May 2018 (24594)] -BLCFILL, 127 -BLCI, 129 -BLCIC, 131 -BLCMSK, 133 -BLCS, 135 -BLSIC, 141 -CLZERO, 179 -LLWPCB, 243 -LOOPNZ, 248 -LOOPZ, 248 -LWPINS, 250 -LWPVAL, 252 -MONITORX, 258 -MWAITX, 284 -PREFETCH, 309 -SLWPCB, 362 -T1MSKC, 370 -TZMSK, 376 -UD0, 378 -UD1, 378 -UD2, 378 -CLGI, 394 -INVLPGA, 404 -SKINIT, 443 -STGI, 451 -VMLOAD, 470 -VMMCALL, 472 -VMRUN, 473 -VMSAVE, 478 -@AMD64_ProgrammersManual_vol4.pdf [AMD64 Architecture Programmer's Manual Volume 4: 128-Bit and 256-Bit Media Instructions, Rev 3.23 Feb 2019 (26568)] +CBW, 241 +CWDE, 241 +CDQE, 241 +CLAC, 242 +CLC, 243 +CLD, 244 +CLDEMOTE, 245 +CLFLUSH, 247 +CLFLUSHOPT, 249 +CLI, 251 +CLRSBSY, 253 +CLTS, 255 +CLWB, 256 +CMC, 258 +CMOV, 259 +CMOVA, 259 +CMOVAE, 259 +CMOVB, 259 +CMOVBE, 259 +CMOVC, 259 +CMOVE, 259 +CMOVG, 259 +CMOVGE, 259 +CMOVL, 259 +CMOVLE, 259 +CMOVNA, 259 +CMOVNAE, 259 +CMOVNB, 259 +CMOVNBE, 259 +CMOVNC, 259 +CMOVNE, 259 +CMOVNG, 259 +CMOVNGE, 259 +CMOVNL, 259 +CMOVNLE, 259 +CMOVNO, 259 +CMOVNP, 259 +CMOVNS, 259 +CMOVNZ, 259 +CMOVO, 259 +CMOVP, 259 +CMOVPE, 259 +CMOVPO, 259 +CMOVS, 259 +CMOVZ, 259 +CMP, 263 +CMPPD, 265 +VCMPPD, 265 +CMPEQPD, 267 +CMPLTPD, 267 +CMPLEPD, 267 +CMPUNORDPD, 267 +CMPNEQPD, 267 +CMPNLTPD, 267 +CMPNLEPD, 267 +CMPORDPD, 267 +VCMPEQPD, 268 +VCMPLTPD, 268 +VCMPLEPD, 268 +VCMPUNORDPD, 268 +VCMPNEPD, 268 +VCMPNLTPD, 268 +VCMPNLEPD, 268 +VCMPORDPD, 268 +VCMPEQ_UQPD, 268 +VCMPNGEPD, 268 +VCMPNGTPD, 268 +VCMPFALSEPD, 268 +VCMPNEQ_OQPD, 268 +VCMPGEPD, 268 +VCMPGTPD, 268 +VCMPTRUEPD, 268 +VCMPEQ_OSPD, 268 +VCMPLT_OQPD, 268 +VCMPLE_OQPD, 268 +VCMPUNORD_SPD, 268 +VCMPNEQ_USPD, 268 +VCMPNLT_UQPD, 268 +VCMPNLE_UQPD, 268 +VCMPORD_SPD, 268 +VCMPEQ_USPD, 268 +VCMPNGE_UQPD, 268 +VCMPNGT_UQPD, 268 +VCMPFALSE_OSPD, 268 +VCMPNEQ_OSPD, 268 +VCMPGE_OQPD, 268 +VCMPGT_OQPD, 268 +VCMPTRUE_USPD, 268 +CMPPS, 272 +VCMPPS, 272 +CMPEQPS, 273 +CMPLTPS, 273 +CMPLEPS, 273 +CMPUNORDPS, 273 +CMPNEQPS, 273 +CMPNLTPS, 273 +CMPNLEPS, 273 +CMPORDPS, 273 +VCMPEQPS, 274 +VCMPLTPS, 274 +VCMPLEPS, 274 +VCMPUNORDPS, 274 +VCMPNEQPS, 274 +VCMPNLTPS, 274 +VCMPNLEPS, 274 +VCMPORDPS, 274 +VCMPEQ_UQPS, 274 +VCMPNGEPS, 274 +VCMPNGTPS, 274 +VCMPFALSEPS, 274 +VCMPNEQ_OQPS, 274 +VCMPGEPS, 274 +VCMPGTPS, 274 +VCMPTRUEPS, 274 +VCMPEQ_OSPS, 274 +VCMPLT_OQPS, 274 +VCMPLE_OQPS, 274 +VCMPUNORD_SPS, 274 +VCMPNEQ_USPS, 274 +VCMPNLT_UQPS, 274 +VCMPNLE_UQPS, 274 +VCMPORD_SPS, 274 +VCMPEQ_USPS, 274 +VCMPNGE_UQPS, 274 +VCMPNGT_UQPS, 274 +VCMPFALSE_OSPS, 274 +VCMPNEQ_OSPS, 274 +VCMPGE_OQPS, 274 +VCMPGT_OQPS, 274 +VCMPTRUE_USPS, 274 +CMPS, 279 +CMPSB, 279 +CMPSW, 279 +CMPSQ, 279 +CMPSD, 283 +VCMPSD, 283 +CMPEQSD, 284 +CMPLTSD, 284 +CMPLESD, 284 +CMPUNORDSD, 284 +CMPNEQSD, 284 +CMPNLTSD, 284 +CMPNLESD, 284 +CMPORDSD, 284 +VCMPEQSD, 284 +VCMPLTSD, 284 +VCMPLESD, 284 +VCMPUNORDSD, 284 +VCMPNEQSD, 284 +VCMPNLTSD, 284 +VCMPNLESD, 284 +VCMPORDSD, 284 +VCMPEQ_UQSD, 284 +VCMPNGESD, 284 +VCMPNGTSD, 284 +VCMPFALSESD, 284 +VCMPNEQ_OQSD, 284 +VCMPGESD, 284 +VCMPGTSD, 285 +VCMPTRUESD, 285 +VCMPEQ_OSSD, 285 +VCMPLT_OQSD, 285 +VCMPLE_OQSD, 285 +VCMPUNORD_SSD, 285 +VCMPNEQ_USSD, 285 +VCMPNLT_UQSD, 285 +VCMPNLE_UQSD, 285 +VCMPORD_SSD, 285 +VCMPEQ_USSD, 285 +VCMPNGE_UQSD, 285 +VCMPNGT_UQSD, 285 +VCMPFALSE_OSSD, 285 +VCMPNEQ_OSSD, 285 +VCMPGE_OQSD, 285 +VCMPGT_OQSD, 285 +VCMPTRUE_USSD, 285 +CMPSS, 287 +VCMPSS, 287 +CMPEQSS, 288 +CMPLTSS, 288 +CMPLESS, 288 +CMPUNORDSS, 288 +CMPNEQSS, 288 +CMPNLTSS, 288 +CMPNLESS, 288 +CMPORDSS, 288 +VCMPEQSS, 288 +VCMPLTSS, 288 +VCMPLESS, 288 +VCMPUNORDSS, 288 +VCMPNEQSS, 288 +VCMPNLTSS, 288 +VCMPNLESS, 288 +VCMPORDSS, 288 +VCMPEQ_UQSS, 288 +VCMPNGESS, 288 +VCMPNGTSS, 288 +VCMPFALSESS, 288 +VCMPNEQ_OQSS, 288 +VCMPGESS, 288 +VCMPGTSS, 289 +VCMPTRUESS, 289 +VCMPEQ_OSSS, 289 +VCMPLT_OQSS, 289 +VCMPLE_OQSS, 289 +VCMPUNORD_SSS, 289 +VCMPNEQ_USSS, 289 +VCMPNLT_UQSS, 289 +VCMPNLE_UQSS, 289 +VCMPORD_SSS, 289 +VCMPEQ_USSS, 289 +VCMPNGE_UQSS, 289 +VCMPNGT_UQSS, 289 +VCMPFALSE_OSSS, 289 +VCMPNEQ_OSSS, 289 +VCMPGE_OQSS, 289 +VCMPGT_OQSS, 289 +VCMPTRUE_USSS, 289 +CMPXCHG, 291 +CMPXCHG8B, 293 +CMPXCHG16B, 293 +COMISD, 296 +VCOMISD, 296 +COMISS, 298 +VCOMISS, 298 +CPUID, 300 +CRC32, 339 +CVTDQ2PD, 342 +VCVTDQ2PD, 342 +CVTDQ2PS, 346 +VCVTDQ2PS, 346 +CVTPD2DQ, 349 +VCVTPD2DQ, 349 +CVTPD2PI, 353 +CVTPD2PS, 354 +VCVTPD2PS, 354 +CVTPI2PD, 358 +CVTPI2PS, 359 +CVTPS2DQ, 360 +VCVTPS2DQ, 360 +CVTPS2PD, 363 +VCVTPS2PD, 363 +CVTPS2PI, 366 +CVTSD2SI, 367 +VCVTSD2SI, 367 +CVTSD2SS, 369 +VCVTSD2SS, 369 +CVTSI2SD, 371 +VCVTSI2SD, 371 +CVTSI2SS, 373 +VCVTSI2SS, 373 +CVTSS2SD, 375 +VCVTSS2SD, 375 +CVTSS2SI, 377 +VCVTSS2SI, 377 +CVTTPD2DQ, 379 +VCVTTPD2DQ, 379 +CVTTPD2PI, 383 +CVTTPS2DQ, 384 +VCVTTPS2DQ, 384 +CVTTPS2PI, 387 +CVTTSD2SI, 388 +VCVTTSD2SI, 388 +CVTTSS2SI, 390 +VCVTTSS2SI, 390 +CWD, 392 +CDQ, 392 +CQO, 392 +DAA, 393 +DAS, 395 +DEC, 397 +DIV, 399 +DIVPD, 402 +VDIVPD, 402 +DIVPS, 405 +VDIVPS, 405 +DIVSD, 408 +VDIVSD, 408 +DIVSS, 410 +VDIVSS, 410 +DPPD, 412 +VDPPD, 412 +DPPS, 414 +VDPPS, 414 +EMMS, 417 +ENTER, 420 +EXTRACTPS, 423 +VEXTRACTPS, 423 +F2XM1, 425 +FABS, 427 +FADD, 428 +FADDP, 428 +FIADD, 428 +FBLD, 431 +FBSTP, 433 +FCHS, 435 +FCLEX, 437 +FNCLEX, 437 +FCMOV, 439 +FCMOVB, 439 +FCMOVE, 439 +FCMOVBE, 439 +FCMOVU, 439 +FCMOVNB, 439 +FCMOVNE, 439 +FCMOVNBE, 439 +FCMOVNU, 439 +FCOM, 441 +FCOMP, 441 +FCOMPP, 441 +FCOMI, 444 +FCOMIP, 444 +FUCOMI, 444 +FUCOMIP, 444 +FCOS, 447 +FDECSTP, 449 +FDIV, 450 +FDIVP, 450 +FIDIV, 450 +FDIVR, 453 +FDIVRP, 453 +FIDIVR, 453 +FFREE, 456 +FICOM, 456 +FICOMP, 457 +FILD, 459 +FINCSTP, 461 +FINIT, 462 +FNINIT, 462 +FIST, 464 +FISTP, 464 +FISTTP, 467 +FLD, 469 +FLD1, 471 +FLDL2T, 471 +FLDL2E, 471 +FLDPI, 471 +FLDLG2, 471 +FLDLN2, 471 +FLDZ, 471 +FLDCW, 473 +FLDENV, 475 +FMUL, 477 +FMULP, 477 +FIMUL, 477 +FNOP, 480 +FPATAN, 481 +FPREM, 483 +FPREM1, 485 +FPTAN, 487 +FRNDINT, 489 +FRSTOR, 490 +FSAVE, 492 +FNSAVE, 492 +FSCALE, 495 +FSIN, 497 +FSINCOS, 499 +FSQRT, 501 +FST, 503 +FSTP, 503 +FSTCW, 505 +FNSTCW, 505 +FSTENV, 507 +FNSTENV, 507 +FSTSW, 509 +FNSTSW, 509 +FSUB, 511 +FSUBP, 511 +FISUB, 511 +FSUBR, 514 +FSUBRP, 514 +FISUBR, 514 +FTST, 517 +FUCOM, 519 +FUCOMP, 519 +FUCOMPP, 519 +FXAM, 522 +FXCH, 524 +FXRSTOR, 526 +FXRSTOR64, 526 +FXSAVE, 529 +FXSAVE64, 529 +FXTRACT, 537 +FYL2X, 539 +FYL2XP1, 541 +GF2P8AFFINEINVQB, 543 +GF2P8AFFINEQB, 546 +GF2P8MULB, 548 +HADDPD, 550 +VHADDPD, 550 +HADDPS, 553 +VHADDPS, 553 +HLT, 556 +HSUBPD, 557 +VHSUBPD, 557 +HSUBPS, 560 +VHSUBPS, 560 +IDIV, 563 +IMUL, 566 +IN, 570 +INC, 572 +INCSSPD, 574 +INCSSPQ, 574 +INS, 576 +INSB, 576 +INSW, 576 +INSD, 576 +INSERTPS, 579 +VINSERTPS, 579 +INT, 582 +INTO, 582 +INT3, 582 +INVD, 597 +INVLPG, 599 +INVPCID, 601 +IRET, 604 +IRETD, 604 +IRETQ, 604 +J, 613 +JA, 613 +JAE, 613 +JB, 613 +JBE, 613 +JC, 613 +JCXZ, 613 +JECXZ, 613 +JRCXZ, 613 +JE, 613 +JG, 613 +JGE, 613 +JL, 613 +JLE, 613 +JNA, 613 +JNAE, 613 +JNB, 613 +JNBE, 613 +JNC, 613 +JNE, 613 +JNG, 613 +JNGE, 613 +JNL, 613 +JNLE, 613 +JNO, 613 +JNP, 613 +JNS, 613 +JNZ, 613 +JO, 613 +JP, 613 +JPE, 613 +JPO, 613 +JS, 613 +JZ, 613 +JMP, 618 +KADDW, 627 +KADDB, 627 +KADDQ, 627 +KADDD, 627 +KANDW, 628 +KANDB, 628 +KANDQ, 628 +KANDD, 628 +KANDNW, 629 +KANDNB, 629 +KANDNQ, 629 +KANDND, 629 +KMOVW, 630 +KMOVB, 630 +KMOVQ, 630 +KMOVD, 630 +KNOTW, 632 +KNOTB, 632 +KNOTQ, 632 +KNOTD, 632 +KORW, 633 +KORB, 633 +KORQ, 633 +KORD, 633 +KORTESTW, 634 +KORTESTB, 634 +KORTESTQ, 634 +KORTESTD, 634 +KSHIFTLW, 636 +KSHIFTLB, 636 +KSHIFTLQ, 636 +KSHIFTLD, 636 +KSHIFTRW, 638 +KSHIFTRB, 638 +KSHIFTRQ, 638 +KSHIFTRD, 638 +KTESTW, 640 +KTESTB, 640 +KTESTQ, 640 +KTESTD, 640 +KUNPCKBW, 642 +KUNPCKWD, 642 +KUNPCKDQ, 642 +KXNORW, 643 +KXNORB, 643 +KXNORQ, 643 +KXNORD, 643 +KXORW, 644 +KXORB, 644 +KXORQ, 644 +KXORD, 644 +LAHF, 645 +LAR, 646 +LDDQU, 649 +VLDDQU, 649 +LDMXCSR, 651 +VLDMXCSR, 651 +LDS, 652 +LES, 652 +LFS, 652 +LGS, 652 +LSS, 652 +LEA, 656 +LEAVE, 658 +LFENCE, 660 +LGDT, 661 +LIDT, 661 +LLDT, 664 +LMSW, 666 +LOCK, 668 +LODS, 670 +LODSB, 670 +LODSW, 670 +LODSD, 670 +LODSQ, 670 +LOOP, 673 +LOOPE, 673 +LOOPNE, 673 +LSL, 675 +LTR, 678 +LZCNT, 680 +MASKMOVDQU, 690 +VMASKMOVDQU, 690 +MASKMOVQ, 692 +MAXPD, 694 +VMAXPD, 694 +MAXPS, 697 +VMAXPS, 697 +MAXSD, 700 +VMAXSD, 700 +MAXSS, 702 +VMAXSS, 702 +MFENCE, 704 +MINPD, 705 +VMINPD, 705 +MINPS, 708 +VMINPS, 708 +MINSD, 711 +VMINSD, 711 +MINSS, 713 +VMINSS, 713 +MONITOR, 715 +MOV, 717 +MOVAPD, 727 +VMOVPAD, 727 +MOVAPS, 731 +VMOVAPS, 731 +MOVBE, 735 +MOVD, 737 +VMOVD, 737 +MOVQ, 737 +VMOVQ, 737 +MOVDDUP, 741 +VMOVDDUP, 741 +MOVDIRI, 744 +MOVDIR64B, 746 +MOVDQA, 748 +VMOVDQA, 748 +VMOVDQA32, 748 +VMOVDQA64, 748 +MOVDQU, 753 +VMOVDQU, 753 +VMOVDQU8, 753 +VMOVDQU16, 753 +VMOVDQU32, 753 +VMOVDQU64, 753 +MOVDQ2Q, 761 +MOVHLPS, 762 +VMOVHLPS, 762 +MOVHPD, 764 +VMOVHPD, 764 +MOVHPS, 766 +VMOVHPS, 766 +MOVLHPS, 768 +VMOVLHPS, 768 +MOVLPD, 770 +VMOVLPD, 770 +MOVLPS, 772 +VMOVLPS, 772 +MOVMSKPD, 774 +VMOVMSKPD, 774 +MOVMSKPS, 776 +VMOVMSKPS, 776 +MOVNTDQA, 778 +VMOVNTDQA, 778 +MOVNTDQ, 780 +VMOVNTDQ, 780 +MOVNTI, 782 +MOVNTPD, 784 +VMOVNTPD, 784 +MOVNTPS, 786 +VMOVNTPS, 786 +MOVNTQ, 788 +MOVQ, 789 +VMOVQ, 789 +MOVQ2DQ, 792 +MOVS, 793 +MOVSB, 793 +MOVSW, 793 +MOVSQ, 793 +MOVSD, 797 +VMOVSD, 797 +MOVSHDUP, 800 +VMOVSHDUP, 800 +MOVSLDUP, 803 +VMOVSLDUP, 803 +MOVSS, 806 +VMOVSS, 806 +MOVSX, 810 +MOVSXD, 810 +MOVUPD, 812 +VMOVUPD, 812 +MOVUPS, 816 +VMOVUPS, 816 +MOVZX, 820 +MPSADBW, 822 +VMPSADBW, 822 +MUL, 830 +MULPD, 832 +VMULPD, 832 +MULPS, 835 +VMULPS, 835 +MULSD, 838 +VMULSD, 838 +MULSS, 840 +VMULSS, 840 +MULX, 842 +MWAIT, 844 +NEG, 847 +NOP, 849 +NOT, 850 +OR, 852 +ORPD, 854 +VORPD, 854 +ORPS, 857 +VORPS, 857 +OUT, 860 +OUTS, 862 +OUTSB, 862 +OUTSW, 862 +OUTSD, 862 +PABSB, 866 +VPABSB, 866 +PABSW, 866 +VPABSW, 866 +PABSD, 866 +VPABSD, 866 +PABSQ, 866 +VPABSQ, 866 +PACKSSWB, 872 +VPACKSSWB, 872 +PACKSSDW, 872 +VPACKSSDW, 872 +PACKUSDW, 880 +VPACKUSDW, 880 +PACKUSWB, 885 +VPACKUSWB, 885 +PADDB, 890 +VPADDB, 890 +PADDW, 890 +VPADDW, 890 +PADDD, 890 +VPADDD, 890 +PADDQ, 890 +VPADDQ, 890 +PADDSB, 897 +VPADDSB, 897 +PADDSW, 897 +VPADDSW, 897 +PADDUSB, 901 +VPADDUSB, 901 +PADDUSW, 901 +VPADDUSW, 901 +PALIGNR, 905 +VPALIGNR, 905 +PAND, 909 +VPAND, 909 +VPANDD, 909 +VPANDQ, 909 +PANDN, 912 +VPANDN, 912 +VPANDND, 912 +VPANDNQ, 912 +PAUSE, 915 +PAVGB, 916 +VPAVGB, 916 +PAVGW, 916 +VPAVGW, 916 +PBLENDVB, 920 +VPBLENDVB, 920 +PBLENDW, 924 +VPBLENDW, 924 +PCLMULQDQ, 927 +VPCLMULQDQ, 927 +PCMPEQB, 930 +VPCMPEQB, 930 +PCMPEQW, 930 +VPCMPEQW, 930 +PCMPEQD, 930 +VPCMPEQD, 930 +PCMPEQQ, 936 +VPCMPEQQ, 936 +PCMPESTRI, 939 +VPCMPESTRI, 939 +PCMPESTRM, 941 +VPCMPESTRM, 941 +PCMPGTB, 943 +VPCMPGTB, 943 +PCMPGTW, 943 +VPCMPGTW, 943 +PCMPGTD, 943 +VPCMPGTD, 943 +PCMPGTQ, 949 +VPCMPGTQ, 949 +PCMPISTRI, 952 +VPCMPISTRI, 952 +PCMPISTRM, 954 +VPCMPISTRM, 954 +PDEP, 956 +PEXT, 958 +PEXTRB, 960 +VPEXTRB, 960 +PEXTRD, 960 +VPEXTRD, 960 +PEXTRQ, 960 +VPEXTRQ, 960 +PEXTRW, 963 +VPEXTRW, 963 +PHADDW, 966 +VPHADDW, 966 +PHADDD, 966 +VPHADDD, 966 +PHADDSW, 970 +VPHADDSW, 970 +PHMINPOSUW, 972 +VPHMINPOSUW, 972 +PHSUBW, 974 +VPHSUBW, 974 +PHSUBD, 974 +PHSUBSW, 977 +VPHSUBSW, 977 +PINSRB, 979 +VPINSRB, 979 +PINSRD, 979 +VPINSRD, 979 +PINSRQ, 979 +VPINSRQ, 979 +PINSRW, 982 +VPINSRW, 982 +PMADDUBSW, 984 +VPMADDUBSW, 984 +PMADDWD, 987 +VPMADDWD, 987 +PMAXSB, 990 +VPMAXSB, 990 +PMAXSW, 990 +VPMAXSW, 990 +PMAXSD, 990 +VPMAXSD, 990 +PMAXSQ, 990 +VPMAXSQ, 990 +PMAXUB, 997 +VPMAXUB, 997 +PMAXUW, 997 +VPMAXUW, 997 +PMAXUD, 1002 +VPMAXUD, 1002 +PMAXUQ, 1002 +VPMAXUQ, 1002 +PMINSB, 1006 +VPMINSB, 1006 +PMINSW, 1006 +VPMINSW, 1006 +PMINSD, 1011 +VPMINSD, 1011 +PMINSQ, 1011 +VPMINSQ, 1011 +PMINUB, 1015 +VPMINUB, 1015 +PMINUW, 1015 +VPMINUW, 1015 +PMINUD, 1020 +VPMINUD, 1020 +PMINUQ, 1020 +VPMINUQ, 1020 +PMOVMSKB, 1024 +VPMOVMSKB, 1024 +PMOVSX, 1026 +PMOVSXBW, 1026 +VPMOVSXBW, 1026 +PMOVSXBD, 1026 +VPMOVSXBD, 1026 +PMOVSXBQ, 1026 +VPMOVSXBQ, 1026 +PMOVSXWD, 1026 +VPMOVSXWD, 1026 +PMOVSXWQ, 1026 +VPMOVSXWQ, 1026 +PMOVSXDQ, 1026 +VPMOVSXDQ, 1026 +PMOVZX, 1035 +PMOVZXBW, 1035 +VPMOVZXBW, 1035 +PMOVZXBD, 1035 +VPMOVZXBD, 1035 +PMOVZXBQ, 1035 +VPMOVZXBQ, 1035 +PMOVZXWD, 1035 +VPMOVZXWD, 1035 +PMOVZXWQ, 1035 +VPMOVZXWQ, 1035 +PMOVZXDQ, 1035 +VPMOVZXDQ, 1035 +PMULDQ, 1044 +VPMULDQ, 1044 +PMULHRSW, 1047 +VPMULHRSW, 1047 +PMULHUW, 1051 +VPMULHUW, 1051 +PMULHW, 1055 +VPMULHW, 1055 +PMULLD, 1059 +VPMULLD, 1059 +PMULLQ, 1059 +VPMULLQ, 1059 +PMULLW, 1063 +VPMULLW, 1063 +PMULUDQ, 1067 +VPMULUDQ, 1067 +POP, 1070 +POPA, 1075 +POPAD, 1075 +POPCNT, 1077 +POPF, 1079 +POPFD, 1079 +POPFQ, 1079 +POR, 1083 +PREFETCHT0, 1086 +PREFETCHT1, 1086 +PREFETCHT2, 1086 +PREFETCHNTA, 1086 +PREFETCHW, 1088 +PREFETCHWT1, 2090 +PSADBW, 1090 +VPSADBW, 1090 +PSHUFB, 1094 +VPSHUFB, 1094 +PSHUFD, 1098 +VPSHUFD, 1098 +PSHUFHW, 1102 +VPSHUFHW, 1102 +PSHUFLW, 1105 +VPSHUFLW, 1105 +PSHUFW, 1108 +PSIGNB, 1109 +VPSIGNB, 1109 +PSIGNW, 1109 +VPSIGNW, 1109 +PSIGND, 1109 +VPSIGND, 1109 +PSLLDQ, 1113 +VPSLLDQ, 1113 +PSLLW, 1115 +VPSLLW, 1115 +PSLLD, 1115 +VPSLLD, 1115 +PSLLQ, 1115 +VPSLLQ, 1115 +PSRAW, 1127 +VPSRAW, 1127 +PSRAD, 1127 +VPSRAD, 1127 +VPSRAQ, 1127 +PSRLDQ, 1137 +VPSRLDQ, 1137 +PSRLW, 1139 +VPSRLW, 1139 +PSRLD, 1139 +VPSRLD, 1139 +PSRLQ, 1139 +VPSRLQ, 1139 +PSUBB, 1151 +VPSUBB, 1151 +PSUBW, 1151 +VPSUBW, 1151 +PSUBD, 1151 +VPSUBD, 1151 +PSUBQ, 1158 +VPSUBQ, 1158 +PSUBSB, 1161 +VPSUBSB, 1161 +PSUBSW, 1161 +VPSUBSW, 1161 +PSUBUSB, 1165 +VPSUBUSB, 1165 +PSUBUSW, 1165 +VPSUBUSW, 1165 +PTEST, 1169 +VPTEST, 1169 +PTWRITE, 1171 +PUNPCKHBW, 1173 +VPUNPCKHBW, 1173 +PUNPCKHWD, 1173 +VPUNPCKHWD, 1173 +PUNPCKHDQ, 1173 +VPUNPCKHDQ, 1173 +PUNPCKHQDQ, 1173 +VPUNPCKHQDQ, 1173 +PUNPCKLBW, 1183 +VPUNPCKLBW, 1183 +PUNPCKLWD, 1183 +VPUNPCKLWD, 1183 +PUNPCKLDQ, 1183 +VPUNPCKLDQ, 1183 +PUNPCKLQDQ, 1183 +VPUNPCKLQDQ, 1183 +PUSH, 1193 +PUSHA, 1196 +PUSHAD, 1196 +PUSHF, 1198 +PUSHFD, 1198 +PUSHFQ, 1198 +PXOR, 1200 +VPXOR, 1200 +VPXORD, 1200 +VPXORQ, 1200 +RCL, 1203 +RCR, 1203 +ROL, 1203 +ROR, 1203 +RCPPS, 1208 +VRCPPS, 1208 +RCPSS, 1210 +VRCPSS, 1210 +RDFSBASE, 1212 +RDGSBASE, 1212 +RDMSR, 1214 +RDPID, 1216 +RDPKRU, 1217 +RDPMC, 1219 +RDRAND, 1221 +RDSEED, 1223 +RDSSPD, 1225 +RDSSPQ, 1225 +RDTSC, 1227 +RDTSCP, 1229 +REP, 1231 +REPE, 1231 +REPZ, 1231 +REPNE, 1231 +REPNZ, 1231 +RET, 1235 +RORX, 1248 +ROUNDPD, 1249 +VROUNDPD, 1249 +ROUNDPS, 1252 +VROUNDPS, 1252 +ROUNDSD, 1255 +VROUNDSD, 1255 +ROUNDSS, 1257 +VROUNDSS, 1257 +RSM, 1259 +RSQRTPS, 1261 +VRSQRTPS, 1261 +RSQRTSS, 1263 +VRSQRTSS, 1263 +RSTORSSP, 1265 +SAHF, 1268 +SAL, 1270 +SAR, 1270 +SHL, 1270 +SHR, 1270 +SARX, 1275 +SHLX, 1275 +SHRX, 1275 +SBB, 1279 +SCAS, 1282 +SCASB, 1282 +SCASW, 1282 +SCASD, 1282 +SCASQ, 1282 +SET, 1286 +SETA, 1286 +SETAE, 1286 +SETB, 1286 +SETBE, 1286 +SETC, 1286 +SETE, 1286 +SETG, 1286 +SETGE, 1286 +SETL, 1286 +SETLE, 1286 +SETNA, 1286 +SETNAE, 1286 +SETNB, 1286 +SETNBE, 1286 +SETNC, 1286 +SETNE, 1286 +SETNG, 1286 +SETNGE, 1286 +SETNL, 1286 +SETNLE, 1286 +SETNO, 1286 +SETNP, 1286 +SETNS, 1286 +SETNZ, 1286 +SETO, 1286 +SETP, 1286 +SETPE, 1286 +SETPO, 1286 +SETS, 1286 +SETZ, 1286 +SETSSBSY, 1289 +SFENCE, 1291 +SGDT, 1292 +SHA1RNDS4, 1294 +SHA1NEXTE, 1296 +SHA1MSG1, 1297 +SHA1MSG2, 1298 +SHA256RNDS2, 1299 +SHA256MSG1, 1301 +SHA256MSG2, 1302 +SHLD, 1303 +SHRD, 1306 +SHUFPD, 1309 +VSHUFPD, 1309 +SHUFPS, 1314 +VSHUFPS, 1314 +SIDT, 1318 +SLDT, 1320 +SMSW, 1322 +SQRTPD, 1324 +VSQRTPD, 1324 +SQRTPS, 1327 +VSQRTPS, 1327 +SQRTSD, 1330 +VSQRTSD, 1330 +SQRTSS, 1332 +VSQRTSS, 1332 +STAC, 1334 +STC, 1335 +STD, 1336 +STI, 1337 +STMXCSR, 1339 +STOS, 1340 +STOSB, 1340 +STOSW, 1340 +STOSD, 1340 +STOSQ, 1340 +STR, 1344 +SUB, 1346 +SUBPD, 1348 +VSUBPD, 1348 +SUBPS, 1351 +VSUBPS, 1351 +SUBSD, 1354 +VSUBSD, 1354 +SUBSS, 1356 +VSUBSS, 1356 +SWAPGS, 1358 +SYSCALL, 1360 +SYSENTER, 1363 +SYSEXIT, 1366 +SYSRET, 1369 +TEST, 1372 +TPAUSE, 1374 +TZCNT, 1376 +UCOMISD, 1378 +VUCOMISD, 1378 +UCOMISS, 1380 +VUCOMISS, 1380 +UD0, 1382 +UD1, 1382 +UD2, 1382 +UMONITOR, 1383 +UMWAIT, 1385 +UNPCKHPD, 1387 +VUNPCKHPD, 1387 +UNPCKHPS, 1391 +VUNPCKHPS, 1391 +UNPCKLPD, 1395 +VUNPCKLPD, 1395 +UNPCKLPS, 1399 +VUNPCKLPS, 1399 +VALIGND, 1407 +VALIGNQ, 1407 +VBLENDMPD, 1411 +VBLENDMPS, 1411 +VBROADCAST, 1414 +VBROADCASTSS, 1414 +VBROADCASTSD, 1414 +VBROADCASTF128, 1414 +VBROADCASTF32X2, 1414 +VBROADCASTF32X4, 1414 +VBROADCASTF64X2, 1414 +VBROADCASTF32X8, 1414 +VBROADCASTF64X4, 1414 +VCOMPRESSPD, 1422 +VCOMPRESSPS, 1424 +VCVTPD2QQ, 1426 +VCVTPD2UDQ, 1429 +VCVTPD2UQQ, 1432 +VCVTPH2PS, 1435 +VCVTPS2PH, 1438 +VCVTPS2UDQ, 1442 +VCVTPS2QQ, 1445 +VCVTPS2UQQ, 1448 +VCVTQQ2PD, 1451 +VCVTQQ2PS, 1453 +VCVTSD2USI, 1455 +VCVTSS2USI, 1456 +VCVTTPD2QQ, 1458 +VCVTTPD2UDQ, 1460 +VCVTTPD2UQQ, 1463 +VCVTTPS2UDQ, 1465 +VCVTTPS2QQ, 1467 +VCVTTPS2UQQ, 1469 +VCVTTSD2USI, 1471 +VCVTTSS2USI, 1472 +VCVTUDQ2PD, 1474 +VCVTUDQ2PS, 1476 +VCVTUQQ2PD, 1478 +VCVTUQQ2PS, 1480 +VCVTUSI2SD, 1482 +VCVTUSI2SS, 1484 +VDBPSADBW, 1486 +VEXPANDPD, 1490 +VEXPANDPS, 1492 +VERR, 1494 +VERW, 1494 +VEXP2PD, 2096 +VEXP2PS, 2098 +VEXTRACTF128, 1496 +VEXTRACTF32X4, 1496 +VEXTRACTF64X2, 1496 +VEXTRACTF32X8, 1496 +VEXTRACTF64X4, 1496 +VEXTRACTI128, 1502 +VEXTRACTI32X4, 1502 +VEXTRACTI64X2, 1502 +VEXTRACTI32X8, 1502 +VEXTRACTI64X4, 1502 +VFIXUPIMMPD, 1508 +VFIXUPIMMPS, 1512 +VFIXUPIMMSD, 1516 +VFIXUPIMMSS, 1519 +VFMADD132PD, 1522 +VFMADD213PD, 1522 +VFMADD231PD, 1522 +VFMADD132PS, 1529 +VFMADD213PS, 1529 +VFMADD231PS, 1529 +VFMADD132SD, 1536 +VFMADD213SD, 1536 +VFMADD231SD, 1536 +VFMADD132SS, 1539 +VFMADD213SS, 1539 +VFMADD231SS, 1539 +VFMADDSUB132PD, 1542 +VFMADDSUB213PD, 1542 +VFMADDSUB231PD, 1542 +VFMADDSUB132PS, 1552 +VFMADDSUB213PS, 1552 +VFMADDSUB231PS, 1552 +VFMSUBADD132PD, 1561 +VFMSUBADD213PD, 1561 +VFMSUBADD231PD, 1561 +VFMSUBADD132PS, 1571 +VFMSUBADD213PS, 1571 +VFMSUBADD231PS, 1571 +VFMSUB132PD, 1581 +VFMSUB213PD, 1581 +VFMSUB231PD, 1581 +VFMSUB132PS, 1588 +VFMSUB213PS, 1588 +VFMSUB231PS, 1588 +VFMSUB132SD, 1595 +VFMSUB213SD, 1595 +VFMSUB231SD, 1595 +VFMSUB132SS, 1598 +VFMSUB213SS, 1598 +VFMSUB231SS, 1598 +VFNMADD132PD, 1601 +VFNMADD213PD, 1601 +VFNMADD231PD, 1601 +VFNMADD132PS, 1608 +VFNMADD213PS, 1608 +VFNMADD231PS, 1608 +VFNMADD132SD, 1614 +VFNMADD213SD, 1614 +VFNMADD231SD, 1614 +VFNMADD132SS, 1617 +VFNMADD213SS, 1617 +VFNMADD231SS, 1617 +VFNMSUB132PD, 1620 +VFNMSUB213PD, 1620 +VFNMSUB231PD, 1620 +VFNMSUB132PS, 1626 +VFNMSUB213PS, 1626 +VFNMSUB231PS, 1626 +VFNMSUB132SD, 1632 +VFNMSUB213SD, 1632 +VFNMSUB231SD, 1632 +VFNMSUB132SS, 1635 +VFNMSUB213SS, 1635 +VFNMSUB231SS, 1635 +VFPCLASSPD, 1638 +VFPCLASSPS, 1641 +VFPCLASSSD, 1643 +VFPCLASSSS, 1645 +VGATHERDPD, 1647 +VGATHERQPD, 1647 +VGATHERDPS, 1652 +VGATHERQPS, 1652 +VGATHERPFODPS, 2100 +VGATHERPFOQPS, 2100 +VGATHERPFODPD, 2100 +VGATHERPFOQPD, 2100 +VGATHERPF1DPS, 2102 +VGATHERPF1QPS, 2102 +VGATHERPF1DPD, 2102 +VGATHERPF1QPD, 2102 +VGETEXPPD, 1663 +VGETEXPPS, 1666 +VGETEXPSD, 1670 +VGETEXPSS, 1672 +VGETMANTPD, 1674 +VGETMANTPS, 1678 +VGETMANTSD, 1681 +VGETMANTSS, 1683 +VINSERTF128, 1685 +VINSERTF32X4, 1685 +VINSERTF64X2, 1685 +VINSERTF32X8, 1685 +VINSERTF64X4, 1685 +VINSERTI128, 1689 +VINSERTI32X4, 1689 +VINSERTI64X2, 1689 +VINSERTI32X8, 1689 +VINSERTI64X4, 1689 +VMASKMOV, 1693 +VMASKMOVPS, 1693 +VMASKMOVPD, 1693 +VBLENDD, 1696 +VPBLENDMB, 1698 +VPBLENDMW, 1698 +VPBLENDMD, 1700 +VPBLENDMQ, 1700 +VPBROADCASTB, 1703 +VPBROADCASTW, 1703 +VPBROADCASTD, 1703 +VPBROADCASTQ, 1703 +VPBROADCASTI32X2, 1706 +VPBROADCASTI128, 1706 +VPBROADCASTI32X4, 1706 +VPBROADCASTI64X2, 1706 +VPBROADCASTI32X8, 1706 +VPBROADCASTI64X4, 1706 +VPBROADCASTM, 1715 +VPBROADCASTMB2Q, 1715 +VPBROADCASTMW2D, 1715 +VPCMPB, 1717 +VPCMPUB, 1717 +VPCMPD, 1720 +VPCMPUD, 1720 +VPCMPQ, 1723 +VPCMPUQ, 1723 +VPCMPW, 1726 +VPCMPUW, 1726 +VCOMPRESSB, 1729 +VCOMPRESSW, 1729 +VCOMPRESSD, 1732 +VCOMPRESSQ, 1734 +VPCONFLICTD, 1736 +VPCONFLICTQ, 1736 +VPDPBUSD, 1739 +VPDPBUSDS, 1741 +VPDWSSD, 1743 +VPDPWSSDS, 1745 +VPERM2F128, 1747 +VPERM2I128, 1749 +VPERMB, 1751 +VPERMD, 1753 +VPERMW, 1753 +VPERMI2B, 1756 +VPERMI2W, 1758 +VPERMI2D, 1758 +VPERMI2Q, 1758 +VPERMI2PS, 1758 +VPERMI2PD, 1758 +VPERMILPD, 1764 +VPERMILPS, 1769 +VPERMPD, 1774 +VPERMPS, 1777 +VPERMQ, 1780 +VPERMT2B, 1783 +VPERMT2W, 1785 +VPERMT2D, 1785 +VPERMT2Q, 1785 +VPERMT2PS, 1785 +VPERMT2PD, 1785 +VPEXPANDB, 1790 +VPEXPANDW, 1790 +VEXPANDD, 1793 +VEXPANDQ, 1795 +VPGATHERDD, 1797 +VPGATHERQD, 1797 +VPGATHERDQ, 1804 +VPGATHERQQ, 1804 +VPLZCNTD, 1811 +VPLZCNTQ, 1811 +VPMADD52HUQ, 1814 +VPMADD52LUQ, 1816 +VPMASKMOVD, 1818 +VPMASKMOVQ, 1818 +VPMOVM2B, 1832 +VPMOVM2W, 1832 +VPMOVM2D, 1832 +VPMOVM2Q, 1832 +VPMOVB2M, 1821 +VPMOVW2M, 1821 +VPMOVD2M, 1821 +VPMOVQ2M, 1821 +VPMOVQB, 1835 +VPMOVSQB, 1835 +VPMOVUSQB, 1835 +VPMOVQW, 1843 +VPMOVSQW, 1843 +VPMOVUSQW, 1843 +VPMOVQD, 1839 +VPMOVSQD, 1839 +VPMOVUSQD, 1839 +VPMOVDB, 1824 +VPMOVSDB, 1824 +VPMOVUSDB, 1824 +VPMOVDW, 1828 +VPMOVSDW, 1828 +VPMOVUSDW, 1828 +VPMOVWB, 1847 +VPMOVSWB, 1847 +VPMOVUSWB, 1847 +VPMULTISHIFTQB, 1851 +VPOPCNTB, 1853 +VPOPCNTW, 1853 +VPOPCNTD, 1853 +VPOPCNTQ, 1853 +PROLD, 1856 +VPROLD, 1856 +PROLVD, 1856 +VPROLVD, 1856 +PROLVQ, 1856 +VPROLVQ, 1856 +PRORD, 1861 +VPRORD, 1861 +PRORVD, 1861 +VPRORVD, 1861 +PRORQ, 1861 +VPRORQ, 1861 +PRORVQ, 1861 +VPRORVQ, 1861 +VPSCATTERDD, 1866 +VPSCATTERDQ, 1866 +VPSCATTERQD, 1866 +VPSCATTERQQ, 1866 +VPSHLD, 1870 +VPSHLDW, 1870 +VPSHLDD, 1870 +VPSHLDQ, 1870 +VPSHLDV, 1873 +VPSHLDVW, 1873 +VPSHLDVD, 1873 +VPSHLDVQ, 1873 +VPSHRD, 1876 +VPSHRDW, 1876 +VPSHRDD, 1876 +VPSHRDQ, 1876 +VPSHRDV, 1879 +VPSHRDVW, 1879 +VPSHRDVD, 1879 +VPSHRDVQ, 1879 +VPSHUFBITQMB, 1882 +VPSLLVW, 1883 +VPSLLVD, 1883 +VPSLLVQ, 1883 +VPSRAVW, 1888 +VPSRAVD, 1888 +VPSRAVQ, 1888 +VPSRLVW, 1893 +VPSRLVD, 1893 +VPSRLVQ, 1893 +VPTERNLOGD, 1898 +VPTERNLOGQ, 1898 +VPTESTMB, 1901 +VPTESTMW, 1901 +VPTESTMD, 1901 +VPTESTMQ, 1901 +VPTESTNMB, 1904 +VPTESTNMW, 1904 +VPTESTNMD, 1904 +VPTESTNMQ, 1904 +VRANGEPD, 1908 +VRANGEPS, 1913 +VRANGESD, 1917 +VRANGESS, 1920 +VRCP14PD, 1923 +VRCP14SD, 1925 +VRCP14PS, 1927 +VRCP14SS, 1929 +VRCP28PD, 2108 +VRCP28SD, 2110 +VRCP28PS, 2112 +VRCP28SS, 2114 +VREDUCEPD, 1931 +VREDUCESD, 1934 +VREDUCEPS, 1936 +VREDUCESS, 1938 +VRNDSCALEPD, 1940 +VRNDSCALESD, 1944 +VRNDSCALEPS, 1946 +VRNDSCALESS, 1949 +VRSQRT14PD, 1951 +VRSQRT14SD, 1953 +VRSQRT14PS, 1955 +VRSQRT14SS, 1957 +VRSQRT28PD, 2116 +VRSQRT28SD, 2118 +VRSQRT28PS, 2120 +VRSQRT28SS, 2122 +VSCALEFPD, 1959 +VSCALEFSD, 1962 +VSCALEFPS, 1964 +VSCALEFSS, 1967 +VSCATTERDPS, 1969 +VSCATTERDPD, 1969 +VSCATTERQPS, 1969 +VSCATTERQPD, 1969 +VSCATTERPFODPS, 2124 +VSCATTERPFOQPS, 2124 +VSCATTERPFODPD, 2124 +VSCATTERPFOQPD, 2124 +VSCATTERPF1DPS, 2126 +VSCATTERPF1QPS, 2126 +VSCATTERPF1DPD, 2126 +VSCATTERPF1QPD, 2126 +VSHUFF32X4, 1973 +VSHUFF64X2, 1973 +VSHUFI32X4, 1973 +VSHUFI64X2, 1973 +VTESTPD, 1978 +VTESTPS, 1978 +VZEROALL, 1981 +VZEROUPPER, 1982 +WAIT, 1983 +FWAIT, 1983 +WBINVD, 1984 +WRFSBASE, 1986 +WRGSBASE, 1986 +WRMSR, 1988 +WRPKRU, 1990 +WRSSD, 1991 +WRSSQ, 1991 +WRUSSD, 1993 +WRUSSQ, 1993 +XACQUIRE, 1995 +XRELEASE, 1995 +XABORT, 1999 +XADD, 2001 +XBEGIN, 2003 +XCHG, 2006 +XEND, 2008 +XGETBV, 2010 +XLAT, 2012 +XLATB, 2012 +XOR, 2014 +XORPD, 2016 +VXORPD, 2016 +XORPS, 2019 +VXORPS, 2019 +XRSTOR, 2022 +XRSTOR64, 2022 +XSTORS, 2027 +XSTORS64, 2027 +XSAVE, 2031 +XSAVE64, 2031 +XSAVEC, 2034 +XSAVEC64, 2034 +XSAVEOPT, 2037 +XSAVEOPT64, 2037 +XSAVES, 2040 +XSAVES64, 2040 +XSETBV, 2043 +XTEST, 2045 + +@24594.pdf [AMD64 Architecture Programmer's Manual Volume 3: General-Purpose and System Instructions, Rev 3.28 September 2019 (24594)] +BLCFILL, 129 +BLCI, 131 +BLCIC, 133 +BLCMSK, 135 +BLCS, 137 +BLSIC, 143 +CLZERO, 183 +LLWPCB, 247 +LOOPNZ, 252 +LOOPZ, 252 +LWPINS, 254 +LWPVAL, 256 +MONITORX, 263 +MWAITX, 289 +PREFETCH, 314 +SLWPCB, 369 +T1MSKC, 377 +TZMSK, 383 +UD0, 385 +UD1, 385 +UD2, 385 +CLGI, 400 +INVLPGA, 410 +SKINIT, 449 +STGI, 457 +VMLOAD, 476 +VMMCALL, 478 +VMRUN, 479 +VMSAVE, 484 +@26568.pdf [AMD64 Architecture Programmer's Manual Volume 4: 128-Bit and 256-Bit Media Instructions, Rev 3.23 Feb 2019 (26568)] EXTRQ, 181 INSERTQ, 196 MOVNTSD, 260 @@ -1632,7 +1692,7 @@ VPSHLB, 878 VPSHLD, 880 VPSHLQ, 882 VPSHLW, 884 -@AMD64_ProgrammersManual_vol5.pdf [AMD64 Architecture Programmer's Manual Volume 5: 64-Bit Media and x87 Floating-Point Instructions, Rev 3.15 May 2018 (26569)] +@26569_APM_V5.pdf [AMD64 Architecture Programmer's Manual Volume 5: 64-Bit Media and x87 Floating-Point Instructions, Rev 3.15 May 2018 (26569)] FEMMS, 48 PAVGUSB, 100 PF2ID, 118 From 05fba7639c9e4fb3269441d76ea1929d4551a883 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 6 Feb 2020 12:45:11 -0500 Subject: [PATCH 21/36] Corrected bitfield related regression issues --- .../merge/datatypes/DataTypeMerge3Test.java | 110 +++++++++++------- .../database/data/DataTypeManagerDB.java | 5 +- .../program/database/data/StructureDB.java | 9 +- .../program/model/data/StructureDataType.java | 6 - 4 files changed, 75 insertions(+), 55 deletions(-) diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java index fa41507f5e..8938fb089d 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/datatypes/DataTypeMerge3Test.java @@ -77,10 +77,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); - - Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); - Union union = (Union) c.getDataType("CoolUnion"); // choose MY chooseOption(DataTypeMergeManager.OPTION_MY);// DLL_Table from MY @@ -90,6 +86,11 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + + Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); + Union union = (Union) c.getDataType("CoolUnion"); + // DLL_Table should have a Word data type as the last component Structure s = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); DataTypeComponent dtc = s.getComponent(s.getNumComponents() - 1); @@ -154,7 +155,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); // choose DLL_Table from LATEST which means delete it chooseOption(DataTypeMergeManager.OPTION_LATEST); @@ -164,6 +164,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); Union union = (Union) c.getDataType("CoolUnion"); @@ -226,7 +228,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// choose DLL_Table from ORIGINAL @@ -234,6 +235,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + Category c = dtm.getCategory(new CategoryPath("/Category1/Category2")); Union union = (Union) c.getDataType("CoolUnion"); @@ -298,6 +301,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { executeMerge(true); + setErrorsExpected(false); + DataTypeManager dtm = resultProgram.getDataTypeManager(); checkConflictCount(0); @@ -371,13 +376,17 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); + executeMerge(); + + chooseOption(DataTypeMergeManager.OPTION_LATEST);// LATEST CoolUnion + setErrorsExpected(true); - executeMerge(); - chooseOption(DataTypeMergeManager.OPTION_LATEST);// LATEST CoolUnion chooseOption(DataTypeMergeManager.OPTION_MY);// MY Foo waitForCompletion(); + setErrorsExpected(false); + checkConflictCount(0); DataTypeManager dtm = resultProgram.getDataTypeManager(); @@ -451,10 +460,7 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); - setErrorsExpected(true); - executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_MY);// MY CoolUnion @@ -462,6 +468,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -522,10 +530,12 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); + executeMerge(); + + chooseOption(DataTypeMergeManager.OPTION_LATEST);// Latest CoolUnion + setErrorsExpected(true); - executeMerge(); - chooseOption(DataTypeMergeManager.OPTION_LATEST);// Latest CoolUnion chooseOption(DataTypeMergeManager.OPTION_MY);// My Bar // @@ -533,6 +543,9 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { // OptionDialog errorDialog = waitForDialogComponent(null, OptionDialog.class, DEFAULT_WINDOW_TIMEOUT); + + setErrorsExpected(false); + assertNotNull(errorDialog); errorDialog.close(); window.setVisible(false); @@ -602,17 +615,20 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); - setErrorsExpected(true); - executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); - // + chooseOption(DataTypeMergeManager.OPTION_MY);// choose My Bar - chooseOption(DataTypeMergeManager.OPTION_ORIGINAL); - // choose Structure_1 from ORIGINAL + setErrorsExpected(true); + + chooseOption(DataTypeMergeManager.OPTION_ORIGINAL); // choose Structure_1 from ORIGINAL + + setErrorsExpected(false); waitForCompletion(); + + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // Bar should contain original Structure_1 Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); DataTypeComponent[] dtcs = bar.getDefinedComponents(); @@ -676,14 +692,15 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); - // - chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// choose original Bar - chooseOption(DataTypeMergeManager.OPTION_MY); - // choose Structure_1 from MY + chooseOption(DataTypeMergeManager.OPTION_ORIGINAL); // choose original Bar + + chooseOption(DataTypeMergeManager.OPTION_MY); // choose Structure_1 from MY waitForCompletion(); + + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // Bar should contain original Structure_1 Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); assertEquals(6, bar.getLength()); @@ -750,14 +767,15 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); - // + chooseOption(DataTypeMergeManager.OPTION_MY);// choose my Bar - chooseOption(DataTypeMergeManager.OPTION_LATEST);// delele Structure_1 - // choose Structure_1 from MY + chooseOption(DataTypeMergeManager.OPTION_LATEST);// delele Structure_1 (choose Structure_1 from MY) waitForCompletion(); + + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // Bar should contain undefined to replace Structure_1 Structure bar = (Structure) dtm.getDataType(new CategoryPath("/MISC"), "Bar"); assertEquals(7, bar.getLength()); @@ -848,7 +866,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); // conflict on ArrayStruct (6) chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// use ORIGINAL ArrayStruct @@ -859,6 +876,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { // conflict on FloatStruct (2) chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete FloatStruct + DataTypeManager dtm = resultProgram.getDataTypeManager(); + assertNull( dtm.getDataType(new CategoryPath("/Category1/Category2/Category5"), "FloatStruct")); @@ -940,7 +959,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { // bitfield silently transitions to int since typedef BF was removed - executeMerge(); + executeMerge(true); + DataTypeManager dtm = resultProgram.getDataTypeManager(); Structure s1 = @@ -1028,7 +1048,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { // bitfield silently transitions to BF.conflict since two different BF types were added - executeMerge(); + executeMerge(true); + DataTypeManager dtm = resultProgram.getDataTypeManager(); Structure s1 = @@ -1129,7 +1150,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// choose DLL_Table from ORIGINAL @@ -1137,6 +1157,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // DLL_Table should exist Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); @@ -1218,7 +1240,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete DLL_Table @@ -1226,6 +1247,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // DLL_Table should not exist Structure dll = (Structure) dtm.getDataType(CategoryPath.ROOT, "DLL_Table"); @@ -1308,7 +1331,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table @@ -1316,6 +1338,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // CoolUnion should not be null Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -1395,7 +1419,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_LATEST);// delete DLL_Table @@ -1403,6 +1426,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // CoolUnion should not be null Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -1483,7 +1508,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_MY);// my DLL_Table @@ -1491,6 +1515,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // CoolUnion should be null Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -1572,7 +1598,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table @@ -1580,6 +1605,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // CoolUnion should not be null Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -1668,7 +1695,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table @@ -1676,6 +1702,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // CoolUnion should not be null Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -1773,7 +1801,6 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_ORIGINAL);// original DLL_Table @@ -1781,6 +1808,8 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // CoolUnion should not be null Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); @@ -1893,12 +1922,13 @@ public class DataTypeMerge3Test extends AbstractDataTypeMergeTest { } }); executeMerge(); - DataTypeManager dtm = resultProgram.getDataTypeManager(); chooseOption(DataTypeMergeManager.OPTION_MY);// MY bitfields w/ enum waitForCompletion(); + DataTypeManager dtm = resultProgram.getDataTypeManager(); + // primitive type of byte used in absence of enum Union union = (Union) dtm.getDataType(new CategoryPath("/Category1/Category2"), "CoolUnion"); 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 e6fc6db105..b262485cb9 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 @@ -772,7 +772,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { private DataType resolveBitFieldDataType(BitFieldDataType bitFieldDataType, DataTypeConflictHandler handler) { - // NOTE: When a bit-field is getting adding added it will get resolved more than once. + // NOTE: When a bit-field is getting added it will get resolved more than once. // The first time we will ensure that the base data type, which may be a TypeDef, gets // resolved. If the bit-offset is too large it will be set to 0 // with the expectation that it will get corrected during subsequent packing. @@ -786,7 +786,8 @@ abstract public class DataTypeManagerDB implements DataTypeManager { int storageSizeBits = 8 * storageSize; if ((bitOffset + bitSize) > storageSizeBits) { // should get recomputed during packing when used within aligned structure - bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - bitSize : 0; + int effectiveBitSize = Math.min(bitSize, baseLengthBits); + bitOffset = getDataOrganization().isBigEndian() ? baseLengthBits - effectiveBitSize : 0; storageSize = baseLength; } try { diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java index 8b70770bf3..8f3d98148b 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/StructureDB.java @@ -997,10 +997,7 @@ class StructureDB extends CompositeDB implements Structure { if (ordinal < 0 || ordinal >= numComponents) { throw new ArrayIndexOutOfBoundsException(ordinal); } - if (dataType instanceof BitFieldDataType) { - throw new IllegalArgumentException( - "Components may not be replaced with a bit-field"); - } + validateDataType(dataType); DataTypeComponent origDtc = getComponent(ordinal); @@ -1044,9 +1041,7 @@ class StructureDB extends CompositeDB implements Structure { throw new IllegalArgumentException( "Offset " + offset + " is beyond end of structure (" + structLength + ")."); } - if (dataType instanceof BitFieldDataType) { - throw new IllegalArgumentException("Components may not be replaced with a bit-field"); - } + lock.acquire(); try { checkDeleted(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java index 140a91ff3d..d05d36db2c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/StructureDataType.java @@ -1149,9 +1149,6 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur if (index < 0 || index >= numComponents) { throw new ArrayIndexOutOfBoundsException(index); } - if (dataType instanceof BitFieldDataType) { - throw new IllegalArgumentException("Components may not be replaced with a bit-field"); - } validateDataType(dataType); @@ -1191,9 +1188,6 @@ public class StructureDataType extends CompositeDataTypeImpl implements Structur throw new IllegalArgumentException( "Offset " + offset + " is beyond end of structure (" + structLength + ")."); } - if (dataType instanceof BitFieldDataType) { - throw new IllegalArgumentException("Components may not be replaced with a bit-field"); - } validateDataType(dataType); From af5e11e034ffa64578ab347f047e33587d8eb37f Mon Sep 17 00:00:00 2001 From: adamopolous Date: Wed, 9 Oct 2019 14:00:37 -0400 Subject: [PATCH 22/36] allow tests to be initiated via web interface --- .gitlab-ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index b7544a3749..44fc7f7345 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -12,3 +12,4 @@ test-parallel: image: ghidra/ubuntu only: - master + - web From a2a9e025227f2881b0aa104d365fd892cb835b7d Mon Sep 17 00:00:00 2001 From: ghizard <50744617+ghizard@users.noreply.github.com> Date: Thu, 6 Feb 2020 18:05:47 -0500 Subject: [PATCH 23/36] Ghidra 9.1.2 Change History --- .../src/global/docs/ChangeHistory.html | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html b/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html index ca05fa91d5..2ea54acd8e 100644 --- a/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html +++ b/Ghidra/Configurations/Public_Release/src/global/docs/ChangeHistory.html @@ -6,6 +6,24 @@ +

Ghidra 9.1.2 Change History (February 2020)

+

Bugs

+
    +
  • Data Types. Improved PDB composite reconstruction to attempt pack(1) alignment if default alignment fails. (GT-3401)
  • +
  • Data Types. Added missing support for multi-user merge of unions and structures containing bitfields or a trailing flexible array member. (GT-3479)
  • +
  • Data Types. Corrected structure editor save button enablement issue when editing bitfields within an unaligned structure. (GT-3519, Issue #1297)
  • +
  • Disassembly. Corrected potential infinite loop with disassembler caused by branch to self with invalid delay slot instruction. (GT-3511, Issue #1486)
  • +
  • GUI. Corrected processor manual display for Microsoft Windows users, which was not displaying processor manual and was, instead, rendering a blank page in web browser. (GT-3444)
  • +
  • GUI:Bitfield Editor. Added field comment support to composite bitfield editor. (GT-3410)
  • +
  • Importer:MachO. A MachO loader regression, in Ghidra 9.1.1, when laying down symbols at the correct location, has been fixed. (GT-3487, Issue #1446)
  • +
  • Languages. Corrected mnemonic for ARM thumb RSB.w instruction. (GT-3420, Issue #1365)
  • +
  • Languages. Corrected issue in M68000 with some move instructions not creating correct array assignments. (GT-3429, Issue #1394)
  • +
  • Languages. Updated x86 processor manual index file with latest Intel and AMD manuals. (GT-3489, Issue #1078)
  • +
  • Multi-User:Ghidra Server. Corrected Ghidra Server remote interface errors that occur when running with Java 11.0.6 (and later) release, which would throw RemoteException Method is not Remote errors. (GT-3521, Issue #1440)
  • +
  • PDB. Corrected PDB XML generation for zero-length classes and structures and resolved various datatype dependency issues encountered during PDB Analysis. Changed line numbers from hex to decimal. (GT-3462, Issue #1410)
  • +
+
+

Ghidra 9.1.1 Change History (December 2019)

Improvements

    From e16bd30366352ea9ef7b2653d5bba280348e5695 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 6 Feb 2020 18:08:02 -0500 Subject: [PATCH 24/36] Tests - fixed tests failing due to font issue on test machine --- .../src/main/java/generic/text/TextLayoutGraphics.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Ghidra/Framework/Generic/src/main/java/generic/text/TextLayoutGraphics.java b/Ghidra/Framework/Generic/src/main/java/generic/text/TextLayoutGraphics.java index 488c703c3d..299b560126 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/text/TextLayoutGraphics.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/text/TextLayoutGraphics.java @@ -158,12 +158,18 @@ public class TextLayoutGraphics extends Graphics2D { //Insert spaces to account for distance past last field in row FontMetrics metrics = COMPONENT.getFontMetrics(sortedTextInfo.font); int spaceWidth = metrics.charWidth(' '); + if (spaceWidth == 0) { + // some environments report 0 for some fonts + spaceWidth = 4; + } + int fillSpaces = Math.round((float) (sortedTextInfo.point.x - lastXPos) / (float) spaceWidth); //Account for the case where there's a very small amount of space between fields if (fillSpaces == 0 && sortedTextInfo.point.x > lastXPos) { fillSpaces = 1; } + for (int j = 0; j < fillSpaces; j++) { buffer.append(' '); } From cc6020736c73f856a3fb430729f38a20c918ddd6 Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 6 Feb 2020 18:08:21 -0500 Subject: [PATCH 25/36] Tests - fixed test timing issues --- .../docking/widgets/table/GTableTest.java | 80 ++++++++++++++----- .../table/AbstractSortedTableModel.java | 13 +++ .../filechooser/GhidraFileChooserTest.java | 16 +++- 3 files changed, 85 insertions(+), 24 deletions(-) diff --git a/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java b/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java index 3c2a4d05ce..679a3deb10 100644 --- a/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/docking/widgets/table/GTableTest.java @@ -25,6 +25,7 @@ import org.junit.*; import docking.widgets.table.model.TestDataModel; import ghidra.test.AbstractGhidraHeadedIntegrationTest; +import ghidra.util.Msg; import ghidra.util.table.GhidraTable; public class GTableTest extends AbstractGhidraHeadedIntegrationTest { @@ -44,6 +45,9 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { frame.getContentPane().add(new JScrollPane(table)); frame.pack(); frame.setVisible(true); + + // showing the table will trigger a call to sort; wait for sorting to finish + waitForSort(); } @After @@ -59,26 +63,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { setSelectedRow(table, 0); triggerText(table, "a"); - assertEquals(11, table.getSelectedRow()); + assertSelectedRow(11, "a"); + triggerText(table, "c"); - assertEquals(12, table.getSelectedRow()); + assertSelectedRow(12, "c"); timeout(); + triggerText(table, "ad"); - assertEquals(24, table.getSelectedRow()); + assertSelectedRow(24, "ad"); timeout(); + triggerText(table, "av"); - assertEquals(70, table.getSelectedRow()); + assertSelectedRow(70, "av"); timeout(); + triggerText(table, "x"); - assertEquals(1920, table.getSelectedRow()); + assertSelectedRow(1920, "x"); timeout(); + triggerText(table, "a"); - assertEquals(11, table.getSelectedRow()); + assertSelectedRow(11, "a"); // test the case where no match is found table.setAutoLookupTimeout(1000); // longer timeout needed for multiple keys triggerText(table, "zed"); - assertEquals(11, table.getSelectedRow()); // no change + assertSelectedRow(11, "zed"); // no change } @Test @@ -92,31 +101,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { setSelectedRow(table, 0); triggerText(table, "a"); - assertEquals(1846, table.getSelectedRow()); + assertSelectedRow(1846, "a"); triggerText(table, "c"); - assertEquals(1902, table.getSelectedRow()); + assertSelectedRow(1902, "c"); timeout(); triggerText(table, "ad"); - assertEquals(1885, table.getSelectedRow()); + assertSelectedRow(1885, "ad"); timeout(); triggerText(table, "av"); - assertEquals(1848, table.getSelectedRow()); + assertSelectedRow(1848, "av"); timeout(); triggerText(table, "x"); - assertEquals(0, table.getSelectedRow()); + assertSelectedRow(0, "x"); timeout(); triggerText(table, "a"); - assertEquals(1846, table.getSelectedRow()); + assertSelectedRow(1846, "a"); // test the case where no match is found table.setAutoLookupTimeout(1000); // longer timeout needed for multiple keys triggerText(table, "zed"); - assertEquals(1846, table.getSelectedRow()); // no change + assertSelectedRow(1846, "zed"); // no change } @Test @@ -132,26 +141,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { // note: the order checked here is the same as the sorted order, since we did not move // any rows after disabling the sort triggerText(table, "a"); - assertEquals(11, table.getSelectedRow()); + assertSelectedRow(11, "a"); + triggerText(table, "c"); - assertEquals(12, table.getSelectedRow()); + assertSelectedRow(12, "c"); timeout(); + triggerText(table, "ad"); - assertEquals(24, table.getSelectedRow()); + assertSelectedRow(24, "ad"); timeout(); + triggerText(table, "av"); - assertEquals(70, table.getSelectedRow()); + assertSelectedRow(70, "av"); timeout(); + triggerText(table, "x"); - assertEquals(1920, table.getSelectedRow()); + assertSelectedRow(1920, "x"); timeout(); + triggerText(table, "a"); - assertEquals(11, table.getSelectedRow()); + assertSelectedRow(11, "a"); // test the case where no match is found table.setAutoLookupTimeout(1000); // longer timeout needed for multiple keys triggerText(table, "zed"); - assertEquals(11, table.getSelectedRow()); // no change + assertSelectedRow(11, "zed"); // no change } @Test @@ -192,9 +206,31 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { assertEquals("Auto-lookup failed to change the table row", 11, table.getSelectedRow()); } + private void assertSelectedRow(int row, String lookupText) { + + int actual = runSwing(() -> table.getSelectedRow()); + if (row != actual) { + + int col = 4; // String 'Name' column + String expectedString = (String) table.getValueAt(row, col); + String actualString = (String) table.getValueAt(actual, col); + String message = "Auto-lookup row not selected for '" + lookupText + "'.\n\t" + + "Expected text: '" + expectedString + "'; Actual text: '" + actualString + "'"; + Msg.out(message); + assertEquals(message, row, actual); + } + } + private void removeSortColumn(int column) { waitForSwing(); runSwing(() -> TableUtils.columnAlternativelySelected(table, column)); + waitForSort(); + } + + private void waitForSort() { + // the call to sort may be run in an invokeLater() + waitForSwing(); + waitForCondition(() -> !model.isSortPending()); waitForSwing(); } @@ -202,7 +238,7 @@ public class GTableTest extends AbstractGhidraHeadedIntegrationTest { TableSortState descendingSortState = TableSortState.createDefaultSortState(column, false); runSwing(() -> model.setTableSortState(descendingSortState)); - waitForSwing(); + waitForSort(); } private void timeout() { diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java index 9353174ac2..ba6a3dca78 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/AbstractSortedTableModel.java @@ -190,10 +190,23 @@ public abstract class AbstractSortedTableModel extends AbstractGTableModel return pendingSortState; } + /** + * Returns true if there is a pending change to the current sort state + * (this includes a sort state that signals no sort will be applied) + * + * @return true if there is a pending change to the current sort state + */ public boolean isSortPending() { return isSortPending; } + /** + * Returns true if this model has been sorted and does not have a new pending sort that will + * be applied + * + * @return true if sorted + * @see #isSortPending() + */ public boolean isSorted() { return !isSortPending && !sortState.isUnsorted(); } diff --git a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java index 4ce3cfa3eb..05fd71f780 100644 --- a/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java +++ b/Ghidra/Framework/Docking/src/test.slow/java/docking/widgets/filechooser/GhidraFileChooserTest.java @@ -1747,8 +1747,15 @@ public class GhidraFileChooserTest extends AbstractDockingTest { public void testHistoryRestoresSelectedFiles() throws Exception { File startDir = createTempDir(); - setDir(startDir); - createFileSubFile(startDir, 3); + File subDir = createFileSubFile(startDir, 3); + setDir(subDir); + +// // debug +// DirectoryList list = getListView(); +// ListSelectionModel sm = list.getSelectionModel(); +// sm.addListSelectionListener(e -> { +// Msg.debug(this, "selection changed: " + e); +// }); pressUp(); selectFile(getListView(), 1); @@ -1930,6 +1937,11 @@ public class GhidraFileChooserTest extends AbstractDockingTest { } private File selectFile(DirectoryList list, int index) { + + // TODO debug - remove when all tests passing on server + int size = list.getModel().getSize(); + Msg.debug(this, "selectFile() - new index: " + index + "; list size: " + size); + runSwing(() -> list.setSelectedIndex(index)); return runSwing(() -> list.getSelectedFile()); } From 22cc232210a050ff3921220df6d53f8896e5234b Mon Sep 17 00:00:00 2001 From: dragonmacher <48328597+dragonmacher@users.noreply.github.com> Date: Thu, 6 Feb 2020 18:09:00 -0500 Subject: [PATCH 26/36] Tests - fixed test failing to improper dialog parenting; updated dialog parenting to avoid transient parents --- .../plugin/core/exporter/ExporterDialog.java | 13 ++++++++---- .../{Compare.java => StringComparer.java} | 20 +++++++++---------- .../java/docking/DockingWindowManager.java | 16 ++++++--------- 3 files changed, 25 insertions(+), 24 deletions(-) rename Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/{Compare.java => StringComparer.java} (80%) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java index 0cd1004ef6..601aefd94c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/exporter/ExporterDialog.java @@ -116,6 +116,10 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa addCancelButton(); setHelpLocation(new HelpLocation("ExporterPlugin", "Exporter_Dialog")); + // This dialog is temporary and will be closed when the task is finished. Mark + // it transient so no other windows will be parented to this dialog. + setTransient(true); + // need to initialize a few things selectedFormatChanged(); validate(); @@ -503,7 +507,7 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa Object tmpConsumer = new Object(); obj.addConsumer(tmpConsumer); - SystemUtilities.runSwingLater(() -> { + Swing.runLater(() -> { try { AboutDomainObjectUtils.displayInformation(tool, obj.getDomainFile(), obj.getMetadata(), "Export Results Summary", resultsBuffer.toString(), @@ -516,9 +520,10 @@ public class ExporterDialog extends DialogComponentProvider implements AddressFa } - /************************************************** - * Methods for testing - **************************************************/ +//================================================================================================== +// Methods for Testing +//================================================================================================== + JCheckBox getSelectionCheckBox() { return selectionCheckBox; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/StringComparer.java similarity index 80% rename from Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java rename to Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/StringComparer.java index 4b2fb28cb5..9c265ff308 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/Compare.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/exporter/StringComparer.java @@ -16,16 +16,16 @@ package ghidra.app.util.exporter; import java.io.*; -import java.util.ArrayList; +import java.util.List; import org.junit.Assert; import ghidra.util.Msg; -public class Compare { - public static void compare(ArrayList expectedList, File actualFile) throws Exception { +public class StringComparer { + public static void compareLines(List expectedList, File actualFile) throws Exception { int index = 0; - + boolean hasFailure = false; try (BufferedReader reader = new BufferedReader(new FileReader(actualFile))) { @@ -35,7 +35,7 @@ public class Compare { if (actualLine == null) { break; } - + if (index >= expectedList.size()) { ++excess; continue; @@ -46,26 +46,26 @@ public class Compare { expectedLine = expectedLine.trim(); boolean match = - expectedLine.equals(actualLine) || actualLine.startsWith(expectedLine); + expectedLine.equals(actualLine) || actualLine.startsWith(expectedLine); hasFailure |= !match; if (!match) { - Msg.debug(Compare.class, "Expected line does not match actual line (" + index + + Msg.debug(StringComparer.class, "Expected line does not match actual line (" + index + "): \nExpected: " + expectedLine + "\nActual: " + actualLine); } } if (excess > 0) { String message = "Actual file contains " + excess + " more lines than expected"; - Msg.debug(Compare.class, message); + Msg.debug(StringComparer.class, message); Assert.fail(message); } else if (!hasFailure && index < expectedList.size()) { int fewer = expectedList.size() - index; String message = "Actual file contains " + fewer + - " fewer lines than expected"; - Msg.debug(Compare.class, message); + " fewer lines than expected"; + Msg.debug(StringComparer.class, message); Assert.fail(message); } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java index 24a6132904..7f78305998 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DockingWindowManager.java @@ -1854,20 +1854,16 @@ public class DockingWindowManager implements PropertyChangeListener, Placeholder // as message dialogs will too be closed DockingDialog d = (DockingDialog) activeWindow; Window ancestor = SwingUtilities.getWindowAncestor(d); - if (!d.isShowing()) { - if (!ancestor.isShowing()) { - return null; - } + if (d.isShowing() && isNonTransientWindow(d)) { + return d; + } + // The active window is not a suitable parent; try its parent + if (ancestor.isShowing() && isNonTransientWindow(ancestor)) { return ancestor; } - DialogComponentProvider provider = d.getComponent(); - if (provider.isTransient()) { - return ancestor; - } - - return d; + return null; } public ComponentProvider getActiveComponentProvider() { From fce7cd0a9a7cd185b388c2d61694836618d2a3c8 Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Mon, 3 Feb 2020 16:42:35 -0500 Subject: [PATCH 27/36] Correct divide-by-zero test issue --- .../core/equate/AbstractConvertAction.java | 24 +++++++++++++------ 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java index 776a4c35ba..0c09879c3c 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/equate/AbstractConvertAction.java @@ -42,10 +42,6 @@ public abstract class AbstractConvertAction extends ListingContextAction { this.isSigned = isSigned; setPopupMenuData(new MenuData(new String[] { "Convert", "" }, "Convert")); setEnabled(true); - JMenuItem item = new JMenuItem(); - Font font = item.getFont(); - metrics = plugin.getTool().getActiveWindow().getFontMetrics(font); - } @Override @@ -132,14 +128,28 @@ public abstract class AbstractConvertAction extends ListingContextAction { return isSigned; } + private int stringWidth(String s) { + if (metrics == null) { + JMenuItem item = new JMenuItem(); + Font font = item.getFont(); + metrics = plugin.getTool().getActiveWindow().getFontMetrics(font); + } + int w = metrics.stringWidth(s); + if (w == 0) { + // use default computation if metrics report 0 + return 10 * s.length(); + } + return w; + } + String getStandardLengthString(String baseString) { - int baseWidth = metrics.stringWidth(baseString); - int spaceWidth = metrics.stringWidth(" "); + int baseWidth = stringWidth(baseString); + int spaceWidth = stringWidth(" "); int paddingSize = (140 - baseWidth) / spaceWidth; if (paddingSize <= 0) { return baseString; } - StringBuffer buf = new StringBuffer(baseString); + StringBuilder buf = new StringBuilder(baseString); for (int i = 0; i < paddingSize; i++) { buf.append(" "); } From 772e0166e22c0f7301aa8c182190fad4f384c77b Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Thu, 6 Feb 2020 19:11:44 -0500 Subject: [PATCH 28/36] Corrected test --- .../listing/EquateMergeManager1Test.java | 137 +++++++++--------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/EquateMergeManager1Test.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/EquateMergeManager1Test.java index 05a4931917..9e981c8bd8 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/EquateMergeManager1Test.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/app/merge/listing/EquateMergeManager1Test.java @@ -15,7 +15,7 @@ */ package ghidra.app.merge.listing; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.*; import java.util.List; @@ -59,8 +59,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { super(); } -@Test - public void testRemoveEquate() throws Exception { + @Test + public void testRemoveEquate() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { /* (non-Javadoc) @@ -139,8 +139,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { assertEquals(0, equates.size()); } -@Test - public void testChangeEquate() throws Exception { + @Test + public void testChangeEquate() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { /* (non-Javadoc) @@ -211,7 +211,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { Address addr = addr(program, address); Equate oldEquate = equateTab.getEquate(addr, opIndex, value); if (oldEquate.getName().equals(newName)) { - Assert.fail("Equate '" + oldEquate.getName() + "' already exists with value=" + value + "."); + Assert.fail( + "Equate '" + oldEquate.getName() + "' already exists with value=" + value + "."); } oldEquate.removeReference(addr, opIndex); try { @@ -220,8 +221,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { newEquate = equateTab.createEquate(newName, value); } if (newEquate.getValue() != value) { - Assert.fail("Can't create equate '" + newEquate.getName() + "' with value=" + value + - ". It already exists with value=" + newEquate.getValue() + "."); + Assert.fail("Can't create equate '" + newEquate.getName() + "' with value=" + + value + ". It already exists with value=" + newEquate.getValue() + "."); } newEquate.addReference(addr, opIndex); } @@ -230,8 +231,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { } } -@Test - public void testRemoveVsChangeEquate() throws Exception { + @Test + public void testRemoveVsChangeEquate() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { /* (non-Javadoc) @@ -285,7 +286,7 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { assertEquals(1L, eq.getValue()); } -@Test + @Test public void testAddNameDiffPickMy() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { @@ -344,53 +345,56 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { @Test public void testAddNameDiffOnWordDataUpperBit0PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new WordDataType(), new byte[] { (byte) 0x5f, - (byte) 0x5f }, 0x5f5f, true); + runTestAddNameDiffPickIndicated("0x1002d24", new WordDataType(), + new byte[] { (byte) 0x5f, (byte) 0x5f }, 0x5f5f, true); } @Test public void testAddNameDiffOnWordDataUpperBit1PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new WordDataType(), new byte[] { (byte) 0xad, - (byte) 0xad }, 0xadad, true); + runTestAddNameDiffPickIndicated("0x1002d24", new WordDataType(), + new byte[] { (byte) 0xad, (byte) 0xad }, 0xadad, true); } @Test public void testAddNameDiffOnSignedWordDataUpperBit0PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedWordDataType(), new byte[] { - (byte) 0x5f, (byte) 0x5f }, 0x5f5fL, true); + runTestAddNameDiffPickIndicated("0x1002d24", new SignedWordDataType(), + new byte[] { (byte) 0x5f, (byte) 0x5f }, 0x5f5fL, true); } @Test public void testAddNameDiffOnSignedWordDataUpperBit1PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedWordDataType(), new byte[] { - (byte) 0xad, (byte) 0xad }, 0xffffffffffffadadL, true); + runTestAddNameDiffPickIndicated("0x1002d24", new SignedWordDataType(), + new byte[] { (byte) 0xad, (byte) 0xad }, 0xffffffffffffadadL, true); } @Test public void testAddNameDiffOnSignedQWordDataUpperBit0PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedQWordDataType(), new byte[] { - (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, - (byte) 0x5f, (byte) 0x5f }, 0x5f5f5f5f5f5f5f5fL, true); + runTestAddNameDiffPickIndicated( + "0x1002d24", new SignedQWordDataType(), new byte[] { (byte) 0x5f, (byte) 0x5f, + (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f }, + 0x5f5f5f5f5f5f5f5fL, true); } @Test public void testAddNameDiffOnSignedQWordDataUpperBit1PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedQWordDataType(), new byte[] { - (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, - (byte) 0xad, (byte) 0xad }, 0xadadadadadadadadL, true); + runTestAddNameDiffPickIndicated( + "0x1002d24", new SignedQWordDataType(), new byte[] { (byte) 0xad, (byte) 0xad, + (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad }, + 0xadadadadadadadadL, true); } @Test public void testAddNameDiffOnSignedInt5DataUpperBit0PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new Integer5DataType(), new byte[] { - (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f }, 0x5f5f5f5f5fL, true); + runTestAddNameDiffPickIndicated("0x1002d24", new Integer5DataType(), + new byte[] { (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f }, + 0x5f5f5f5f5fL, true); } @Test public void testAddNameDiffOnSignedInt5DataUpperBit1PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new Integer5DataType(), new byte[] { - (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad }, 0xffffffadadadadadL, - true); + runTestAddNameDiffPickIndicated("0x1002d24", new Integer5DataType(), + new byte[] { (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad }, + 0xffffffadadadadadL, true); } @Test @@ -409,43 +413,48 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { @Test public void testAddNameDiffOnSignedInt7DataUpperBit0PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new Integer7DataType(), new byte[] { - (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, - (byte) 0x5f }, 0x5f5f5f5f5f5f5fL, true); + runTestAddNameDiffPickIndicated("0x1002d24", new Integer7DataType(), + new byte[] { (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, + (byte) 0x5f, (byte) 0x5f }, + 0x5f5f5f5f5f5f5fL, true); } @Test public void testAddNameDiffOnSignedInt7DataUpperBit1PickMy() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new Integer7DataType(), new byte[] { - (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, - (byte) 0xad }, 0xffadadadadadadadL, true); + runTestAddNameDiffPickIndicated("0x1002d24", new Integer7DataType(), + new byte[] { (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, + (byte) 0xad, (byte) 0xad }, + 0xffadadadadadadadL, true); } @Test public void testAddNameDiffOnSignedWordDataUpperBit0PickLatest() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedWordDataType(), new byte[] { - (byte) 0x5f, (byte) 0x5f }, 0x5f5fL, false); + runTestAddNameDiffPickIndicated("0x1002d24", new SignedWordDataType(), + new byte[] { (byte) 0x5f, (byte) 0x5f }, 0x5f5fL, false); } @Test public void testAddNameDiffOnSignedQWordDataUpperBit0PickLatest() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedQWordDataType(), new byte[] { - (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, - (byte) 0x5f, (byte) 0x5f }, 0x5f5f5f5f5f5f5f5fL, false); + runTestAddNameDiffPickIndicated( + "0x1002d24", new SignedQWordDataType(), new byte[] { (byte) 0x5f, (byte) 0x5f, + (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f, (byte) 0x5f }, + 0x5f5f5f5f5f5f5f5fL, false); } @Test public void testAddNameDiffOnSignedQWordDataUpperBit1PickLatest() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new SignedQWordDataType(), new byte[] { - (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, - (byte) 0xad, (byte) 0xad }, 0xadadadadadadadadL, false); + runTestAddNameDiffPickIndicated( + "0x1002d24", new SignedQWordDataType(), new byte[] { (byte) 0xad, (byte) 0xad, + (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad }, + 0xadadadadadadadadL, false); } @Test public void testAddNameDiffOnSignedInt5DataUpperBit1PickLatest() throws Exception { - runTestAddNameDiffPickIndicated("0x1002d24", new Integer5DataType(), new byte[] { - (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, - (byte) 0xad, (byte) 0xad }, 0xffffffadadadadadL, false); + runTestAddNameDiffPickIndicated( + "0x1002d24", new Integer5DataType(), new byte[] { (byte) 0xad, (byte) 0xad, (byte) 0xad, + (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad, (byte) 0xad }, + 0xffffffadadadadadL, false); } @Test @@ -476,10 +485,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { try { Listing listing = program.getListing(); Address startAddr = addr(program, "0x1002d20"); - program.getMemory().setBytes( - startAddr, - new byte[] { (byte) 0x8d, (byte) 0x04, (byte) 0x8d, (byte) 0x0, (byte) 0x0, - (byte) 0x0, (byte) 0x0 }); //LEA EAX,[0x0 + ECX*0x4] + program.getMemory().setBytes(startAddr, new byte[] { (byte) 0x8d, (byte) 0x04, + (byte) 0x8d, (byte) 0x0, (byte) 0x0, (byte) 0x0, (byte) 0x0 }); //LEA EAX,[0x0 + ECX*0x4] createInstruction(program, startAddr); Instruction instruction = listing.getInstructionAt(startAddr); Assert.assertTrue(instruction != null); @@ -491,7 +498,7 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { } finally { program.endTransaction(txId, commit); - } + } } @Override @@ -533,7 +540,7 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { } finally { program.endTransaction(txId, commit); - } + } } }); } @@ -579,11 +586,11 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { List equates = equateTab.getEquates(addr("0x1002d20"), 1); assertEquals(2, equates.size()); Equate eq = equates.get(0); - assertEquals("ZERO", eq.getName()); - assertEquals(0L, eq.getValue()); - eq = equates.get(1); assertEquals("QUAD", eq.getName()); assertEquals(4L, eq.getValue()); + eq = equates.get(1); + assertEquals("ZERO", eq.getName()); + assertEquals(0L, eq.getValue()); } @Test @@ -595,8 +602,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { setupAddNameDiffOnSubOperand(); executeMerge(ASK_USER); - chooseEquate("0x1002d20", 1, KEEP_LATEST); // 0x0 chooseEquate("0x1002d20", 1, KEEP_MY); // 0x4 + chooseEquate("0x1002d20", 1, KEEP_LATEST); // 0x0 waitForMergeCompletion(); EquateTable equateTab = resultProgram.getEquateTable(); @@ -620,8 +627,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { setupAddNameDiffOnSubOperand(); executeMerge(ASK_USER); - chooseEquate("0x1002d20", 1, KEEP_MY); // 0x0 chooseEquate("0x1002d20", 1, KEEP_LATEST); // 0x4 + chooseEquate("0x1002d20", 1, KEEP_MY); // 0x0 waitForMergeCompletion(); EquateTable equateTab = resultProgram.getEquateTable(); @@ -637,7 +644,7 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { } @Test - public void testAddSameNameDiffValue() throws Exception { + public void testAddSameNameDiffValue() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { /* (non-Javadoc) @@ -703,8 +710,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { assertEquals(1L, eq.getValue()); } -@Test - public void testAddSameNameDiffValueWithResolve() throws Exception { + @Test + public void testAddSameNameDiffValueWithResolve() throws Exception { mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() { /* (non-Javadoc) @@ -808,8 +815,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { }); } -@Test - public void testChangeEquateUseForAllPickLatest() throws Exception { + @Test + public void testChangeEquateUseForAllPickLatest() throws Exception { setupUseForAll(); executeMerge(ASK_USER); @@ -832,8 +839,8 @@ public class EquateMergeManager1Test extends AbstractListingMergeManagerTest { assertEquals(1L, eq.getValue()); } -@Test - public void testChangeEquateUseForAllPickMy() throws Exception { + @Test + public void testChangeEquateUseForAllPickMy() throws Exception { setupUseForAll(); executeMerge(ASK_USER); From dcd529604108bb71d3d10e559a54cd09986cd5c0 Mon Sep 17 00:00:00 2001 From: ghidorahrex Date: Fri, 7 Feb 2020 14:55:16 -0500 Subject: [PATCH 29/36] GT-933: Code review fixes for atmega SP memory addresses in .pspec --- Ghidra/Processors/Atmel/data/languages/atmega256.pspec | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Ghidra/Processors/Atmel/data/languages/atmega256.pspec b/Ghidra/Processors/Atmel/data/languages/atmega256.pspec index c69c8cf17b..dec8fbab1c 100644 --- a/Ghidra/Processors/Atmel/data/languages/atmega256.pspec +++ b/Ghidra/Processors/Atmel/data/languages/atmega256.pspec @@ -135,8 +135,8 @@ - - + + From 6de961364fd44dfe43986e7ac10544d7be9b8abe Mon Sep 17 00:00:00 2001 From: ghidravore Date: Mon, 10 Feb 2020 11:14:17 -0500 Subject: [PATCH 30/36] Fixed bug where column filter tooltip was on the wrong column --- .../src/main/java/docking/widgets/table/GTableHeader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java index 8d12fc8727..a8fe270267 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/table/GTableHeader.java @@ -196,7 +196,7 @@ public class GTableHeader extends JTableHeader { int realIndex = gTable.convertColumnIndexToModel(columnIndex); - String columnFilterToolTip = getColumnFilterToolTip(model, columnIndex); + String columnFilterToolTip = getColumnFilterToolTip(model, realIndex); VariableColumnTableModel variableModel = VariableColumnTableModel.from(model); if (variableModel != null) { String description = variableModel.getColumnDescription(realIndex); From 0536335c21438b61e003390e6c4dc76a8c1f3555 Mon Sep 17 00:00:00 2001 From: ghidravore Date: Tue, 11 Feb 2020 12:27:19 -0500 Subject: [PATCH 31/36] GT-3535 improving data type category performance --- .../program/database/data/CategoryTest.java | 36 +++- .../program/database/data/CategoryDB.java | 156 ++++++++++++++++-- .../database/data/DataTypeManagerDB.java | 18 +- .../database/data/LazyLoadingCachingMap.java | 30 ++-- .../ghidra/program/model/data/Category.java | 13 ++ 5 files changed, 216 insertions(+), 37 deletions(-) diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java index b846c40931..c8128b93a5 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/data/CategoryTest.java @@ -575,6 +575,37 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest { assertEquals(comps.length - 1, newDt.getDefinedComponents().length); } + @Test + public void testDataTypeConflictHandling() throws Exception { + Category sub1 = root.createCategory("Cat1"); + DataType dt1 = new StructureDataType("DT", 1); + DataType dt2 = new StructureDataType("DT", 2); + DataType added1 = sub1.addDataType(dt1, null); + DataType added2 = sub1.addDataType(dt2, null); + assertEquals("DT", added1.getName()); + assertEquals("DT.conflict", added2.getName()); + + List list = sub1.getDataTypesByBaseName("DT"); + assertEquals(2, list.size()); + assertEquals(added1, list.get(0)); + assertEquals(added2, list.get(1)); + + list = sub1.getDataTypesByBaseName("DT.conflict"); + assertEquals(2, list.size()); + assertEquals(added1, list.get(0)); + assertEquals(added2, list.get(1)); + + sub1.remove(added2, TaskMonitor.DUMMY); + list = sub1.getDataTypesByBaseName("DT"); + assertEquals(1, list.size()); + assertEquals(added1, list.get(0)); + + list = sub1.getDataTypesByBaseName("DT.conflict"); + assertEquals(1, list.size()); + assertEquals(added1, list.get(0)); + + } + @Test public void testGetDataTypeManager() throws Exception { Category sub1 = root.createCategory("SubCat-A"); @@ -772,10 +803,7 @@ public class CategoryTest extends AbstractGhidraHeadedIntegrationTest { clearEvents(); struct2 = (Structure) newDt.insert(3, struct2).getDataType(); - int eventCount = getEventCount(); - if (4 != eventCount) { - System.err.println("halt!"); - } + assertEquals(5, getEventCount()); Event ev = getEvent(4); assertEquals("DT Changed", ev.evName); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java index 348b6be6c2..5f96e2b3bc 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java @@ -16,8 +16,7 @@ package ghidra.program.database.data; import java.io.IOException; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import db.Record; @@ -26,6 +25,7 @@ import ghidra.program.database.DatabaseObject; import ghidra.program.model.data.*; import ghidra.program.model.data.DataTypeConflictHandler.ConflictResult; import ghidra.util.InvalidNameException; +import ghidra.util.Lock; import ghidra.util.exception.AssertException; import ghidra.util.exception.DuplicateNameException; import ghidra.util.task.TaskMonitor; @@ -41,6 +41,7 @@ class CategoryDB extends DatabaseObject implements Category { private LazyLoadingCachingMap subcategoryMap; private LazyLoadingCachingMap dataTypeMap; + private ConflictMap conflictMap; /** * Category Constructor @@ -57,19 +58,19 @@ class CategoryDB extends DatabaseObject implements Category { this.name = name; this.parent = parent; - subcategoryMap = new LazyLoadingCachingMap<>(mgr.lock, CategoryDB.class) { + subcategoryMap = new LazyLoadingCachingMap<>(mgr.lock) { @Override public Map loadMap() { return buildSubcategoryMap(); } }; - dataTypeMap = new LazyLoadingCachingMap<>(mgr.lock, DataType.class) { + dataTypeMap = new LazyLoadingCachingMap<>(mgr.lock) { @Override public Map loadMap() { return createDataTypeMap(); } }; - + conflictMap = new ConflictMap(mgr.lock); } /** @@ -102,6 +103,7 @@ class CategoryDB extends DatabaseObject implements Category { protected boolean refresh(Record rec) { subcategoryMap.clear(); dataTypeMap.clear(); + conflictMap.clear(); if (isRoot()) { return true; @@ -210,13 +212,26 @@ class CategoryDB extends DatabaseObject implements Category { return map; } + private String getBaseName(String dataTypeName) { + int indexOf = dataTypeName.indexOf(DataType.CONFLICT_SUFFIX); + if (indexOf <= 0) { + return dataTypeName; + } + return dataTypeName.substring(0, indexOf); + } + + private boolean isConflictName(String dataTypeName) { + return dataTypeName.contains(DataType.CONFLICT_SUFFIX); + } + /** * @see ghidra.program.model.data.Category#getCategories() */ @Override public Category[] getCategories() { validate(mgr.lock); - return subcategoryMap.valuesToArray(); + Collection categories = subcategoryMap.values(); + return categories.toArray(new Category[categories.size()]); } /** @@ -225,7 +240,8 @@ class CategoryDB extends DatabaseObject implements Category { @Override public DataType[] getDataTypes() { validate(mgr.lock); - return dataTypeMap.valuesToArray(); + Collection dataTypes = dataTypeMap.values(); + return dataTypes.toArray(new DataType[dataTypes.size()]); } /** @@ -587,19 +603,137 @@ class CategoryDB extends DatabaseObject implements Category { } void dataTypeRenamed(DataType childDataType, String oldName) { - dataTypeMap.remove(oldName); - dataTypeMap.put(childDataType.getName(), childDataType); + dataTypeRemoved(oldName); + dataTypeAdded(childDataType); } - void dataTypeAdded(DataType childDataType) { - dataTypeMap.put(childDataType.getName(), childDataType); + void dataTypeAdded(DataType dataType) { + String dtName = dataType.getName(); + dataTypeMap.put(dtName, dataType); + if (isConflictName(dtName)) { + conflictMap.addDataType(dataType); + } } void dataTypeRemoved(String dataTypeName) { dataTypeMap.remove(dataTypeName); + if (isConflictName(dataTypeName)) { + conflictMap.removeDataTypeName(dataTypeName); + } } void categoryAdded(CategoryDB cat) { subcategoryMap.put(cat.getName(), cat); } + + @Override + public List getDataTypesByBaseName(String dataTypeName) { + List list = new ArrayList<>(); + String baseName = getBaseName(dataTypeName); + + DataType baseType = dataTypeMap.get(baseName); + if (baseType != null) { + list.add(baseType); + } + + List relatedNameDataTypes = conflictMap.getDataTypesForBaseName(baseName); + list.addAll(relatedNameDataTypes); + return list; + } + + /** + * Class to handle complexities of having a map as the value in a LazyLoadingCachingMap + * This map uses data type's base name as the key (i.e. all .conflict suffixex stripped off.) + * The value is another map that maps the actual data type's name to the datatype. This map + * effectively provides an efficient way to get all data types in a category that have the + * same name, but possibly have had their name modified (by appending .conflict) to get around + * the requirement that names have to be unique in the same category. + */ + class ConflictMap extends LazyLoadingCachingMap> { + + ConflictMap(Lock lock) { + super(lock); + } + + /** + * Creates a map of all data types whose name has a .conflict suffix where the key + * is the base name and the value is a map of actual name to data type. This mapping is + * maintained as a lazy cache map. + * @return the loaded map + */ + @Override + protected Map> loadMap() { + Map> map = new HashMap<>(); + Collection values = dataTypeMap.values(); + for (DataType dataType : values) { + String dataTypeName = dataType.getName(); + if (isConflictName(dataTypeName)) { + String baseName = getBaseName(dataTypeName); + Map innerMap = map.get(baseName); + if (innerMap == null) { + innerMap = new HashMap<>(); + map.put(baseName, innerMap); + } + innerMap.put(dataTypeName, dataType); + } + } + return map; + } + + /** + * Adds the data type to the conflict mapping structure. If the mapping is currently not + * loaded then this method can safely do nothing. + * @param dataType the data type to add to the mapping if the mapping is already loaded + */ + synchronized void addDataType(DataType dataType) { + Map> map = getMap(); + if (map == null) { + return; + } + + String dataTypeName = dataType.getName(); + String baseName = getBaseName(dataTypeName); + Map innerMap = map.get(baseName); + if (innerMap == null) { + innerMap = new HashMap<>(); + put(baseName, innerMap); + } + innerMap.put(dataTypeName, dataType); + } + + /** + * Removes the data type with the given name from the conflict mapping structure. If the + * mapping is currently not loaded then this method can safely do nothing. + * @param dataTypeName the name of the data type to remove from this mapping + */ + synchronized void removeDataTypeName(String dataTypeName) { + Map> map = getMap(); + if (map == null) { + return; + } + String baseName = getBaseName(dataTypeName); + Map innerMap = map.get(baseName); + if (innerMap == null) { + return; + } + innerMap.remove(dataTypeName); + } + + /** + * Returns a list of all data types that have conflict names for the given base name + * @param baseName the data type base name to search for (i.e. the .conflict suffix removed) + * @return a list of all conflict named data types that would have the given base name if + * no conflicts existed + */ + List getDataTypesForBaseName(String baseName) { + Map map = get(baseName); + if (map == null) { + return Collections.emptyList(); + } + synchronized (this) { + return new ArrayList<>(map.values()); + } + } + + } } 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 24d17bf75f..e862a76f4d 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 @@ -934,14 +934,12 @@ abstract public class DataTypeManagerDB implements DataTypeManager { if (category == null) { return null; } - String namePrefix = dtName + DataType.CONFLICT_SUFFIX; - DataType[] dataTypes = category.getDataTypes(); - for (DataType candidate : dataTypes) { + List relatedByName = category.getDataTypesByBaseName(dtName); + + for (DataType candidate : relatedByName) { String candidateName = candidate.getName(); - if (candidateName.startsWith(namePrefix)) { - if (!candidateName.equals(excludedName) && candidate.isEquivalent(dataType)) { - return candidate; - } + if (!candidateName.equals(excludedName) && candidate.isEquivalent(dataType)) { + return candidate; } } return null; @@ -3210,11 +3208,11 @@ abstract public class DataTypeManagerDB implements DataTypeManager { long[] ids = parentChildAdapter.getParentIds(childID); // TODO: consider deduping ids using Set List dts = new ArrayList<>(); - for (int i = 0; i < ids.length; i++) { - DataType dt = getDataType(ids[i]); + for (long id : ids) { + DataType dt = getDataType(id); if (dt == null) { // cleanup invalid records for missing parent - attemptRecordRemovalForParent(ids[i]); + attemptRecordRemovalForParent(id); } else { dts.add(dt); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java index 5f3ef6cb9c..75758544a4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java @@ -16,8 +16,7 @@ package ghidra.program.database.data; import java.lang.ref.SoftReference; -import java.lang.reflect.Array; -import java.util.Map; +import java.util.*; import ghidra.util.Lock; @@ -39,11 +38,9 @@ public abstract class LazyLoadingCachingMap { private Lock lock; private SoftReference> softRef; - private Class valueClass; - protected LazyLoadingCachingMap(Lock lock, Class valueClass) { + protected LazyLoadingCachingMap(Lock lock) { this.lock = lock; - this.valueClass = valueClass; } /** @@ -96,13 +93,13 @@ public abstract class LazyLoadingCachingMap { } } - public V[] valuesToArray() { + /** + * Returns an unmodifiable view of the values in this map. + * @return an unmodifiable view of the values in this map. + */ + public Collection values() { Map map = getOrLoadMap(); - synchronized (this) { - @SuppressWarnings("unchecked") - V[] array = (V[]) Array.newInstance(valueClass, map.size()); - return map.values().toArray(array); - } + return Collections.unmodifiableCollection(map.values()); } private Map getOrLoadMap() { @@ -113,6 +110,14 @@ public abstract class LazyLoadingCachingMap { return map; } } + + // We must get the database lock before calling loadMap(). Also, we can't get the + // database lock while having the synchronization lock for this class or a deadlock can + // occur. Note: all other places where the map is being used or manipulated, it must be done + // while having the class's synchronization lock since the map itself is not thread safe. + // It should be safe here since it creates a new map and then in one operation it sets it + // as the map to be used elsewhere. + lock.acquire(); try { map = getMap(); @@ -132,11 +137,12 @@ public abstract class LazyLoadingCachingMap { * "lock". * @return the underlying map of key,value pairs or null if it is currently not loaded. */ - private Map getMap() { + protected Map getMap() { if (softRef == null) { return null; } return softRef.get(); } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java index fd052237c8..29cb25610c 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java @@ -15,6 +15,8 @@ */ package ghidra.program.model.data; +import java.util.List; + import ghidra.util.InvalidNameException; import ghidra.util.exception.DuplicateNameException; import ghidra.util.task.TaskMonitor; @@ -48,6 +50,17 @@ public interface Category extends Comparable { */ public abstract DataType[] getDataTypes(); + /** + * Get all data types in this category whose base name matches the base name of the given name. + * The base name of a name if the first part of the string up to where the first ".conflict" + * occurs. In other words find all data types whose name matches the given name once + * any conflict suffixes have been removed from both both the given name and the data types + * that are being scanned. + * @param name the name for which to get conflict related data types in this category + * @return a list of data types that have the same base name as the base name of the given name + */ + public abstract List getDataTypesByBaseName(String name); + /** * Adds the given datatype to this category. * @param dt the datatype to add to this category. From 687ce7f529d17f0fa215c2d8193b39b6ea8f636a Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 11 Feb 2020 15:52:10 -0500 Subject: [PATCH 32/36] GT-3531 corrected DomainFile.isVersioned() for checked-out file. Revised language upgrade support to facilitate optional context reset. --- .../ghidra/framework/data/GhidraFileData.java | 2 +- .../ghidra/program/database/ProgramDB.java | 16 +++---- .../register/ProgramRegisterContextDB.java | 45 ++++++++++++++++--- .../lang/GhidraLanguagePropertyKeys.java | 7 +++ 4 files changed, 54 insertions(+), 16 deletions(-) diff --git a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java index bff3212273..3d341207ae 100644 --- a/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java +++ b/Ghidra/Framework/Project/src/main/java/ghidra/framework/data/GhidraFileData.java @@ -580,7 +580,7 @@ public class GhidraFileData { boolean isVersioned() { synchronized (fileSystem) { if (versionedFolderItem == null) { - return false; + return isCheckedOut(); } return !isHijacked(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java index 992e326e2e..bc6386b766 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/ProgramDB.java @@ -284,7 +284,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM if (monitor == null) { monitor = TaskMonitorAdapter.DUMMY; } - + boolean success = false; try { int id = startTransaction("create program"); @@ -2284,8 +2284,9 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM * Translate language * @param translator language translator, if null only re-disassembly will occur. * @param newCompilerSpecID new compiler specification which corresponds to new language, may be null. - * @param monitor - * @throws LockException + * @param forceRedisassembly if true a redisassembly will be forced even if not required + * @param monitor task monitor + * @throws LockException if exclusive access is missing */ public void setLanguage(LanguageTranslator translator, CompilerSpecID newCompilerSpecID, boolean forceRedisassembly, TaskMonitor monitor) throws LockException { @@ -2296,7 +2297,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM try { setEventsEnabled(false); try { - boolean notifyCodeManager = true; + boolean redisassemblyRequired = true; int oldLanguageVersion = languageVersion; int oldLanguageMinorVersion = languageMinorVersion; if (translator != null) { @@ -2311,7 +2312,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM } else if (!forceRedisassembly && language.getVersion() == languageVersion && language.getMinorVersion() == languageMinorVersion) { - notifyCodeManager = false; // compiler spec change only + redisassemblyRequired = false; // compiler spec change only Msg.info(this, "Setting compiler spec for Program " + getName() + ": " + compilerSpecID + " -> " + newCompilerSpecID); } @@ -2350,15 +2351,14 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM monitor.setProgress(0); ProgramRegisterContextDB contextMgr = (ProgramRegisterContextDB) getProgramContext(); - if (translator != null) { + if (redisassemblyRequired) { contextMgr.setLanguage(translator, compilerSpec, memoryManager, monitor); } else { - // force re-initialization contextMgr.initializeDefaultValues(language, compilerSpec); } - if (notifyCodeManager) { + if (redisassemblyRequired) { Disassembler.clearUnimplementedPcodeWarnings(this, null, monitor); repairContext(oldLanguageVersion, oldLanguageMinorVersion, translator, monitor); monitor.setMessage("Updating instructions..."); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java index 1249c92d96..2cd68cb0ee 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/register/ProgramRegisterContextDB.java @@ -72,12 +72,12 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple } if (openMode == DBConstants.UPGRADE && oldContextDataExists) { -// TODO: Make sure upgrade is working correctly before uncommenting -// try { -// OldProgramContextDB.removeOldContextData(dbHandle); -// } catch (IOException e) { -// errorHandler.dbError(e); -// } + try { + OldProgramContextDB.removeOldContextData(dbHandle); + } + catch (IOException e) { + errorHandler.dbError(e); + } } } @@ -161,6 +161,12 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple } } + /** + * Intialize context with default values defined by pspec and cspec. + * NOTE: cspec values take precedence + * @param lang processor language + * @param compilerSpec compiler specification + */ public void initializeDefaultValues(Language lang, CompilerSpec compilerSpec) { defaultRegisterValueMap.clear(); lang.applyContextSettings(this); @@ -288,9 +294,31 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple } } + /** + * Perform context upgrade due to a language change + * @param translator language translator required by major upgrades (may be null) + * @param newCompilerSpec new compiler specification + * @param programMemory program memory + * @param monitor task monitor + * @throws CancelledException thrown if monitor cancelled + */ public void setLanguage(LanguageTranslator translator, CompilerSpec newCompilerSpec, AddressSetView programMemory, TaskMonitor monitor) throws CancelledException { + if (translator == null) { + Language lang = program.getLanguage(); + boolean clearContext = Boolean.valueOf( + lang.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE)); + if (clearContext) { + RegisterValueStore store = registerValueMap.get(baseContextRegister); + if (store != null) { + store.clearAll(); + } + } + initializeDefaultValues(lang, newCompilerSpec); + return; + } + Language newLanguage = translator.getNewLanguage(); // Sort the registers by size so that largest come first. @@ -309,8 +337,11 @@ public class ProgramRegisterContextDB extends AbstractStoredProgramContext imple continue; } + boolean clearContext = register.isProcessorContext() && Boolean.valueOf( + newLanguage.getProperty(GhidraLanguagePropertyKeys.RESET_CONTEXT_ON_UPGRADE)); + // Update storage range map - if (!store.setLanguage(translator, monitor)) { + if (clearContext || !store.setLanguage(translator, monitor)) { // Clear and remove old register value store Msg.warn(this, "WARNING! Discarding all context for register " + register.getName()); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java index c438fb4d76..37c7ecf085 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/lang/GhidraLanguagePropertyKeys.java @@ -112,4 +112,11 @@ public final class GhidraLanguagePropertyKeys { * following the call. Non-returning functions can be detected in many cases. */ public static final String ENABLE_NO_RETURN_ANALYSIS = "enableNoReturnAnalysis"; + + /** + * Property to indicate that all stored instruction context should be cleared + * during a language upgrade operation which requires redisassembly. + * NOTE: This is an experimental concept which may be removed in the future + */ + public static final String RESET_CONTEXT_ON_UPGRADE = "resetContextOnUpgrade"; } From dcf22394a48f49badc53b2ba6ea97b3b9c56c32b Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Tue, 11 Feb 2020 16:19:43 -0500 Subject: [PATCH 33/36] Corrected minor bug in Assembler --- .../plugin/assembler/sleigh/grammars/AssemblySentential.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/grammars/AssemblySentential.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/grammars/AssemblySentential.java index b9a75abe7b..1a5388ddc8 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/grammars/AssemblySentential.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/app/plugin/assembler/sleigh/grammars/AssemblySentential.java @@ -149,7 +149,7 @@ public class AssemblySentential extends return Collections.singleton(new WhiteSpaceParseToken(grammar, this, "")); } if (Character.isLetterOrDigit(buffer.charAt(b)) && - Character.isLetterOrDigit(buffer.charAt(b - 1))) { + (b == 0 || Character.isLetterOrDigit(buffer.charAt(b - 1)))) { return Collections.emptySet(); } } From ab0b4e02df5cc75412c9d444b44ec7e129a59c98 Mon Sep 17 00:00:00 2001 From: ghidravore Date: Tue, 11 Feb 2020 17:54:54 -0500 Subject: [PATCH 34/36] GT-3535 changes from review --- .../program/database/data/CategoryDB.java | 44 +++++++++++-------- .../database/data/DataTypeManagerDB.java | 1 - .../database/data/LazyLoadingCachingMap.java | 6 ++- .../ghidra/program/model/data/Category.java | 10 +++-- 4 files changed, 35 insertions(+), 26 deletions(-) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java index 5f96e2b3bc..564b1e3814 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java @@ -636,20 +636,20 @@ class CategoryDB extends DatabaseObject implements Category { list.add(baseType); } - List relatedNameDataTypes = conflictMap.getDataTypesForBaseName(baseName); + List relatedNameDataTypes = conflictMap.getDataTypesByBaseName(baseName); list.addAll(relatedNameDataTypes); return list; } /** - * Class to handle complexities of having a map as the value in a LazyLoadingCachingMap - * This map uses data type's base name as the key (i.e. all .conflict suffixex stripped off.) - * The value is another map that maps the actual data type's name to the datatype. This map + * Class to handle the complexities of having a map as the value in a LazyLoadingCachingMap + * This map uses the data type's base name as the key (i.e. all .conflict suffixes stripped off.) + * The value is another map that maps the actual data type's name to the data type. This map * effectively provides an efficient way to get all data types in a category that have the * same name, but possibly have had their name modified (by appending .conflict) to get around * the requirement that names have to be unique in the same category. */ - class ConflictMap extends LazyLoadingCachingMap> { + private class ConflictMap extends LazyLoadingCachingMap> { ConflictMap(Lock lock) { super(lock); @@ -657,8 +657,10 @@ class CategoryDB extends DatabaseObject implements Category { /** * Creates a map of all data types whose name has a .conflict suffix where the key - * is the base name and the value is a map of actual name to data type. This mapping is - * maintained as a lazy cache map. + * is the base name and {@link LazyLoadingCachingMap} the value is a map of actual name to data type. This mapping is + * maintained as a lazy cache map. This is only called by the super class when the + * cached needs to be populated and we are depending on it to acquire the necessary + * database lock. (See {@link LazyLoadingCachingMap#loadMap()} * @return the loaded map */ @Override @@ -670,10 +672,7 @@ class CategoryDB extends DatabaseObject implements Category { if (isConflictName(dataTypeName)) { String baseName = getBaseName(dataTypeName); Map innerMap = map.get(baseName); - if (innerMap == null) { - innerMap = new HashMap<>(); - map.put(baseName, innerMap); - } + map.computeIfAbsent(baseName, b -> new HashMap<>()); innerMap.put(dataTypeName, dataType); } } @@ -682,10 +681,12 @@ class CategoryDB extends DatabaseObject implements Category { /** * Adds the data type to the conflict mapping structure. If the mapping is currently not - * loaded then this method can safely do nothing. + * loaded then this method can safely do nothing. This method is synchronized to provide + * thread safe access/manipulation of the map. * @param dataType the data type to add to the mapping if the mapping is already loaded */ synchronized void addDataType(DataType dataType) { + // if the cache is not currently populated, don't need to do anything Map> map = getMap(); if (map == null) { return; @@ -693,17 +694,14 @@ class CategoryDB extends DatabaseObject implements Category { String dataTypeName = dataType.getName(); String baseName = getBaseName(dataTypeName); - Map innerMap = map.get(baseName); - if (innerMap == null) { - innerMap = new HashMap<>(); - put(baseName, innerMap); - } + Map innerMap = map.computeIfAbsent(baseName, b -> new HashMap<>()); innerMap.put(dataTypeName, dataType); } /** * Removes the data type with the given name from the conflict mapping structure. If the - * mapping is currently not loaded then this method can safely do nothing. + * mapping is currently not loaded then this method can safely do nothing. This method is + * synchronized to provide thread safe access/manipulate of the map. * @param dataTypeName the name of the data type to remove from this mapping */ synchronized void removeDataTypeName(String dataTypeName) { @@ -725,11 +723,19 @@ class CategoryDB extends DatabaseObject implements Category { * @return a list of all conflict named data types that would have the given base name if * no conflicts existed */ - List getDataTypesForBaseName(String baseName) { + List getDataTypesByBaseName(String baseName) { + + // Note that the following call to get MUST NOT be in a synchronized block because + // it may trigger a loading of the cache which requires a database lock and you + // can't be synchronized on this class when acquiring a database lock or else a + // deadlock will occur. Map map = get(baseName); if (map == null) { return Collections.emptyList(); } + + // the following must be synchronized so that the implied iterator can complete without + // another thread changing the map's values. synchronized (this) { return new ArrayList<>(map.values()); } 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 e862a76f4d..bccbcb8563 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 @@ -3206,7 +3206,6 @@ abstract public class DataTypeManagerDB implements DataTypeManager { lock.acquire(); try { long[] ids = parentChildAdapter.getParentIds(childID); - // TODO: consider deduping ids using Set List dts = new ArrayList<>(); for (long id : ids) { DataType dt = getDataType(id); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java index 75758544a4..e491b57e7e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/LazyLoadingCachingMap.java @@ -44,7 +44,8 @@ public abstract class LazyLoadingCachingMap { } /** - * This method will reload the map data from scratch. + * This method will reload the map data from scratch. Subclass may assume that the database + * lock has been acquired. * @return a map containing all current key, value pairs. */ protected abstract Map loadMap(); @@ -113,7 +114,8 @@ public abstract class LazyLoadingCachingMap { // We must get the database lock before calling loadMap(). Also, we can't get the // database lock while having the synchronization lock for this class or a deadlock can - // occur. Note: all other places where the map is being used or manipulated, it must be done + // occur, since the other methods may be called while the client has the db lock. + // Note: all other places where the map is being used or manipulated, it must be done // while having the class's synchronization lock since the map itself is not thread safe. // It should be safe here since it creates a new map and then in one operation it sets it // as the map to be used elsewhere. diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java index 29cb25610c..9e3684b225 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/Category.java @@ -52,11 +52,13 @@ public interface Category extends Comparable { /** * Get all data types in this category whose base name matches the base name of the given name. - * The base name of a name if the first part of the string up to where the first ".conflict" - * occurs. In other words find all data types whose name matches the given name once - * any conflict suffixes have been removed from both both the given name and the data types + * The base name of a name is the first part of the string up to where the first ".conflict" + * occurs. In other words, finds all data types whose name matches the given name once + * any conflict suffixes have been removed from both the given name and the data types * that are being scanned. - * @param name the name for which to get conflict related data types in this category + * @param name the name for which to get conflict related data types in this category. Note: the + * name that is passed in will be normalized to its base name, so you may pass in names with .conflict + * appended as a convenience. * @return a list of data types that have the same base name as the base name of the given name */ public abstract List getDataTypesByBaseName(String name); From 4ce56458b8274cef6162bcb57d483b19b4da064c Mon Sep 17 00:00:00 2001 From: ghidravore Date: Tue, 11 Feb 2020 18:13:55 -0500 Subject: [PATCH 35/36] oops --- .../main/java/ghidra/program/database/data/CategoryDB.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java index 564b1e3814..7d277d2a7f 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/CategoryDB.java @@ -657,7 +657,8 @@ class CategoryDB extends DatabaseObject implements Category { /** * Creates a map of all data types whose name has a .conflict suffix where the key - * is the base name and {@link LazyLoadingCachingMap} the value is a map of actual name to data type. This mapping is + * is the base name and {@link LazyLoadingCachingMap} the value is a map of actual name + * to data type. This mapping is * maintained as a lazy cache map. This is only called by the super class when the * cached needs to be populated and we are depending on it to acquire the necessary * database lock. (See {@link LazyLoadingCachingMap#loadMap()} @@ -671,8 +672,8 @@ class CategoryDB extends DatabaseObject implements Category { String dataTypeName = dataType.getName(); if (isConflictName(dataTypeName)) { String baseName = getBaseName(dataTypeName); - Map innerMap = map.get(baseName); - map.computeIfAbsent(baseName, b -> new HashMap<>()); + Map innerMap = + map.computeIfAbsent(baseName, b -> new HashMap<>()); innerMap.put(dataTypeName, dataType); } } From d181cec0704cbed544ecceb2eb75de3b0d05bc40 Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Wed, 5 Feb 2020 17:32:13 -0500 Subject: [PATCH 36/36] Changes to ActionBuilder to allow creating actions that work on more specific ActionContext --- .../action/builder/AbstractActionBuilder.java | 120 ++++++++- .../docking/action/builder/ActionBuilder.java | 2 +- .../action/builder/MultiActionBuilder.java | 2 +- .../builder/MultiStateActionBuilder.java | 4 +- .../action/builder/ToggleActionBuilder.java | 2 +- .../docking/action/ActionBuilderTest.java | 247 ++++++++++++++++++ 6 files changed, 358 insertions(+), 19 deletions(-) create mode 100644 Ghidra/Framework/Docking/src/test/java/docking/action/ActionBuilderTest.java diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/AbstractActionBuilder.java b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/AbstractActionBuilder.java index ce39e05665..14b918d79d 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/AbstractActionBuilder.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/AbstractActionBuilder.java @@ -41,8 +41,15 @@ import resources.ResourceManager; * * @param The type of DockingAction to build * @param the Type of action builder + * @param The type of ActionContext. By default, the ActionContext type always starts as + * the base ActionContext class. If the client calls the {@link #withContext(Class)} method on + * the builder, then that class (which must be a subclass of ActionContext) becomes the ActionContext + * type that will be used for future calls to the builder methods that take predicates with + * ActionContext (i.e. {@link #enabledWhen(Predicate)} and {@link #validContextWhen(Predicate)}. + * This works by substituting a builder with a different ActionContext type when chaining after + * the {@link #withContext(Class)} call. */ -public abstract class AbstractActionBuilder> { +public abstract class AbstractActionBuilder> { /** * Name for the {@code DockingAction} @@ -54,6 +61,11 @@ public abstract class AbstractActionBuilder actionContextClass; + /** * The {@code KeyBindingType} for this {@code DockingAction} */ @@ -62,7 +74,7 @@ public abstract class AbstractActionBuilder actionCallback; + protected Consumer actionCallback; /** * Description for the {@code DockingAction}. (optional) @@ -147,17 +159,17 @@ public abstract class AbstractActionBuilder enabledPredicate; + private Predicate enabledPredicate; /** * Predicate for determining if an action should be included on the pop-up menu */ - private Predicate popupPredicate; + private Predicate popupPredicate; /** * Predicate for determining if an action is applicable for a given context */ - private Predicate validContextPredicate; + private Predicate validContextPredicate; /** * Builder constructor @@ -167,6 +179,7 @@ public abstract class AbstractActionBuilder action) { + public B onAction(Consumer action) { actionCallback = action; return self(); } @@ -501,7 +516,7 @@ public abstract class AbstractActionBuilder predicate) { + public B enabledWhen(Predicate predicate) { enabledPredicate = predicate; return self(); } @@ -524,7 +539,7 @@ public abstract class AbstractActionBuilder predicate) { + public B popupWhen(Predicate predicate) { popupPredicate = predicate; return self(); } @@ -540,11 +555,68 @@ public abstract class AbstractActionBuilder predicate) { + public B validContextWhen(Predicate predicate) { validContextPredicate = predicate; return self(); } + /** + * Sets the specific ActionContext type to use for the various predicate calls + * ({@link #validContextWhen(Predicate)}, {@link #enabledWhen(Predicate)}, and + * {@link #popupWhen(Predicate)}). + *

    + * In other words, this allows the client to specify the type of ActionContext that is valid for + * the action being built. + *

    + * To be effective, this method must be called before setting any of the predicates + * such as the {@link #enabledWhen(Predicate)}. Once this method is called you can define your + * predicates using the more specific ActionContext and be assured your predicates will only + * be called when the current action context is the type (or sub-type) of the context you have + * specified here. + *

    + * For example, assume you have an action that is only enabled when the context is of type + * FooActionContext. If you don't call this method to set the ActionContext type, you would have + * to write your predicate something like this: + *

    +	 * builder.enabledWhen(context -> {
    +	 *     if (!(context instanceof FooContext)) {
    +	 *         return false;
    +	 *     }
    +	 *     return ((FooContext) context).isAwesome();
    +	 * });
    +	 * 
    + * But by first calling the builder method withContext(FooContext.class), you can + * simply write: + * + *
    +	 * builder.enabledWhen(context -> return context.isAwesome() }
    +	 * 
    + * + * @param newActionContextClass the more specific ActionContext type. + * @param The new ActionContext type (as determined by the newActionContextClass) that + * the returned builder will have. + * @param the new builder type. + * @return an ActionBuilder whose generic types have been modified to match the new ActionContext. + * It still contains all the configuration that has been applied so far. + */ + @SuppressWarnings("unchecked") + public > B2 withContext( + Class newActionContextClass) { + + // To make this work, we need to return a builder whose ActionContext is AC2 and not AC + // (which is what this builder is now) + // + // Since we "know" that the only thing that matters regarding the ActionContext type is that + // the template type (AC) must match the type of actionContextClass instance variable, we + // can get away with returning this same builder and casting it to be a builder with type + // AC2 instead of AC. We can do this since we set the actionContextClass below + + actionContextClass = newActionContextClass; + + B2 newSelf = (B2) self(); + return newSelf; + } + protected void validate() { if (actionCallback == null) { throw new IllegalStateException( @@ -566,16 +638,36 @@ public abstract class AbstractActionBuilder adaptPredicate(Predicate predicate) { + if (actionContextClass == ActionContext.class) { + // don't wrap the predicate if it doesn't need it + return (Predicate) predicate; + } + // Convert a sub-classed ActionContext predicate to a plain ActionContext predicate + Predicate predicateAdapter = (ac) -> { + return actionContextClass.isInstance(ac) && predicate.test((C) ac); + }; + return predicateAdapter; + } + protected boolean isPopupAction() { return popupPath != null; } diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ActionBuilder.java b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ActionBuilder.java index f371827b2d..acaacea3e5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ActionBuilder.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ActionBuilder.java @@ -21,7 +21,7 @@ import docking.action.DockingAction; * Builder for {@link DockingAction}s */ public class ActionBuilder - extends AbstractActionBuilder { + extends AbstractActionBuilder { /** * Builder constructor diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiActionBuilder.java b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiActionBuilder.java index f2107e9af3..3b06883b79 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiActionBuilder.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiActionBuilder.java @@ -26,7 +26,7 @@ import docking.menu.MultiActionDockingAction; * Builder for {@link MultiActionDockingAction} */ public class MultiActionBuilder - extends AbstractActionBuilder { + extends AbstractActionBuilder { /** * List of actions for the the MultActionDockingAction */ diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiStateActionBuilder.java b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiStateActionBuilder.java index 09bfa5410c..3a6438117b 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiStateActionBuilder.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/MultiStateActionBuilder.java @@ -27,7 +27,7 @@ import docking.widgets.EventTrigger; * @param The action state type */ public class MultiStateActionBuilder extends - AbstractActionBuilder, MultiStateActionBuilder> { + AbstractActionBuilder, ActionContext, MultiStateActionBuilder> { private BiConsumer, EventTrigger> actionStateChangedCallback; private boolean performActionOnButtonClick; @@ -77,7 +77,7 @@ public class MultiStateActionBuilder extends public MultiStateDockingAction build() { validate(); MultiStateDockingAction action = - new MultiStateDockingAction(name, owner, isToolbarAction()) { + new MultiStateDockingAction<>(name, owner, isToolbarAction()) { @Override public void actionStateChanged(ActionState newActionState, diff --git a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ToggleActionBuilder.java b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ToggleActionBuilder.java index 1219ef4a79..3123c35aa5 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ToggleActionBuilder.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/action/builder/ToggleActionBuilder.java @@ -21,7 +21,7 @@ import docking.action.ToggleDockingAction; * Builder for {@link ToggleDockingAction}s */ public class ToggleActionBuilder extends - AbstractActionBuilder { + AbstractActionBuilder { /** * The initial toggle state for the action diff --git a/Ghidra/Framework/Docking/src/test/java/docking/action/ActionBuilderTest.java b/Ghidra/Framework/Docking/src/test/java/docking/action/ActionBuilderTest.java new file mode 100644 index 0000000000..11be0fd630 --- /dev/null +++ b/Ghidra/Framework/Docking/src/test/java/docking/action/ActionBuilderTest.java @@ -0,0 +1,247 @@ +/* ### + * 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 docking.action; + +import static org.junit.Assert.*; + +import javax.swing.KeyStroke; + +import org.junit.Test; + +import docking.ActionContext; +import docking.action.builder.ActionBuilder; +import resources.Icons; + +public class ActionBuilderTest { + private int actionCount = 0; + + + @Test + public void testDescription() { + DockingAction action = new ActionBuilder("Test", "Test") + .description("foo") + .onAction(e -> actionCount++) + .build(); + assertEquals("foo", action.getDescription()); + } + + @Test + public void testMenuPath() { + DockingAction action = new ActionBuilder("Test", "Test") + .menuPath("foo", "bar") + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getMenuBarData(); + assertEquals("foo->bar", data.getMenuPathAsString()); + } + + @Test + public void testMenuGroup() { + DockingAction action = new ActionBuilder("Test", "Test") + .menuPath("foo", "bar") + .menuGroup("A", "B") + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getMenuBarData(); + assertEquals("A", data.getMenuGroup()); + assertEquals("B", data.getMenuSubGroup()); + } + + @Test + public void testMenuIcon() { + DockingAction action = new ActionBuilder("Test", "Test") + .menuPath("foo", "bar") + .menuIcon(Icons.ADD_ICON) + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getMenuBarData(); + assertEquals(Icons.ADD_ICON, data.getMenuIcon()); + } + + @Test + public void testMenuMnemonic() { + DockingAction action = new ActionBuilder("Test", "Test") + .menuPath("foo", "bar") + .menuMnemonic(5) + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getMenuBarData(); + assertEquals(5, data.getMnemonic()); + } + + @Test + public void testPopupPath() { + DockingAction action = new ActionBuilder("Test", "Test") + .popupMenuPath("foo", "bar") + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getPopupMenuData(); + assertEquals("foo->bar", data.getMenuPathAsString()); + } + + @Test + public void testPopupGroup() { + DockingAction action = new ActionBuilder("Test", "Test") + .popupMenuPath("foo", "bar") + .popupMenuGroup("A", "B") + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getPopupMenuData(); + assertEquals("A", data.getMenuGroup()); + assertEquals("B", data.getMenuSubGroup()); + } + + @Test + public void testPopupIcon() { + DockingAction action = new ActionBuilder("Test", "Test") + .popupMenuPath("foo", "bar") + .popupMenuIcon(Icons.ADD_ICON) + .onAction(e -> actionCount++) + .build(); + + MenuData data = action.getPopupMenuData(); + assertEquals(Icons.ADD_ICON, data.getMenuIcon()); + } + + @Test + public void testToolbarIcon() { + DockingAction action = new ActionBuilder("Test", "Test") + .toolBarIcon(Icons.ADD_ICON) + .onAction(e -> actionCount++) + .build(); + + ToolBarData data = action.getToolBarData(); + assertEquals(Icons.ADD_ICON, data.getIcon()); + } + + @Test + public void testToolbarGroup() { + DockingAction action = new ActionBuilder("Test", "Test") + .toolBarIcon(Icons.ADD_ICON) + .toolBarGroup("A", "B") + .onAction(e -> actionCount++) + .build(); + + ToolBarData data = action.getToolBarData(); + assertEquals("A", data.getToolBarGroup()); + assertEquals("B", data.getToolBarSubGroup()); + } + + @Test + public void testKeyBindingKeyStroke() { + DockingAction action = new ActionBuilder("Test", "Test") + .keyBinding(KeyStroke.getKeyStroke("A")) + .onAction(e -> actionCount++) + .build(); + + assertEquals(KeyStroke.getKeyStroke("A"), action.getKeyBinding()); + } + + @Test + public void testKeyBindingKeyString() { + DockingAction action = new ActionBuilder("Test", "Test") + .keyBinding("ALT A") + .onAction(e -> actionCount++) + .build(); + + assertEquals(KeyStroke.getKeyStroke("ALT A"), action.getKeyBinding()); + } + + @Test + public void testOnAction() { + DockingAction action = new ActionBuilder("Test", "Test") + .onAction(e -> actionCount = 6) + .build(); + + assertEquals(0, actionCount); + action.actionPerformed(new ActionContext()); + assertEquals(6, actionCount); + } + + @Test + public void testEnabled() { + DockingAction action = new ActionBuilder("Test", "Test") + .enabled(true) + .onAction(e -> actionCount++) + .build(); + assertTrue(action.isEnabled()); + + action = new ActionBuilder("Test", "Test") + .enabled(false) + .onAction(e -> actionCount++) + .build(); + assertFalse(action.isEnabled()); + + } + + @Test + public void testEnabledWhen() { + DockingAction action = new ActionBuilder("Test", "Test") + .enabledWhen(c -> c.getContextObject() == this) + .onAction(e -> actionCount++) + .build(); + + assertTrue(action.isEnabledForContext(new ActionContext(null, this, null))); + assertFalse(action.isEnabledForContext(new ActionContext())); + } + + @Test + public void testValidContextWhen() { + DockingAction action = new ActionBuilder("Test", "Test") + .validContextWhen(c -> c.getContextObject() == this) + .onAction(e -> actionCount++) + .build(); + + assertTrue(action.isValidContext(new ActionContext(null, this, null))); + assertFalse(action.isValidContext(new ActionContext())); + } + + @Test + public void testPopupWhen() { + DockingAction action = new ActionBuilder("Test", "Test") + .popupWhen(c -> c.getContextObject() == this) + .onAction(e -> actionCount++) + .build(); + + assertTrue(action.isAddToPopup(new ActionContext(null, this, null))); + assertFalse(action.isAddToPopup(new ActionContext())); + } + + @Test + public void testWithContext() { + DockingAction action = new ActionBuilder("Test", "Test") + .withContext(FooActionContext.class) + .enabledWhen(c -> c.foo()) + .onAction(e -> actionCount++) + .build(); + + assertFalse(action.isEnabledForContext(new ActionContext())); + assertTrue(action.isEnabledForContext(new FooActionContext())); + } + + static class FooActionContext extends ActionContext { + public boolean foo() { + return true; + } + + } +}