diff --git a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm index ddbb78a6f7..9a5dd24ece 100644 --- a/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm +++ b/Ghidra/Features/Base/src/main/help/help/topics/DataTypeEditors/StructureEditor.htm @@ -179,14 +179,12 @@
-When a structure is unaligned, with the exception of bitfields, each component immediately - follows the one before it. In - other words no automatic alignment or padding occurs. Unaligned structures can contain - Unaligned structures should be used to position components with known data - types at specific offsets within the structure. Therefore the structure editor tries to - prevent defined components (those other than Undefined bytes) from accidentally being moved - to a different offset when performing operations like drag and drop, although undefined bytes - may be consumed.
+When a structure is unaligned, with the exception of bitfields, each component shown within + the editor immediately follows the one before it. In other words, no automatic alignment or padding occurs. + Unaligned structures may be used to position components with known data + types at specific offsets within a structure. Therefore, when editing an unaligned structure, + the structure editor attempts to prevent defined components from moving + to a different offset when performing operations like drag and drop which may consume undefined bytes.
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 94552ee191..327aa91932 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 @@ -812,7 +812,7 @@ abstract public class DataTypeManagerDB implements DataTypeManager { } finally { if (isResolveCacheOwner) { - flushResolveCacheAndClearQueue(); + flushResolveQueue(true); } if (isEquivalenceCacheOwner) { clearEquivalenceCache(); @@ -1142,15 +1142,26 @@ abstract public class DataTypeManagerDB implements DataTypeManager { lock.acquire(); boolean isEquivalenceCacheOwner = activateEquivalenceCache(); boolean isResolveCacheOwner = activateResolveCache(); + // TODO: extended hold time on lock may cause the GUI to become + // unresponsive. Consider releasing lock between resolves, although + // this exposes risk of having active resolve queue/cache without lock try { + monitor.setMessage("Adding datatypes..."); + monitor.setMaximum(dataTypes.size()); + monitor.setProgress(0); + int i = 0; for (DataType dt : dataTypes) { monitor.checkCanceled(); resolve(dt, handler); + if (isResolveCacheOwner) { + flushResolveQueue(false); + } + monitor.setProgress(++i); } } finally { if (isResolveCacheOwner) { - flushResolveCacheAndClearQueue(); + flushResolveQueue(true); } if (isEquivalenceCacheOwner) { clearEquivalenceCache(); @@ -3764,19 +3775,17 @@ abstract public class DataTypeManagerDB implements DataTypeManager { /** * Activate resolveCache and associated resolveQueue if not already active. If * this method returns true caller is responsible for flushing resolveQueue and - * invoking {@link #flushResolveCacheAndClearQueue(DataTypeConflictHandler)} - * when resolve. For each completed resolve - * {@link #cacheResolvedDataType(DataType, DataType)} should be called. + * invoking {@link #flushResolveQueue(boolean)} when resolve complete. + * For each completed resolve {@link #cacheResolvedDataType(DataType, DataType)} + * should be invoked. * - * @return true if resolveCache and resolveQueue activated else false if - * previously activated. + * @return true if resolveCache activated else false if already active. */ boolean activateResolveCache() { if (resolveCache != null) { return false; } resolveCache = new IdentityHashMap<>(); - resolveQueue = new TreeSet<>(); return true; } @@ -3788,10 +3797,19 @@ abstract public class DataTypeManagerDB implements DataTypeManager { */ void queuePostResolve(DataTypeDB resolvedDt, DataType definitionDt) { resolvedDt.resolving = true; + if (resolveQueue == null) { + resolveQueue = new TreeSet<>(); + } resolveQueue.add(new ResolvePair(resolvedDt, definitionDt)); } - void flushResolveCacheAndClearQueue() { + void flushResolveQueue(boolean deactivateCache) { + if (resolveQueue == null) { + if (deactivateCache) { + resolveCache = null; + } + return; + } DataTypeConflictHandler handler = getDependencyConflictHandler(); while (!resolveQueue.isEmpty()) { ResolvePair resolvePair = resolveQueue.pollFirst(); @@ -3805,8 +3823,10 @@ abstract public class DataTypeManagerDB implements DataTypeManager { resolvedDt.pointerPostResolveRequired = false; } } - resolveCache = null; resolveQueue = null; + if (deactivateCache) { + resolveCache = null; + } } private DataType getCachedResolve(DataType dt) { 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 afb5024090..ba73acb18b 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 @@ -1168,7 +1168,7 @@ class StructureDB extends CompositeDB implements Structure { } finally { if (isResolveCacheOwner) { - dataMgr.flushResolveCacheAndClearQueue(); + dataMgr.flushResolveQueue(true); } lock.release(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java index 1c3bb0faef..34bb985bb2 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/data/UnionDB.java @@ -257,7 +257,7 @@ class UnionDB extends CompositeDB implements Union { } finally { if (isResolveCacheOwner) { - dataMgr.flushResolveCacheAndClearQueue(); + dataMgr.flushResolveQueue(true); } lock.release(); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java index 98a51620eb..18cb06dbc4 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/data/DataTypeManager.java @@ -101,6 +101,9 @@ public interface DataTypeManager { * Sequentially adds a collection of datatypes to this data manager. * This method provides the added benefit of equivalence caching * for improved performance. + *
+ * WARNING: This is an experimental method whoose use may cause the GUI and + * task monitor to become unresponsive due to extended hold times on the manager lock. * @param dataTypes collection of datatypes * @param handler conflict handler * @param monitor task monitor