diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java index a6630d0802..d75cd2d321 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/emulation/ProgramEmulationUtils.java @@ -28,6 +28,7 @@ import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils; import ghidra.app.plugin.core.debug.service.modules.DebuggerStaticMappingUtils.Extrema; import ghidra.app.services.DebuggerEmulationService; import ghidra.framework.model.DomainFile; +import ghidra.pcode.emu.EmulatorUtilities; import ghidra.program.model.address.*; import ghidra.program.model.lang.*; import ghidra.program.model.listing.Program; @@ -142,7 +143,7 @@ public class ProgramEmulationUtils { EMU_SESSION_SCHEMA = EMU_CTX.getSchema(new SchemaName("EmuSession")); } - public static final String BLOCK_NAME_STACK = "STACK"; + public static final String BLOCK_NAME_STACK = EmulatorUtilities.BLOCK_NAME_STACK; /** * Conventional prefix for first snapshot to identify "pure emulation" traces. @@ -428,7 +429,7 @@ public class ProgramEmulationUtils { final AddressRange alloc; if (cSpec.stackGrowsNegative()) { Address max = spAddr.subtractWrap(1); - Address min = spAddr.subtractWrapSpace(size); + Address min = spAddr.subtractWrap(size); if (min.compareTo(max) > 0) { alloc = new AddressRangeImpl(max.getAddressSpace().getMinAddress(), max); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java index 944e639c33..fad17ba9ba 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/DBTraceTimeViewport.java @@ -19,6 +19,7 @@ import java.util.*; import java.util.function.Function; import java.util.stream.Collectors; +import generic.util.MergeSortingIterator; import ghidra.program.model.address.*; import ghidra.trace.model.*; import ghidra.trace.model.Lifespan.DefaultLifeSet; @@ -370,7 +371,7 @@ public class DBTraceTimeViewport implements TraceTimeViewport { List> iters = getOrderedSpans().stream() .map(rng -> iterFunc.apply(rng.lmax())) .collect(Collectors.toList()); - return new UniqIterator<>(new MergeSortingIterator<>(iters, comparator)); + return new DistinctIterator<>(new MergeSortingIterator<>(iters, comparator)); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsMemoryView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsMemoryView.java index 71d948abff..576a4704b6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsMemoryView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsMemoryView.java @@ -19,7 +19,7 @@ import java.util.Collections; import java.util.Iterator; import java.util.concurrent.locks.Lock; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.program.model.address.*; import ghidra.trace.database.DBTraceUtils; import ghidra.trace.database.space.DBTraceDelegatingManager; @@ -361,7 +361,7 @@ public abstract class AbstractBaseDBTraceCodeUnitsMemoryView get(long snap, AddressSetView set, boolean forward) { - return () -> NestedIterator.start(set.iterator(forward), + return () -> FlattenedIterator.start(set.iterator(forward), r -> get(snap, r, forward).iterator()); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsView.java index 4cad7ec97c..63db71f21e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractBaseDBTraceCodeUnitsView.java @@ -15,7 +15,7 @@ */ package ghidra.trace.database.listing; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.program.model.address.*; import ghidra.trace.model.*; import ghidra.trace.model.listing.TraceBaseCodeUnitsView; @@ -124,7 +124,7 @@ public abstract class AbstractBaseDBTraceCodeUnitsView get(long snap, AddressSetView set, boolean forward) { - return () -> NestedIterator.start(set.iterator(forward), + return () -> FlattenedIterator.start(set.iterator(forward), r -> this.get(snap, r, forward).iterator()); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractComposedDBTraceCodeUnitsView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractComposedDBTraceCodeUnitsView.java index c48d2a102b..298db34123 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractComposedDBTraceCodeUnitsView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/listing/AbstractComposedDBTraceCodeUnitsView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.Iterator; import java.util.stream.StreamSupport; +import generic.util.MergeSortingIterator; import ghidra.program.model.address.*; import ghidra.trace.model.TraceAddressSnapRange; import ghidra.trace.model.listing.TraceCodeUnit; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java index 62257d7a01..5ae8b33e3a 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewListing.java @@ -20,7 +20,8 @@ import java.util.*; import org.apache.commons.collections4.IteratorUtils; -import generic.NestedIterator; +import generic.util.MergeSortingIterator; +import generic.util.FlattenedIterator; import ghidra.program.database.ProgramDB; import ghidra.program.database.code.InstructionDB; import ghidra.program.database.function.OverlappingFunctionException; @@ -348,7 +349,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV } // TODO: The property map doesn't heed forking. return new WrappingCodeUnitIterator( - NestedIterator + FlattenedIterator .start(map.getAddressSetView(Lifespan.at(program.snap)).iterator(forward), rng -> getTopCodeIterator( s -> codeOperations.codeUnits().get(s, rng, forward).iterator(), @@ -371,7 +372,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV } // TODO: The property map doesn't heed forking. return new WrappingCodeUnitIterator( - NestedIterator + FlattenedIterator .start(map.getAddressSetView(Lifespan.at(program.snap)).iterator(addr, forward), rng -> getTopCodeIterator( s -> codeOperations.codeUnits().get(s, rng, forward).iterator(), @@ -394,7 +395,7 @@ public abstract class AbstractDBTraceProgramViewListing implements TraceProgramV return new WrappingCodeUnitIterator(Collections.emptyIterator()); } // TODO: The property map doesn't heed forking. - return new WrappingCodeUnitIterator(NestedIterator.start( + return new WrappingCodeUnitIterator(FlattenedIterator.start( new IntersectionAddressSetView(map.getAddressSetView(Lifespan.at(program.snap)), addrSet).iterator(forward), rng -> getTopCodeIterator( diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java index 6a8a7ae377..e91535c7ad 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -23,7 +23,7 @@ import java.util.function.Predicate; import javax.help.UnsupportedOperationException; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; import ghidra.program.model.listing.Variable; @@ -242,7 +242,7 @@ public abstract class AbstractDBTraceProgramViewReferenceManager implements Refe protected Iterator getReferenceIteratorForSnap(long snap, Address startAddr) { AddressIterator addresses = refs.getReferenceSources(Lifespan.at(snap)).getAddresses(startAddr, true); - return NestedIterator.start(addresses, a -> { + return FlattenedIterator.start(addresses, a -> { return refs.getReferencesFrom(snap, a).iterator(); }); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java index f68e5a0855..376ad28a3e 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewBookmarkManager.java @@ -23,7 +23,7 @@ import javax.swing.Icon; import org.apache.commons.collections4.IteratorUtils; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.program.model.address.*; import ghidra.program.model.listing.Bookmark; import ghidra.program.model.listing.BookmarkType; @@ -310,7 +310,7 @@ public class DBTraceProgramViewBookmarkManager implements TraceProgramViewBookma @Override public Iterator getBookmarksIterator() { // TODO: This seems terribly inefficient. We'll have to see how/when it's used. - return NestedIterator.start(bookmarkManager.getActiveSpaces().iterator(), + return FlattenedIterator.start(bookmarkManager.getActiveSpaces().iterator(), space -> filteredIterator(space.getAllBookmarks().iterator(), bm -> program.viewport.containsAnyUpper(bm.getLifespan()))); } @@ -327,7 +327,7 @@ public class DBTraceProgramViewBookmarkManager implements TraceProgramViewBookma AddressSet allMemory = factory.getAddressSet(); AddressSet within = forward ? factory.getAddressSet(startAddress, allMemory.getMaxAddress()) : factory.getAddressSet(allMemory.getMinAddress(), startAddress); - return NestedIterator.start(within.iterator(forward), rng -> { + return FlattenedIterator.start(within.iterator(forward), rng -> { DBTraceBookmarkSpace space = bookmarkManager.getBookmarkSpace(rng.getAddressSpace(), false); if (space == null) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewProgramContext.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewProgramContext.java index c8a11c415e..577713eedb 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewProgramContext.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewProgramContext.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,7 @@ import java.util.*; import java.util.Map.Entry; import java.util.function.Function; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.program.model.address.*; import ghidra.program.model.lang.*; import ghidra.program.model.listing.ContextChangeException; @@ -110,7 +110,7 @@ public class DBTraceProgramViewProgramContext extends AbstractProgramContext { setRegisterValue(start, end, new RegisterValue(register, value)); } - private static class NestedAddressRangeIterator extends NestedIterator + private static class NestedAddressRangeIterator extends FlattenedIterator implements AddressRangeIterator { protected NestedAddressRangeIterator(Iterator it, Function> f) { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java index 057b472b02..6c151204b6 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/DBTraceProgramViewSymbolTable.java @@ -18,8 +18,7 @@ package ghidra.trace.database.program; import java.util.*; import java.util.stream.StreamSupport; -import generic.NestedIterator; -import generic.util.PeekableIterator; +import generic.util.*; import ghidra.program.model.address.*; import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; @@ -342,7 +341,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { @Override public SymbolIterator getSymbols(AddressSetView set, SymbolType type, boolean forward) { - return new SymbolIteratorAdapter(NestedIterator.start(set.iterator(), range -> { + return new SymbolIteratorAdapter(FlattenedIterator.start(set.iterator(), range -> { if (range.getAddressSpace().isMemorySpace()) { if (type == SymbolType.LABEL) { return symbolManager.labels() @@ -426,7 +425,7 @@ public class DBTraceProgramViewSymbolTable implements SymbolTable { @Override public SymbolIterator getPrimarySymbolIterator(AddressSetView asv, boolean forward) { - return new PrimarySymbolIterator(NestedIterator.start(asv.iterator(forward), + return new PrimarySymbolIterator(FlattenedIterator.start(asv.iterator(forward), range -> symbolManager.labels() .getIntersecting(Lifespan.at(program.snap), range, true, forward) .iterator())); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/DBTraceDelegatingManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/DBTraceDelegatingManager.java index d7a7a5f74c..80e39795d5 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/DBTraceDelegatingManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/space/DBTraceDelegatingManager.java @@ -19,7 +19,7 @@ import java.util.*; import java.util.concurrent.locks.Lock; import java.util.function.*; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.program.model.address.*; import ghidra.util.LockHold; @@ -191,7 +191,7 @@ public interface DBTraceDelegatingManager { return new AbstractCollection<>() { @Override public Iterator iterator() { - return NestedIterator.start(spaces.iterator(), func.andThen(Iterable::iterator)); + return FlattenedIterator.start(spaces.iterator(), func.andThen(Iterable::iterator)); } @Override diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackManager.java index a17d775b2b..3efa2abdbd 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/stack/DBTraceStackManager.java @@ -19,7 +19,7 @@ import java.io.IOException; import java.util.concurrent.locks.ReadWriteLock; import db.DBHandle; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import ghidra.framework.data.OpenMode; import ghidra.program.model.address.AddressSetView; import ghidra.trace.database.DBTrace; @@ -119,7 +119,7 @@ public class DBTraceStackManager implements TraceStackManager, DBTraceManager { @Override // TODO: Should probably include a lifespan parameter? public Iterable getFramesIn(AddressSetView set) { - return () -> NestedIterator.start(set.iterator(), + return () -> FlattenedIterator.start(set.iterator(), rng -> trace.getObjectManager() .getObjectsIntersecting(Lifespan.ALL, rng, TraceStackFrame.KEY_PC, TraceStackFrame.class) diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolMultipleTypesView.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolMultipleTypesView.java index 129077e1c5..c8ab22d9b8 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolMultipleTypesView.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceSymbolMultipleTypesView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,9 +18,9 @@ package ghidra.trace.database.symbol; import java.util.*; import java.util.stream.Collectors; +import generic.util.MergeSortingIterator; import ghidra.trace.model.symbol.*; import ghidra.util.LazyCollection; -import ghidra.util.MergeSortingIterator; public class DBTraceSymbolMultipleTypesView implements TraceSymbolView { diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/OverlappingObjectIterator.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/OverlappingObjectIterator.java index 0529d29475..d2064b2df9 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/OverlappingObjectIterator.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/OverlappingObjectIterator.java @@ -20,11 +20,11 @@ import java.util.Map.Entry; import org.apache.commons.lang3.tuple.Pair; +import generic.util.AbstractPeekableIterator; import ghidra.program.model.address.Address; import ghidra.program.model.address.AddressRange; import ghidra.program.model.listing.CodeUnit; import ghidra.trace.model.TraceAddressSnapRange; -import ghidra.util.AbstractPeekableIterator; /** * An iterator of overlapping objects return from two given iterators. diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/TraceViewportSpanIterator.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/TraceViewportSpanIterator.java index 3c4fed55cc..fa5790f802 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/TraceViewportSpanIterator.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/util/TraceViewportSpanIterator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,6 +15,7 @@ */ package ghidra.trace.util; +import generic.util.AbstractPeekableIterator; import ghidra.trace.model.Lifespan; import ghidra.trace.model.Lifespan.DefaultLifeSet; import ghidra.trace.model.Lifespan.MutableLifeSet; @@ -22,7 +23,6 @@ import ghidra.trace.model.Trace; import ghidra.trace.model.time.TraceSnapshot; import ghidra.trace.model.time.TraceTimeManager; import ghidra.trace.model.time.schedule.TraceSchedule; -import ghidra.util.AbstractPeekableIterator; public class TraceViewportSpanIterator extends AbstractPeekableIterator { private final TraceTimeManager timeManager; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/program/model/address/CachedAddressSetView.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/program/model/address/CachedAddressSetView.java index 5b77d9da6d..713916d9bc 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/program/model/address/CachedAddressSetView.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/program/model/address/CachedAddressSetView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,7 +20,7 @@ import static ghidra.util.MathUtilities.cmin; import java.util.Iterator; -import ghidra.util.AbstractPeekableIterator; +import generic.util.AbstractPeekableIterator; import ghidra.util.AddressIteratorAdapter; /** diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UniqIterator.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/DistinctIterator.java similarity index 75% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UniqIterator.java rename to Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/DistinctIterator.java index dad6ded804..3ea142892e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UniqIterator.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/DistinctIterator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,23 +18,24 @@ package ghidra.util; import java.util.Iterator; import java.util.Objects; +import generic.util.AbstractPeekableIterator; import generic.util.PeekableIterator; +import generic.util.PeekableIterators; /** * A filtering iterator which removes repeated objects - * *

- * This operates in style to the uniq command on UNIX, which only removes immediate repeats. To - * obtain a truly unique iteration, the wrapped iterator must visit elements in sorted order. + * This iterator only removes immediate repeats (similar to the uniq command on UNIX). To obtain a + * truly distinct iteration, the wrapped iterator must visit elements in sorted order. * * @param the type of elements */ -public class UniqIterator extends AbstractPeekableIterator { +public class DistinctIterator extends AbstractPeekableIterator { protected boolean first; protected T last; protected final PeekableIterator wrapped; - public UniqIterator(Iterator wrapped) { + public DistinctIterator(Iterator wrapped) { this.wrapped = PeekableIterators.castOrWrap(wrapped); } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/spatial/AbstractConstraintsTree.java b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/spatial/AbstractConstraintsTree.java index 73c9d754b2..fad5b6b801 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/spatial/AbstractConstraintsTree.java +++ b/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/database/spatial/AbstractConstraintsTree.java @@ -22,7 +22,7 @@ import java.util.function.Consumer; import java.util.stream.Stream; import db.DBRecord; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import generic.util.PeekableIterator; import ghidra.util.LockHold; import ghidra.util.database.*; @@ -287,7 +287,7 @@ public abstract class AbstractConstraintsTree< // } nodes.add(n); } - return NestedIterator.start(nodes.iterator(), n -> iterator(n, query)); + return FlattenedIterator.start(nodes.iterator(), n -> iterator(n, query)); } protected Iterator orderedIterator(Q query) { diff --git a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/EmulatorUtilities.java b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/EmulatorUtilities.java new file mode 100644 index 0000000000..542435202b --- /dev/null +++ b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/emu/EmulatorUtilities.java @@ -0,0 +1,280 @@ +/* ### + * 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 ghidra.pcode.emu; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.NoSuchElementException; + +import ghidra.pcode.exec.PcodeArithmetic; +import ghidra.pcode.exec.PcodeExecutorState; +import ghidra.program.model.address.*; +import ghidra.program.model.lang.*; +import ghidra.program.model.listing.*; +import ghidra.program.model.mem.MemoryAccessException; +import ghidra.program.model.mem.MemoryBlock; +import ghidra.util.DifferenceAddressSetView; +import ghidra.util.Msg; + +/** + * Utilities for working with plain emulators (not trace- or debugger-bound) and programs in + * scripts. + */ +public enum EmulatorUtilities { + ; + /** + * The conventional name of the memory block used to specify the location of the stack. This + * should only be the case for single-threaded emulation. + */ + public static final String BLOCK_NAME_STACK = "STACK"; + + /** + * The default block size used to copy program bytes into the emulator + */ + public static final int DEFAULT_BLOCK_SIZE = 4096; + /** + * The default max size to assume for the stack + */ + public static final int DEFAULT_STACK_SIZE = 0x4000; + /** + * These utilities will avoid choosing a stack range lower than this bound, as most platforms + * will never map this page (even in kernel space) so that 0-valued pointers are never valid. + */ + public static final long PAGE_ZERO_END = 0x1000; + + /** + * Copy the bytes from the given program into the given emulator's memory. + * + *

+ * This copies each initialized block of memory from the given program into the emulator's + * shared machine state. Because the machine can have memory of any given type, it will use the + * machine's arithmetic to create values from the program's concrete data. Data is copied in + * blocks of the given size, which can be tweaked for performance. The default value, used by + * {@link #loadProgram(PcodeMachine, Program)} is {@value #DEFAULT_BLOCK_SIZE}. + * + * @param the type of values used by the emulator + * @param machine the emulator whose memory to initialize + * @param program the program whose bytes should be copied into the emulator + * @param blockSize the size of the temporary buffer used for copying + * @throws MemoryAccessException if the program's memory cannot be read + */ + public static void loadProgram(PcodeMachine machine, Program program, int blockSize) + throws MemoryAccessException { + byte[] buf = new byte[blockSize]; + PcodeExecutorState state = machine.getSharedState(); + for (MemoryBlock block : program.getMemory().getBlocks()) { + if (!block.isInitialized()) { + continue; + } + for (AddressRange rng : new AddressRangeChunker(block.getAddressRange(), + buf.length)) { + int len = block.getBytes(rng.getMinAddress(), buf); + state.setConcrete(rng.getMinAddress(), + len == buf.length ? buf : Arrays.copyOf(buf, len)); + } + } + } + + /** + * Copy the bytes from the given program into the given emulator's memory. + * + * @see #loadProgram(PcodeMachine, Program, int) + * @param machine the emulator whose memory to initialize + * @param program the program whose bytes should be copied into the emulator + * @throws MemoryAccessException if the program's memory cannot be read + */ + public static void loadProgram(PcodeMachine machine, Program program) + throws MemoryAccessException { + loadProgram(machine, program, DEFAULT_BLOCK_SIZE); + } + + /** + * Choose an assumed stack range by examining the entry point for a contextual value of the + * stack pointer. + * + * @param program the program whose context to examine + * @param entry the entry point where context should be examined + * @param stackSize the assumed max size of the stack + * @return the range assumed to be reserved for the stack, or null if no stack pointer value is + * in the context + */ + public static AddressRange chooseStackRangeFromContext(Program program, Address entry, + int stackSize) { + ProgramContext ctx = program.getProgramContext(); + CompilerSpec cSpec = program.getCompilerSpec(); + Register sp = cSpec.getStackPointer(); + RegisterValue spVal = ctx.getRegisterValue(sp, entry); + if (spVal == null || !spVal.hasValue()) { + return null; + } + + Address spAddr = cSpec.getStackBaseSpace().getAddress(spVal.getUnsignedValue().longValue()); + if (cSpec.stackGrowsNegative()) { + Address max = spAddr.subtractWrap(1); + Address min = spAddr.subtractWrap(stackSize); + if (min.compareTo(max) > 0) { + return new AddressRangeImpl(max.getAddressSpace().getMinAddress(), max); + } + return new AddressRangeImpl(min, max); + } + // Grows positive + Address min = spAddr; + Address max = spAddr.addWrap(stackSize - 1); + if (min.compareTo(max) > 0) { + return new AddressRangeImpl(min, min.getAddressSpace().getMaxAddress()); + } + return new AddressRangeImpl(min, max); + } + + /** + * Choose an assumed stack range by examining the program's memory map for a + * {@value #BLOCK_NAME_STACK} block. + * + * @param program the program to examine + * @return the range assumed to be reserved for the stack, or null if no + * {@value #BLOCK_NAME_STACK} block is found. + */ + public static AddressRange chooseStackRangeFromBlock(Program program) { + AddressSpace space = program.getCompilerSpec().getStackBaseSpace(); + MemoryBlock stackBlock = program.getMemory().getBlock(BLOCK_NAME_STACK); + if (stackBlock == null) { + return null; + } + if (space != stackBlock.getStart().getAddressSpace().getPhysicalSpace()) { + Msg.showError(EmulatorUtilities.class, null, "Invalid STACK block", + "The STACK block must be in the stack's base space. Ignoring."); + return null; + } + return new AddressRangeImpl( + stackBlock.getStart().getPhysicalAddress(), + stackBlock.getEnd().getPhysicalAddress()); + } + + /** + * Choose an assumed stack range + * + *

+ * This will first examine the entry point's context for a stack pointer value using + * {@link #chooseStackRangeFromContext(Program, Address, int)}. Then, it will examine the + * progam's memory map using {@link #chooseStackRangeFromBlock(Program)}. Finally, it will + * search for a slack address range of the requested size. That is, it seeks a range that does + * not intersect any existing memory block. If possible, this will avoid choosing a stack range + * that intersects [0, 4096), so that 0-valued pointers are in fact invalid. + * + *

+ * Note that a stack is not formally "allocated." Instead, the range is used to initialize a + * thread's stack pointer. Unless instrumentation is added to detect a stack overflow, nothing + * really prevents the program from exceeding the returned range. Thus, {@code stackSize} should + * be large enough to accommodate the target. Additionally, the user or client code should be + * prepared for undefined behavior caused by an unmitigated stack overflow. + * + * @param program the program + * @param entry the entry point, in case context there defines an initial stack pointer + * @param stackSize the maximum expected size of the stack + * @return the chosen range assumed to be used for the stack + */ + public static AddressRange chooseStackRange(Program program, Address entry, int stackSize) { + AddressRange customByContext = chooseStackRangeFromContext(program, entry, stackSize); + if (customByContext != null) { + return customByContext; + } + AddressRange customByBlock = chooseStackRangeFromBlock(program); + if (customByBlock != null) { + return customByBlock; + } + // Search for a range of the given size outside any block + AddressSpace space = program.getCompilerSpec().getStackBaseSpace(); + Address max = space.getMaxAddress(); + AddressSet eligible; + if (max.getOffsetAsBigInteger().compareTo(BigInteger.valueOf(0x1000)) < 0) { + eligible = new AddressSet(space.getMinAddress(), max); + } + else { + eligible = new AddressSet(space.getAddress(0x1000), max); + } + + AddressSetView left = new DifferenceAddressSetView(eligible, program.getMemory()); + for (AddressRange candidate : left) { + if (Long.compareUnsigned(candidate.getLength(), stackSize) >= 0) { + try { + return new AddressRangeImpl(candidate.getMinAddress(), stackSize); + } + catch (AddressOverflowException e) { + throw new AssertionError(e); + } + } + } + throw new NoSuchElementException(); + } + + /** + * Choose an assumed stack range of size {@value #DEFAULT_STACK_SIZE} + * + * @see #chooseStackRange(Program, Address, int) + * @param program the program + * @param entry the entry point, in case context there defines an initial stack pointer + * @return the chosen range assumed to be used for the stack + */ + public static AddressRange chooseStackRange(Program program, Address entry) { + return chooseStackRange(program, entry, DEFAULT_STACK_SIZE); + } + + /** + * Prepare a thread to emulate a given function + * + * @param the type of values in the emulator + * @param thread the thread whose state to initialize + * @param function the function to prepare to enter + * @param stackSize the maximum expected size of the stack + */ + public static void initializeForFunction(PcodeThread thread, Function function, + int stackSize) { + PcodeArithmetic arithmetic = thread.getArithmetic(); + + Program program = function.getProgram(); + Address entry = function.getEntryPoint(); + CompilerSpec cSpec = program.getCompilerSpec(); + Register sp = cSpec.getStackPointer(); + ThreadPcodeExecutorState state = thread.getState(); + + ProgramProcessorContext ctx = + new ProgramProcessorContext(program.getProgramContext(), entry); + for (Register reg : ctx.getRegisters()) { + if (!reg.isBaseRegister()) { + continue; + } + RegisterValue rv = ctx.getRegisterValue(reg); + if (rv == null || !rv.hasAnyValue()) { + continue; + } + /** + * NOTE: In theory, there's no need to combine masked values, if this is a fresh + * emulator. If I had to guess, the client would want their values to take precedence, + * so they should overwrite the values after calling this method. Combining can be + * problematic, because the emulator could return some abstraction for the current + * value. + */ + state.setRegisterValue(rv); + } + + AddressRange stack = chooseStackRange(program, entry); + long stackOffset = cSpec.stackGrowsNegative() ? stack.getMaxAddress().getOffset() + 1 + : stack.getMinAddress().getOffset(); + state.setVar(sp, arithmetic.fromConst(stackOffset, sp.getMinimumByteSize())); + + thread.overrideCounter(entry); + } +} diff --git a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/PcodeExecutorStatePiece.java b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/PcodeExecutorStatePiece.java index 198afe82ee..ccc8095514 100644 --- a/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/PcodeExecutorStatePiece.java +++ b/Ghidra/Framework/Emulation/src/main/java/ghidra/pcode/exec/PcodeExecutorStatePiece.java @@ -15,14 +15,14 @@ */ package ghidra.pcode.exec; +import java.math.BigInteger; import java.util.Map; import java.util.Map.Entry; import java.util.stream.Stream; import ghidra.pcode.exec.PcodeArithmetic.Purpose; import ghidra.program.model.address.*; -import ghidra.program.model.lang.Language; -import ghidra.program.model.lang.Register; +import ghidra.program.model.lang.*; import ghidra.program.model.mem.MemBuffer; import ghidra.program.model.pcode.Varnode; @@ -374,4 +374,175 @@ public interface PcodeExecutorStatePiece { * dark. */ void clear(); + + /** + * Convenience to set a variable to a concrete value + * + * @param address the address in memory + * @param value the value + */ + default void setConcrete(Address address, byte[] value) { + setVar(address, value.length, false, getArithmetic().fromConst(value)); + } + + /** + * Convenience to inspect the concrete value of a variable + * + * @param address the address in memory + * @param size the number of bytes to inspect + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default byte[] inspectConcrete(Address address, int size) { + return getArithmetic().toConcrete(getVar(address, size, false, Reason.INSPECT), + Purpose.INSPECT); + } + + /** + * Convenience to set a variable to a concrete value as a {@link BigInteger} + * + * @param address the address is memory + * @param size the size of the variable (in bytes) + * @param value the value + */ + default void setBigInteger(Address address, int size, BigInteger value) { + setVar(address, size, false, getArithmetic().fromConst(value, size)); + } + + /** + * Convenience to inspect the concrete value of a variable as a {@link BigInteger} + * + * @param address the address in memory + * @param size the number of bytes to inspect + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default BigInteger inspectBigInteger(Address address, int size) { + return getArithmetic().toBigInteger(getVar(address, size, false, Reason.INSPECT), + Purpose.INSPECT); + } + + /** + * Convenience to set a variable to a concrete value as a {@code long} + * + * @param address the address is memory + * @param value the value + */ + default void setLong(Address address, long value) { + setVar(address, Long.BYTES, false, getArithmetic().fromConst(value, Long.BYTES)); + } + + /** + * Convenience to inspect the concrete value of a variable as a {@code long} + * + * @param address the address in memory + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default long inspectLong(Address address) { + return getArithmetic().toLong(getVar(address, Long.BYTES, false, Reason.INSPECT), + Purpose.INSPECT); + } + + /** + * Convenience to set a variable to a concrete value as an {@code int} + * + * @param address the address is memory + * @param value the value + */ + default void setInt(Address address, int value) { + setVar(address, Integer.BYTES, false, getArithmetic().fromConst(value, Integer.BYTES)); + } + + /** + * Convenience to inspect the concrete value of a variable as an {@code int} + * + * @param address the address in memory + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default int inspectInt(Address address) { + return (int) getArithmetic().toLong(getVar(address, Integer.BYTES, false, Reason.INSPECT), + Purpose.INSPECT); + } + + /** + * Convenience to set a variable to a concrete value as a {@code short} + * + * @param address the address is memory + * @param value the value + */ + default void setShort(Address address, short value) { + setVar(address, Short.BYTES, false, getArithmetic().fromConst(value, Short.BYTES)); + } + + /** + * Convenience to inspect the concrete value of a variable as a {@code short} + * + * @param address the address in memory + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default short inspectShort(Address address) { + return (short) getArithmetic().toLong(getVar(address, Short.BYTES, false, Reason.INSPECT), + Purpose.INSPECT); + } + + /** + * Convenience to set a variable to a concrete value as a {@code byte} + * + * @param address the address is memory + * @param value the value + */ + default void setByte(Address address, byte value) { + setVar(address, Byte.BYTES, false, getArithmetic().fromConst(value, Byte.BYTES)); + } + + /** + * Convenience to inspect the concrete value of a variable as a {@code byte} + * + * @param address the address in memory + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default byte inspectByte(Address address) { + return (byte) getArithmetic().toLong(getVar(address, Byte.BYTES, false, Reason.INSPECT), + Purpose.INSPECT); + } + + /** + * Convenience to set a register variable to a concrete value as a {@link RegisterValue} + * + *

+ * NOTE: The register from the given value does not have to match the given register, but + * their sizes should at least match. This permits simpler moving of values from one + * register to another. If the sizes do not match, the behavior is undefined. + * + * @param register the register + * @param value the value + */ + default void setRegisterValue(Register register, RegisterValue value) { + setVar(register, getArithmetic().fromConst(value)); + } + + /** + * Convenience to set a register variable to a concrete value as a {@link RegisterValue} + * + * @param value the value + */ + default void setRegisterValue(RegisterValue value) { + setRegisterValue(value.getRegister(), value); + } + + /** + * Convenience to inspect the concrete value of a register variable as a {@link RegisterValue} + * + * @param register the register + * @return the value + * @throws ConcretionError if the value cannot be made concrete + */ + default RegisterValue inspectRegisterValue(Register register) { + return getArithmetic().toRegisterValue(register, getVar(register, Reason.INSPECT), + Purpose.INSPECT); + } } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AbstractPeekableIterator.java b/Ghidra/Framework/Generic/src/main/java/generic/util/AbstractPeekableIterator.java similarity index 68% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AbstractPeekableIterator.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/AbstractPeekableIterator.java index 370b39d9ac..6bc54bc4e4 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AbstractPeekableIterator.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/AbstractPeekableIterator.java @@ -4,25 +4,37 @@ * 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 ghidra.util; +package generic.util; import java.util.NoSuchElementException; -import generic.util.PeekableIterator; - +/** + * An implementation of {@link PeekableIterator} that only requires a way to seek out the next + * element. This will keep that element in hand until the next element is actually requested by the + * client. This does not invoke the search until the next element is required, either because the + * client called next or else wants to peek at it. + * + * @param the type of elements + */ public abstract class AbstractPeekableIterator implements PeekableIterator { protected T next = null; protected boolean soughtNext = false; + /** + * Find the next element in this iterator, because the client called either {@link #next} or + * {@link #peek()}. + * + * @return the next element + */ protected abstract T seekNext(); private void checkSeekNext() { @@ -52,5 +64,4 @@ public abstract class AbstractPeekableIterator implements PeekableIterator } return next; } - } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/generic/NestedIterator.java b/Ghidra/Framework/Generic/src/main/java/generic/util/FlattenedIterator.java similarity index 60% rename from Ghidra/Debug/ProposedUtils/src/main/java/generic/NestedIterator.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/FlattenedIterator.java index 77eebb497c..0752a9254f 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/generic/NestedIterator.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/FlattenedIterator.java @@ -4,34 +4,45 @@ * 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 generic; +package generic.util; import java.util.Iterator; import java.util.function.Function; /** - * TODO Document me + * Given an "outer" iterator and a mapping from its elements to "inner" iterators, this is a + * flattened iterator over elements from the inner iterators. * - * Note the innerFactory may return null to skip an outer element. - * - * TODO: Test innerFactory returning null. - * - * @param - * @param + * @param the type of elements in the outer iterator + * @param the type of elements in the inner and flattened iterators */ -public class NestedIterator implements Iterator { +public class FlattenedIterator implements Iterator { + /** + * Create a flattened iterator + *

+ * This iterates over each element of {@code outer} and applies the given {@code innerFactory} + * to generate an "inner" iterator. The returned iterator will produce elements from the inner + * iterators as if concatentated. This is essentially a flat-map operation on iterators. Note + * the {@code innerFactory} may return null to skip an outer element. + * + * @param the type of elements in the outer iterator + * @param the type of elements in the inner and flattened iterators + * @param outer the outer iterator + * @param innerFactory a mapping from outer elements to inner iterators + * @return the flattened iterator + */ public static Iterator start(Iterator outer, Function> innerFactory) { - return new NestedIterator<>(outer, innerFactory); + return new FlattenedIterator<>(outer, innerFactory); } protected final Iterator outer; @@ -40,7 +51,8 @@ public class NestedIterator implements Iterator { protected Iterator inner; protected Iterator preppedInner; - protected NestedIterator(Iterator outer, Function> innerFactory) { + protected FlattenedIterator(Iterator outer, + Function> innerFactory) { this.outer = outer; this.innerFactory = innerFactory; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/MergeSortingIterator.java b/Ghidra/Framework/Generic/src/main/java/generic/util/MergeSortingIterator.java similarity index 86% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/MergeSortingIterator.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/MergeSortingIterator.java index 28c74c40df..5cb0e5cfb4 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/MergeSortingIterator.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/MergeSortingIterator.java @@ -4,21 +4,24 @@ * 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 ghidra.util; +package generic.util; -import java.util.*; +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.Map; import java.util.Map.Entry; - -import generic.util.PeekableIterator; +import java.util.NoSuchElementException; +import java.util.PriorityQueue; /** * An iterator which merges sorted iterators according to a comparator @@ -87,13 +90,16 @@ public class MergeSortingIterator implements PeekableIterator { /** * Construct a merge-sorting iterator which generates labeled values - * *

* The map of iterators is a map of entries, each giving a label and an iterator to be merged. * Each iterator must return values as sorted by the given comparator. The entries returned by * the combined iterator give the values in sorted order, but each has a the key indicating * which given iterator returned that value. Note that the returned entry may be re-used by the * underlying implementation, so users needing to keep the entry should create a copy. + *

+ * The purpose of the iterator is to know which iterator provided a given entry in the merged + * result. While this has general utility, at the moment, it is only used in our tests to verify + * proper operation of the merge-sorting implementation. * * @param iterMap a map of labeled iterators * @param comparator the comparator of values @@ -110,6 +116,12 @@ public class MergeSortingIterator implements PeekableIterator { protected final Comparator comparator; protected final PriorityQueue> queue; + /** + * Construct a merge sorting iterator + * + * @param iterators a collection of iterators to merge + * @param comparator the comparator defining how the input and output iterators are sorted + */ public MergeSortingIterator(Iterable> iterators, Comparator comparator) { this.comparator = comparator; diff --git a/Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterator.java b/Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterator.java index 431c6fac2b..ef4610b19e 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterator.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -26,10 +26,11 @@ import java.util.NoSuchElementException; public interface PeekableIterator extends Iterator { /** - * Returns the item that would be returned by calling {@link #next()}, but does not - * increment the iterator as next would. + * Returns the item that would be returned by calling {@link #next()}, but without incrementing + * the iterator. * * @return the item that would be returned by calling {@link #next()} + * @throws NoSuchElementException if there is no element to peek at */ public T peek() throws NoSuchElementException; } diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/PeekableIterators.java b/Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterators.java similarity index 55% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/PeekableIterators.java rename to Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterators.java index d7660fc54e..125161ca75 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/PeekableIterators.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/PeekableIterators.java @@ -4,28 +4,38 @@ * 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 ghidra.util; +package generic.util; import java.util.Iterator; -import generic.util.PeekableIterator; -import generic.util.WrappingPeekableIterator; - +/** + * Utilities for working with a {@link PeekableIterator} + */ public enum PeekableIterators { ; - public static PeekableIterator castOrWrap(Iterator it) { - if (it instanceof PeekableIterator) { - return (PeekableIterator) it; + /** + * Ensure that the given iterator is peekable + * + *

+ * If it is already peekable, this casts it as such. If not, it wraps it in a peekable iterator. + * + * @param the type of elements + * @param it the iterator + * @return the peekable iterator + */ + public static PeekableIterator castOrWrap(Iterator it) { + if (it instanceof PeekableIterator pi) { + return pi; } - return new WrappingPeekableIterator(it); + return new WrappingPeekableIterator(it); } } diff --git a/Ghidra/Framework/Generic/src/main/java/generic/util/WrappingPeekableIterator.java b/Ghidra/Framework/Generic/src/main/java/generic/util/WrappingPeekableIterator.java index ff8e037b78..bfa74ece86 100644 --- a/Ghidra/Framework/Generic/src/main/java/generic/util/WrappingPeekableIterator.java +++ b/Ghidra/Framework/Generic/src/main/java/generic/util/WrappingPeekableIterator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -16,59 +16,37 @@ package generic.util; import java.util.Iterator; -import java.util.NoSuchElementException; /** - * An implementation of {@link PeekableIterator} that can take a Java {@link Iterator} and - * wrap it to implement the {@link PeekableIterator} interface. + * An implementation of {@link PeekableIterator} that can take a Java {@link Iterator} and wrap it + * to implement the {@link PeekableIterator} interface. * * @param the type of the iterator */ -public class WrappingPeekableIterator implements PeekableIterator { +public class WrappingPeekableIterator extends AbstractPeekableIterator { - private Iterator iterator; - private T peek; - private boolean peeked; + private final Iterator iterator; + /** + * Wrap the given iterator + * + * @see PeekableIterators#castOrWrap(Iterator) + * @param iterator the iterator + */ public WrappingPeekableIterator(Iterator iterator) { this.iterator = iterator; } - @Override - public boolean hasNext() { - if (peeked) { - return true; - } - return iterator.hasNext(); - } - - @Override - public T next() { - if (peeked) { - peeked = false; - return peek; - } - return iterator.next(); - } - @Override public void remove() { throw new UnsupportedOperationException(); } @Override - public T peek() throws NoSuchElementException { - if (peeked) { - return peek; + protected T seekNext() { + if (!iterator.hasNext()) { + return null; } - - if (!hasNext()) { - throw new NoSuchElementException(); - } - - peek = next(); - peeked = true; - return peek; + return iterator.next(); } - } diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/generic/NestedIteratorTest.java b/Ghidra/Framework/Generic/src/test/java/generic/util/FlattenedIteratorTest.java similarity index 72% rename from Ghidra/Debug/ProposedUtils/src/test/java/generic/NestedIteratorTest.java rename to Ghidra/Framework/Generic/src/test/java/generic/util/FlattenedIteratorTest.java index c94103b47b..1241bc14ed 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/generic/NestedIteratorTest.java +++ b/Ghidra/Framework/Generic/src/test/java/generic/util/FlattenedIteratorTest.java @@ -4,29 +4,35 @@ * 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 generic; +package generic.util; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; import org.apache.commons.collections4.IteratorUtils; import org.junit.Test; -public class NestedIteratorTest { +public class FlattenedIteratorTest { @Test public void testEmptyOuter() { List result = - IteratorUtils.toList(NestedIterator.start(Collections.emptyIterator(), o -> { + IteratorUtils.toList(FlattenedIterator.start(Collections.emptyIterator(), o -> { fail(); return null; })); @@ -36,27 +42,27 @@ public class NestedIteratorTest { @Test public void testSingleOuterEmptyInner() { List result = IteratorUtils.toList( - NestedIterator.start(List.of("Test").iterator(), s -> Collections.emptyIterator())); + FlattenedIterator.start(List.of("Test").iterator(), s -> Collections.emptyIterator())); assertTrue(result.isEmpty()); } @Test public void testDoubleOuterEmptyInner() { List result = IteratorUtils.toList( - NestedIterator.start(List.of("T1", "T2").iterator(), s -> Collections.emptyIterator())); + FlattenedIterator.start(List.of("T1", "T2").iterator(), s -> Collections.emptyIterator())); assertTrue(result.isEmpty()); } @Test public void testSingleOuterSingleInner() { List result = IteratorUtils - .toList(NestedIterator.start(List.of(0).iterator(), n -> List.of("Test").iterator())); + .toList(FlattenedIterator.start(List.of(0).iterator(), n -> List.of("Test").iterator())); assertEquals(List.of("Test"), result); } @Test public void testFirstEmptySecondSingleton() { - List result = IteratorUtils.toList(NestedIterator.start(List.of(0, 1).iterator(), + List result = IteratorUtils.toList(FlattenedIterator.start(List.of(0, 1).iterator(), n -> n == 0 ? Collections.emptyIterator() : List.of("Test").iterator())); assertEquals(List.of("Test"), result); } @@ -64,20 +70,20 @@ public class NestedIteratorTest { @Test public void testSingleOuterDoubleInner() { List result = IteratorUtils.toList( - NestedIterator.start(List.of(0).iterator(), n -> List.of("T1", "T2").iterator())); + FlattenedIterator.start(List.of(0).iterator(), n -> List.of("T1", "T2").iterator())); assertEquals(List.of("T1", "T2"), result); } @Test public void testDoubleOuterDoubleInner() { - List result = IteratorUtils.toList(NestedIterator.start(List.of(0, 1).iterator(), + List result = IteratorUtils.toList(FlattenedIterator.start(List.of(0, 1).iterator(), n -> (n == 0 ? List.of("T1", "T2") : List.of("T3", "T4")).iterator())); assertEquals(List.of("T1", "T2", "T3", "T4"), result); } @Test public void testMultipleHasNextCalls() { - Iterator it = NestedIterator.start(List.of(0, 1).iterator(), + Iterator it = FlattenedIterator.start(List.of(0, 1).iterator(), n -> (n == 0 ? List.of("T1", "T2") : List.of("T3", "T4")).iterator()); assertTrue(it.hasNext()); assertTrue(it.hasNext()); @@ -100,7 +106,7 @@ public class NestedIteratorTest { @Test public void testNoHasNextCalls() { - Iterator it = NestedIterator.start(List.of(0, 1).iterator(), + Iterator it = FlattenedIterator.start(List.of(0, 1).iterator(), n -> (n == 0 ? List.of("T1", "T2") : List.of("T3", "T4")).iterator()); assertEquals("T1", it.next()); assertEquals("T2", it.next()); @@ -116,7 +122,7 @@ public class NestedIteratorTest { List b = new ArrayList<>(List.of("T3", "T4")); List> listList = new ArrayList<>(List.of(a, b)); - Iterator it = NestedIterator.start(listList.iterator(), l -> l.iterator()); + Iterator it = FlattenedIterator.start(listList.iterator(), l -> l.iterator()); assertEquals("T1", it.next()); assertEquals("T2", it.next()); assertTrue(it.hasNext()); // Odd to do this right before a remove, but.... diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AbstractAddressSetView.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AbstractAddressSetView.java similarity index 88% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AbstractAddressSetView.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AbstractAddressSetView.java index 03c53d414a..0f6ae2512a 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AbstractAddressSetView.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AbstractAddressSetView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -20,8 +20,23 @@ import java.util.List; import ghidra.program.model.address.*; +/** + * An abstract implementation of {@link AddressSetView} that provides suitable defaults for as many + * of the required methods as reasonable. + */ public abstract class AbstractAddressSetView implements AddressSetView { + /** + * Adjust the given start address so that if it lands in the given iterator's next range, that + * range would be entirely included. + * + * @param rev the iterator. Note only the first element, if present, of this iterator is + * considered. The client must ensure it's properly positioned. + * @param start the proposed start address + * @param forward true for forward iteration, i.e., the adjustment will be to the range's + * minimum address, if applicable. + * @return the adjusted start + */ protected static Address fixStart(AddressRangeIterator rev, Address start, boolean forward) { if (!rev.hasNext()) { return start; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressIteratorAdapter.java similarity index 71% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressIteratorAdapter.java index 43954807f9..e458a8953e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressIteratorAdapter.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressIteratorAdapter.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,11 +18,14 @@ package ghidra.util; import java.util.Iterator; import java.util.NoSuchElementException; -import generic.NestedIterator; +import generic.util.FlattenedIterator; import generic.util.PeekableIterator; import ghidra.program.model.address.*; -public class AddressIteratorAdapter extends NestedIterator +/** + * Convert an {@link AddressRange} iterator to an {@link AddressIterator}. + */ +public class AddressIteratorAdapter extends FlattenedIterator implements AddressIterator { protected static class ForwardAddressIterator implements PeekableIterator
{ @@ -89,15 +92,39 @@ public class AddressIteratorAdapter extends NestedIterator forRange(AddressRange range, boolean forward) { return () -> forward ? new ForwardAddressIterator(range) : new BackwardAddressIterator(range); } + /** + * Construct an {@link AddressIterator} over the given address ranges + * + * @param outer an iterator of address ranges + * @param forward true for forward iteration. Otherwise backward iteration. This flag must be + * consistent with the order of the given outer iterator. + */ public AddressIteratorAdapter(Iterator outer, boolean forward) { super(outer, forward ? ForwardAddressIterator::new : BackwardAddressIterator::new); } + /** + * Construct an {@link AddressIterator} over the given address ranges, truncating the initial + * range to the given start + * + * @param outer the iterator of address ranges, the first of which must contain or come after + * the given start. + * @param start the starting address + * @param forward true for forward iteration. Otherwise backward iteration. This flag must be + * consistent with the order of the given outer iterator.o + */ public AddressIteratorAdapter(Iterator outer, Address start, boolean forward) { super(outer, forward ? ar -> { if (!ar.contains(start)) { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressRangeComparators.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressRangeComparators.java similarity index 61% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressRangeComparators.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressRangeComparators.java index b5fc316d0b..fa99394ac7 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressRangeComparators.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressRangeComparators.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,14 +18,29 @@ package ghidra.util; import java.util.Comparator; import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressSet; +/** + * Comparators used for sorting address ranges + */ public enum AddressRangeComparators implements Comparator { + /** + * Compare ranges by their minimum address and order them smallest first. + */ FORWARD { @Override public int compare(AddressRange a, AddressRange b) { return a.getMinAddress().compareTo(b.getMinAddress()); } }, + /** + * Compare ranges by their maximum address and order them largest first. + * + * @implNote Which address is compared might not ordinarily matter, since {@link AddressSet} + * requires a disjoint union of ranges. However, these comparators often compare + * ranges from different sets, e.g., in order to merge two or more iterators. Thus, in + * reverse, we want to ensure ranges are ordered by their maximum address. + */ BACKWARD { @Override public int compare(AddressRange a, AddressRange b) { diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressRangeIterators.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressRangeIterators.java similarity index 60% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressRangeIterators.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressRangeIterators.java index 84aa7ebe03..3acf5a617c 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/AddressRangeIterators.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/AddressRangeIterators.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,6 +24,10 @@ import org.apache.commons.collections4.IteratorUtils; import ghidra.program.model.address.*; import ghidra.util.TwoWayBreakdownAddressRangeIterator.Which; +/** + * Utilities for manipulating iterators over {@link AddressRange}s. Notably, this allows the + * creation of lazily computed set operations on {@link AddressSetView}s. + */ public enum AddressRangeIterators { ; @@ -50,13 +54,30 @@ public enum AddressRangeIterators { } } + /** + * Utility for satisfying the type checker. This just forwards the method calls so that an + * {@link Iterator} over {@link AddressRange} can be used where an {@link AddressRangeIterator} + * is required. If only Java had type aliasing.... + * + * @param it the iterator + * @return the wrapper, or the same iterator if it is already an {@link AddressRangeIterator} + */ public static AddressRangeIterator castOrWrap(Iterator it) { - if (it instanceof AddressRangeIterator) { - return (AddressRangeIterator) it; + if (it instanceof AddressRangeIterator ari) { + return ari; } return new WrappingAddressRangeIterator(it); } + /** + * Create an iterator over the union of address ranges in the given iterators + * + * @see UnionAddressSetView + * @param iterators the iterators to union + * @param forward true for forward iteration. The given iterators must all return ranges in the + * order indicated by this flag. + * @return the iterator over the union + */ public static AddressRangeIterator union(Collection> iterators, boolean forward) { return new UnionAddressRangeIterator(iterators, forward); @@ -70,6 +91,17 @@ public enum AddressRangeIterators { : range.getMinAddress().compareTo(start) <= 0; } + /** + * Create an iterator over the difference between two address range iterators + * + * @see DifferenceAddressSetView + * @param a the minuend + * @param b the subtrahend + * @param start the starting address, or null + * @param forward true for forward iteration. The given iterators must all return ranges in the + * order indicated by this flag. + * @return the iterator over the difference + */ public static AddressRangeIterator subtract(Iterator a, Iterator b, Address start, boolean forward) { return new WrappingAddressRangeIterator(IteratorUtils.transformedIterator( @@ -78,6 +110,17 @@ public enum AddressRangeIterators { e -> e.getKey())); } + /** + * Create an iterator over the symmetric difference between two address range iterators + * + * @see SymmetricDifferenceAddressSetView + * @param a the first iterator + * @param b the second iterator + * @param start the starting address, or null + * @param forward true for forward iteration. The given iterators must all return ranges in the + * order indicated by this flag. + * @return the iterator over the symmetric difference + */ public static AddressRangeIterator xor(Iterator a, Iterator b, Address start, boolean forward) { Iterator> eit = @@ -93,6 +136,16 @@ public enum AddressRangeIterators { return new WrappingAddressRangeIterator(result); } + /** + * Create an iterator over the intersection between two address range iterators + * + * @see IntersectionAddressSetView + * @param a the first iterator + * @param b the second iterator + * @param forward true for forward iteration. The given iterators must all return ranges in the + * order indicated by this flag. + * @return the iterator over the symmetric difference + */ public static AddressRangeIterator intersect(Iterator a, Iterator b, boolean forward) { return new WrappingAddressRangeIterator(IteratorUtils.transformedIterator( diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/DifferenceAddressSetView.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/DifferenceAddressSetView.java similarity index 73% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/DifferenceAddressSetView.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/DifferenceAddressSetView.java index ef5993766c..115bdea93e 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/DifferenceAddressSetView.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/DifferenceAddressSetView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -17,12 +17,33 @@ package ghidra.util; import java.util.Iterator; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeImpl; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSetView; +/** + * A lazily computed {@link AddressSetView} defined as the difference between two given + * {@link AddressSetView}s. + *

+ * This is equivalent to using {@link AddressSetView#subtract(AddressSetView)}, but does not + * materialize the difference. The choice of one over the other depends on the number of ranges in + * the inputs and the frequency of use of the result. With few ranges, or in cases where you need to + * access the entire result, anyway, just use the normal {@link AddressRange}. In cases with many, + * many ranges and where only a small part of the result needs to be computed, use this view. It may + * also be advantageous to use this view if the inputs are themselves computed lazily. + */ public class DifferenceAddressSetView extends AbstractAddressSetView { private final AddressSetView a; private final AddressSetView b; + /** + * Construct the difference between two address sets + * + * @param a the minuend + * @param b the subtrahend + */ public DifferenceAddressSetView(AddressSetView a, AddressSetView b) { this.a = a; this.b = b; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/IntersectionAddressSetView.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/IntersectionAddressSetView.java similarity index 75% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/IntersectionAddressSetView.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/IntersectionAddressSetView.java index 696d2a51b2..a0f11ebc46 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/IntersectionAddressSetView.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/IntersectionAddressSetView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,12 +18,33 @@ package ghidra.util; import static ghidra.util.MathUtilities.cmax; import static ghidra.util.MathUtilities.cmin; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSetView; +import ghidra.program.model.address.EmptyAddressRangeIterator; +/** + * A lazily computed {@link AddressSetView} defined as the intersection of two given + * {@link AddressSetView}s. + *

+ * This is equivalent to using {@link AddressSetView#intersect(AddressSetView)}, but does not + * materialize the intersection. The choice of one over the other depends on the number of ranges in + * the inputs and the frequency of use of the result. With few ranges, or in cases where you need to + * access the entire result, anyway, just use the normal {@link AddressRange}. In cases with many, + * many ranges and where only a small part of the result needs to be computed, use this view. It may + * also be advantageous to use this view if the inputs are themselves computed lazily. + */ public class IntersectionAddressSetView extends AbstractAddressSetView { private final AddressSetView a; private final AddressSetView b; + /** + * Construct the intersection of two address sets + * + * @param a the first set + * @param b the second set + */ public IntersectionAddressSetView(AddressSetView a, AddressSetView b) { this.a = a; this.b = b; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/SymmetricDifferenceAddressSetView.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/SymmetricDifferenceAddressSetView.java similarity index 72% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/SymmetricDifferenceAddressSetView.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/SymmetricDifferenceAddressSetView.java index d02c48649c..62a4a155ef 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/SymmetricDifferenceAddressSetView.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/SymmetricDifferenceAddressSetView.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -15,12 +15,34 @@ */ package ghidra.util; -import ghidra.program.model.address.*; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeIterator; +import ghidra.program.model.address.AddressSetView; +/** + * A lazily computed {@link AddressSetView} defined as the symmetric difference between two given + * {@link AddressSetView}s. + *

+ * There is no equivalent method in {@link AddressSetView}, but it could be computed using a + * combination of {@link AddressSetView#subtract(AddressSetView)} and + * {@link AddressSetView#union(AddressSetView)}. However, this class does not materialize the + * result. The choice of one over the other depends on the number of ranges in the inputs and the + * frequency of use of the result. With few ranges, or in cases where you need to access the entire + * result, anyway, just use the normal {@link AddressRange}. In cases with many, many ranges and + * where only a small part of the result needs to be computed, use this view. It may also be + * advantageous to use this if the inputs are themselves computed lazily. + */ public class SymmetricDifferenceAddressSetView extends AbstractAddressSetView { private final AddressSetView a; private final AddressSetView b; + /** + * Construct the symmetric difference between two address sets + * + * @param a the first set + * @param b the second set + */ public SymmetricDifferenceAddressSetView(AddressSetView a, AddressSetView b) { this.a = a; this.b = b; diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/TwoWayBreakdownAddressRangeIterator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/TwoWayBreakdownAddressRangeIterator.java similarity index 74% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/TwoWayBreakdownAddressRangeIterator.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/TwoWayBreakdownAddressRangeIterator.java index b6c740dca1..8ff7e65de2 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/TwoWayBreakdownAddressRangeIterator.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/TwoWayBreakdownAddressRangeIterator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,37 +21,91 @@ import static ghidra.util.MathUtilities.cmin; import java.util.Iterator; import java.util.Map.Entry; -import generic.util.PeekableIterator; +import generic.util.*; import ghidra.program.model.address.*; import ghidra.util.TwoWayBreakdownAddressRangeIterator.Which; +/** + * An iterator that takes two iterators over address ranges and "breaks down" where they do and do + * not overlap. Consider one iterator L that contains only [1,3], and another R that contains only + * [2,4]. The two could be plotted: + * + *

+ *  1  2  3  4
+ * [---L---]
+ *    [---R---]
+ * 
+ * + *

+ * This will return an iterator over range-which pairs. "Which" indicates which iterators include + * the given range, {@link Which#LEFT}, {@link Which#RIGHT}, or {@link Which#BOTH}. There is no + * {@code NONE}, so gaps are omitted. For the example above: + * + *

+ *  1  2  3  4
+ * [L][-B--][R]
+ * 
+ * + *

+ * This supports the computation of difference, symmetric difference, and intersection. NOTE: + * Clients cannot save the entries returned by the iterator. The entry is only valid during + * iteration, and it is reused by the iterator for each subsequent entry. + */ public class TwoWayBreakdownAddressRangeIterator extends AbstractPeekableIterator> { + /** + * Indicates which of the input iterators contain a range + */ public enum Which { - LEFT(true, false), RIGHT(false, true), BOTH(true, true); + /** Only the left included the range */ + LEFT(true, false), + /** Only the right included the range */ + RIGHT(false, true), + /** Both included the range */ + BOTH(true, true); private Which(boolean includesLeft, boolean includesRight) { this.includesLeft = includesLeft; this.includesRight = includesRight; } + /** Indicates the the left iterator includes this range */ public final boolean includesLeft; + /** Indicates that the right iterator includes this range */ public final boolean includesRight; + /** + * Check if this range is included in the difference: {@code left - right} + * + * @return true if included + */ public boolean inSubtract() { return this == LEFT; } + /** + * Check if this range is included in the symmetric difference: {@code left Δ right} + * + * @return true if included + */ public boolean inXor() { return this == LEFT || this == RIGHT; } + /** + * Check if this range is included in the intersection: {@code left ∩ right} + * + * @return true if included + */ public boolean inIntersect() { return this == BOTH; } } + /** + * A mutable map entry + */ public static class MyEntry implements Entry { private AddressRange key; private Which val; @@ -81,6 +135,14 @@ public class TwoWayBreakdownAddressRangeIterator private final MyEntry entry = new MyEntry(); + /** + * Create an iterator that "breaks down" the two address range iterators. + * + * @param lit the iterator of ranges on the left + * @param rit the iterator of ranges on the right + * @param forward true for forward iteration, false for reverse. The input iterators must be + * ordered according to this flag. + */ public TwoWayBreakdownAddressRangeIterator(Iterator lit, Iterator rit, boolean forward) { this.lit = PeekableIterators.castOrWrap(lit); diff --git a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UnionAddressRangeIterator.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/UnionAddressRangeIterator.java similarity index 79% rename from Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UnionAddressRangeIterator.java rename to Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/UnionAddressRangeIterator.java index d5024751a8..a07ac20539 100644 --- a/Ghidra/Debug/ProposedUtils/src/main/java/ghidra/util/UnionAddressRangeIterator.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/util/UnionAddressRangeIterator.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -21,17 +21,26 @@ import static ghidra.util.MathUtilities.cmin; import java.util.Collection; import java.util.Iterator; +import generic.util.AbstractPeekableIterator; +import generic.util.MergeSortingIterator; import generic.util.PeekableIterator; -import ghidra.program.model.address.*; +import generic.util.PeekableIterators; +import ghidra.program.model.address.Address; +import ghidra.program.model.address.AddressRange; +import ghidra.program.model.address.AddressRangeImpl; +import ghidra.program.model.address.AddressRangeIterator; +/** + * The iterator implementation backing several methods in {@link UnionAddressSetView} + */ public class UnionAddressRangeIterator extends AbstractPeekableIterator implements AddressRangeIterator { - private final PeekableIterator mit; + private final PeekableIterator it; private final boolean forward; /** * Coalesce (by union) ranges from a single iterator - * + *

* The ranges must be returned in order: in the forward direction, by increasing min address; in * the reverse direction, by decreasing max address. * @@ -39,13 +48,13 @@ public class UnionAddressRangeIterator extends AbstractPeekableIterator it, boolean forward) { - this.mit = PeekableIterators.castOrWrap(it); + this.it = PeekableIterators.castOrWrap(it); this.forward = forward; } /** * Union into a single range iterator, several range iterators - * + *

* The ranges will be coalesced so that each returned range is disconnected from any other. The * ranges of each iterator must be returned in order by direction. While not recommended, the * ranges of each iterator may overlap, so long as they are sorted as in @@ -56,7 +65,7 @@ public class UnionAddressRangeIterator extends AbstractPeekableIterator> iterators, boolean forward) { - this.mit = new MergeSortingIterator(iterators, + this.it = new MergeSortingIterator(iterators, forward ? AddressRangeComparators.FORWARD : AddressRangeComparators.BACKWARD); this.forward = forward; } @@ -68,18 +77,18 @@ public class UnionAddressRangeIterator extends AbstractPeekableIterator + * This is equivalent to using {@link AddressSetView#union(AddressSetView)}, but does not + * materialize the difference. The choice of one over the other depends on the number of ranges in + * the inputs and the frequency of use of the result. With few ranges, or in cases where you need to + * access the entire result, anyway, just use the normal {@link AddressRange}. In cases with many, + * many ranges and where only a small part of the result needs to be computed, use this view. It may + * also be advantageous to use this if the inputs are themselves computed lazily. + *

+ * This follows the conventions expected of an {@link AddressSetView} in that the returned ranges + * are disjoint. Thus, it will combine intersecting and abutting ranges from among the inputs. For + * example, the union of [[1,2]] and [[3,4]] is [[1,4]]. + */ public class UnionAddressSetView extends AbstractAddressSetView { private final Collection views; + /** + * Construct the union of the given address set views + * + * @param views the input sets + */ public UnionAddressSetView(AddressSetView... views) { this(Arrays.asList(views)); } + /** + * Construct the union of the given address set views + * + * @param views the input sets + */ public UnionAddressSetView(Collection views) { this.views = views; } diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/DifferenceAddressSetViewTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/DifferenceAddressSetViewTest.java similarity index 95% rename from Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/DifferenceAddressSetViewTest.java rename to Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/DifferenceAddressSetViewTest.java index 92545003af..a05f67cb7f 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/DifferenceAddressSetViewTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/DifferenceAddressSetViewTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,19 +19,16 @@ import static org.junit.Assert.*; import java.util.*; -import org.junit.Before; import org.junit.Test; +import generic.test.AbstractGTest; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; -import ghidra.program.util.DefaultLanguageService; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -public class DifferenceAddressSetViewTest extends AbstractGhidraHeadlessIntegrationTest { - protected Language toy; +public class DifferenceAddressSetViewTest extends AbstractGTest { + protected AddressSpace space = new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 1); protected Address addr(long offset) { - return toy.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + return space.getAddress(offset); } protected AddressRange rng(long min, long max) { @@ -54,12 +51,6 @@ public class DifferenceAddressSetViewTest extends AbstractGhidraHeadlessIntegrat return result; } - @Before - public void setUpIteratorTest() throws LanguageNotFoundException { - toy = DefaultLanguageService.getLanguageService().getLanguage( - new LanguageID("Toy:BE:64:default")); - } - @Test public void testCounts() { AddressSetView difference; diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/IntersectionAddressSetViewTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/IntersectionAddressSetViewTest.java similarity index 95% rename from Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/IntersectionAddressSetViewTest.java rename to Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/IntersectionAddressSetViewTest.java index 7dfbbaa68d..47aa4b8cd1 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/IntersectionAddressSetViewTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/IntersectionAddressSetViewTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,19 +19,16 @@ import static org.junit.Assert.*; import java.util.*; -import org.junit.Before; import org.junit.Test; +import generic.test.AbstractGTest; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; -import ghidra.program.util.DefaultLanguageService; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -public class IntersectionAddressSetViewTest extends AbstractGhidraHeadlessIntegrationTest { - protected Language toy; +public class IntersectionAddressSetViewTest extends AbstractGTest { + protected AddressSpace space = new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 1); protected Address addr(long offset) { - return toy.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + return space.getAddress(offset); } protected AddressRange rng(long min, long max) { @@ -54,12 +51,6 @@ public class IntersectionAddressSetViewTest extends AbstractGhidraHeadlessIntegr return result; } - @Before - public void setUpIteratorTest() throws LanguageNotFoundException { - toy = DefaultLanguageService.getLanguageService().getLanguage( - new LanguageID("Toy:BE:64:default")); - } - @Test public void testCounts() { AddressSetView intersection; diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/MergeSortingIteratorTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/MergeSortingIteratorTest.java similarity index 98% rename from Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/MergeSortingIteratorTest.java rename to Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/MergeSortingIteratorTest.java index 95794d0ee7..5051882244 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/MergeSortingIteratorTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/MergeSortingIteratorTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,6 +22,8 @@ import java.util.Map.Entry; import org.junit.Test; +import generic.util.MergeSortingIterator; + public class MergeSortingIteratorTest { @Test public void testEmptyMap() { diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/SymmetricDifferenceAddressSetViewTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/SymmetricDifferenceAddressSetViewTest.java similarity index 96% rename from Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/SymmetricDifferenceAddressSetViewTest.java rename to Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/SymmetricDifferenceAddressSetViewTest.java index abd8e016dd..c92c924e4f 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/SymmetricDifferenceAddressSetViewTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/SymmetricDifferenceAddressSetViewTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,19 +19,16 @@ import static org.junit.Assert.*; import java.util.*; -import org.junit.Before; import org.junit.Test; +import generic.test.AbstractGTest; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; -import ghidra.program.util.DefaultLanguageService; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -public class SymmetricDifferenceAddressSetViewTest extends AbstractGhidraHeadlessIntegrationTest { - protected Language toy; +public class SymmetricDifferenceAddressSetViewTest extends AbstractGTest { + protected AddressSpace space = new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 1); protected Address addr(long offset) { - return toy.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + return space.getAddress(offset); } protected AddressRange rng(long min, long max) { @@ -54,12 +51,6 @@ public class SymmetricDifferenceAddressSetViewTest extends AbstractGhidraHeadles return result; } - @Before - public void setUpIteratorTest() throws LanguageNotFoundException { - toy = DefaultLanguageService.getLanguageService().getLanguage( - new LanguageID("Toy:BE:64:default")); - } - @Test public void testCounts() { AddressSetView xor; diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/TwoWayBreakdownAddressRangeIteratorTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/TwoWayBreakdownAddressRangeIteratorTest.java similarity index 95% rename from Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/TwoWayBreakdownAddressRangeIteratorTest.java rename to Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/TwoWayBreakdownAddressRangeIteratorTest.java index 9c184e4dbe..5fe5a15164 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/TwoWayBreakdownAddressRangeIteratorTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/TwoWayBreakdownAddressRangeIteratorTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -22,17 +22,15 @@ import java.util.Map.Entry; import org.apache.commons.lang3.tuple.ImmutablePair; import org.apache.commons.lang3.tuple.Pair; -import org.junit.Before; import org.junit.Test; +import generic.test.AbstractGTest; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; -import ghidra.program.util.DefaultLanguageService; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; import ghidra.util.TwoWayBreakdownAddressRangeIterator.Which; -public class TwoWayBreakdownAddressRangeIteratorTest extends AbstractGhidraHeadlessIntegrationTest { - protected Language toy; +public class TwoWayBreakdownAddressRangeIteratorTest extends AbstractGTest { + protected AddressSpace rom = new GenericAddressSpace("rom", 64, AddressSpace.TYPE_RAM, 1); + protected AddressSpace ram = new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 2); protected TwoWayBreakdownAddressRangeIterator makeIterator(AddressSet a, AddressSet b, boolean forward) { @@ -41,11 +39,11 @@ public class TwoWayBreakdownAddressRangeIteratorTest extends AbstractGhidraHeadl } protected Address addr(long offset) { - return toy.getAddressFactory().getDefaultAddressSpace().getAddress(offset); + return rom.getAddress(offset); } protected Address dAddr(long offset) { - return toy.getAddressFactory().getAddressSpace("data").getAddress(offset); + return ram.getAddress(offset); } protected AddressRange rng(long min, long max) { @@ -87,12 +85,6 @@ public class TwoWayBreakdownAddressRangeIteratorTest extends AbstractGhidraHeadl return result; } - @Before - public void setUpIteratorTest() throws LanguageNotFoundException { - toy = DefaultLanguageService.getLanguageService() - .getLanguage(new LanguageID("Toy:BE:64:harvard")); - } - @Test public void testBothEmpty() { AddressSet a = new AddressSet(); diff --git a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/UnionAddressSetViewTest.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/UnionAddressSetViewTest.java similarity index 94% rename from Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/UnionAddressSetViewTest.java rename to Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/UnionAddressSetViewTest.java index f619353408..64ffb86240 100644 --- a/Ghidra/Debug/ProposedUtils/src/test/java/ghidra/util/UnionAddressSetViewTest.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/util/UnionAddressSetViewTest.java @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -19,23 +19,21 @@ import static org.junit.Assert.*; import java.util.*; -import org.junit.Before; import org.junit.Test; +import generic.test.AbstractGTest; import ghidra.program.model.address.*; -import ghidra.program.model.lang.*; -import ghidra.program.util.DefaultLanguageService; -import ghidra.test.AbstractGhidraHeadlessIntegrationTest; -public class UnionAddressSetViewTest extends AbstractGhidraHeadlessIntegrationTest { - protected Language toy; +public class UnionAddressSetViewTest extends AbstractGTest { + protected AddressSpace rom = new GenericAddressSpace("rom", 64, AddressSpace.TYPE_RAM, 1); + protected AddressSpace ram = new GenericAddressSpace("ram", 64, AddressSpace.TYPE_RAM, 2); protected Address addr(long offset) { - return toy.getDefaultSpace().getAddress(offset); + return rom.getAddress(offset); } - protected Address daddr(long offset) { - return toy.getDefaultDataSpace().getAddress(offset); + protected Address dAddr(long offset) { + return ram.getAddress(offset); } protected AddressRange rng(long min, long max) { @@ -43,7 +41,7 @@ public class UnionAddressSetViewTest extends AbstractGhidraHeadlessIntegrationTe } protected AddressRange drng(long min, long max) { - return new AddressRangeImpl(daddr(min), daddr(max)); + return new AddressRangeImpl(dAddr(min), dAddr(max)); } protected AddressSet set(AddressRange... ranges) { @@ -62,12 +60,6 @@ public class UnionAddressSetViewTest extends AbstractGhidraHeadlessIntegrationTe return result; } - @Before - public void setUpIteratorTest() throws LanguageNotFoundException { - toy = DefaultLanguageService.getLanguageService() - .getLanguage(new LanguageID("Toy:BE:64:harvard")); - } - @Test public void testCounts() { AddressSetView union;