mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-3903 Refactor of OverlayAddressSpaces to allow multiple blocks within
the same overlay space
This commit is contained in:
parent
7e4d2bcfaa
commit
0f95d266c3
80 changed files with 3383 additions and 1757 deletions
|
@ -161,8 +161,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
// TODO: Should there be a TraceCompilerSpec?
|
||||
this.baseCompilerSpec =
|
||||
baseLanguage.getCompilerSpecByID(baseCompilerSpec.getCompilerSpecID());
|
||||
this.baseAddressFactory =
|
||||
new TraceAddressFactory(this.baseLanguage, this.baseCompilerSpec);
|
||||
this.baseAddressFactory = new TraceAddressFactory(this.baseLanguage, this.baseCompilerSpec,
|
||||
space -> getAddressSet(space));
|
||||
|
||||
try (Transaction tx = this.openTransaction("Create")) {
|
||||
initOptions(DBOpenMode.CREATE);
|
||||
|
@ -182,6 +182,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
programView = createProgramView(0);
|
||||
}
|
||||
|
||||
private AddressSetView getAddressSet(OverlayAddressSpace space) {
|
||||
// use entire space
|
||||
return new AddressSet(space.getMinAddress(), space.getMaxAddress());
|
||||
}
|
||||
|
||||
public DBTrace(DBHandle dbh, DBOpenMode openMode, TaskMonitor monitor, Object consumer)
|
||||
throws CancelledException, VersionException, IOException, LanguageNotFoundException {
|
||||
super(dbh, openMode, monitor, "Untitled", DB_TIME_INTERVAL, DB_BUFFER_SIZE, consumer);
|
||||
|
@ -214,11 +219,11 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
else {
|
||||
name = traceInfo.getString(NAME, "Unnamed?");
|
||||
baseLanguage = DefaultLanguageService.getLanguageService()
|
||||
.getLanguage(
|
||||
new LanguageID(traceInfo.getString(BASE_LANGUAGE, null)));
|
||||
.getLanguage(new LanguageID(traceInfo.getString(BASE_LANGUAGE, null)));
|
||||
baseCompilerSpec = baseLanguage.getCompilerSpecByID(
|
||||
new CompilerSpecID(traceInfo.getString(BASE_COMPILER, null)));
|
||||
baseAddressFactory = new TraceAddressFactory(baseLanguage, baseCompilerSpec);
|
||||
baseAddressFactory = new TraceAddressFactory(baseLanguage, baseCompilerSpec,
|
||||
space -> getAddressSet(space));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -247,9 +252,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
return;
|
||||
}
|
||||
if (baseAddressFactory.getAddressSpace(as.getSpaceID()) != as) {
|
||||
throw new IllegalArgumentException(
|
||||
"AddressSpace '" + as + "' is not in this trace (language=" + getBaseLanguage() +
|
||||
")");
|
||||
throw new IllegalArgumentException("AddressSpace '" + as +
|
||||
"' is not in this trace (language=" + getBaseLanguage() + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,9 +333,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
@DependentService
|
||||
protected DBTraceDataTypeManager createDataTypeManager()
|
||||
throws CancelledException, IOException {
|
||||
return createTraceManager("Data Type Manager",
|
||||
(openMode, monitor) -> new DBTraceDataTypeManager(dbh, openMode, rwLock, monitor,
|
||||
this));
|
||||
return createTraceManager("Data Type Manager", (openMode,
|
||||
monitor) -> new DBTraceDataTypeManager(dbh, openMode, rwLock, monitor, this));
|
||||
}
|
||||
|
||||
@DependentService
|
||||
|
@ -366,8 +369,7 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
}
|
||||
|
||||
@DependentService
|
||||
protected DBTraceObjectManager createObjectManager()
|
||||
throws CancelledException, IOException {
|
||||
protected DBTraceObjectManager createObjectManager() throws CancelledException, IOException {
|
||||
return createTraceManager("Object Manager",
|
||||
(openMode, monitor) -> new DBTraceObjectManager(dbh, openMode, rwLock, monitor,
|
||||
baseLanguage, this));
|
||||
|
@ -376,9 +378,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
@DependentService
|
||||
protected DBTraceOverlaySpaceAdapter createOverlaySpaceAdapter()
|
||||
throws CancelledException, IOException {
|
||||
return createTraceManager("Overlay Space Adapter",
|
||||
(openMode, monitor) -> new DBTraceOverlaySpaceAdapter(dbh, openMode, rwLock, monitor,
|
||||
this));
|
||||
return createTraceManager("Overlay Space Adapter", (openMode,
|
||||
monitor) -> new DBTraceOverlaySpaceAdapter(dbh, openMode, rwLock, monitor, this));
|
||||
}
|
||||
|
||||
@DependentService
|
||||
|
@ -409,9 +410,9 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
@DependentService
|
||||
protected DBTraceStaticMappingManager createStaticMappingManager(
|
||||
DBTraceOverlaySpaceAdapter overlayAdapter) throws CancelledException, IOException {
|
||||
return createTraceManager("Static Mapping Manager", (openMode,
|
||||
monitor) -> new DBTraceStaticMappingManager(dbh, openMode, rwLock, monitor, this,
|
||||
overlayAdapter));
|
||||
return createTraceManager("Static Mapping Manager",
|
||||
(openMode, monitor) -> new DBTraceStaticMappingManager(dbh, openMode, rwLock, monitor,
|
||||
this, overlayAdapter));
|
||||
}
|
||||
|
||||
@DependentService
|
||||
|
@ -434,9 +435,8 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
@DependentService
|
||||
protected DBTraceTimeManager createTimeManager(DBTraceThreadManager threadManager)
|
||||
throws IOException, CancelledException {
|
||||
return createTraceManager("Time Manager",
|
||||
(openMode, monitor) -> new DBTraceTimeManager(dbh, openMode, rwLock, monitor, this,
|
||||
threadManager));
|
||||
return createTraceManager("Time Manager", (openMode, monitor) -> new DBTraceTimeManager(dbh,
|
||||
openMode, rwLock, monitor, this, threadManager));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -830,13 +830,13 @@ public class DBTrace extends DBCachedDomainObjectAdapter implements Trace, Trace
|
|||
allViews(v -> v.updateMemoryChangeRegionBlockFlags(region, lifespan));
|
||||
}
|
||||
|
||||
public void updateViewsChangeRegionBlockRange(TraceMemoryRegion region,
|
||||
AddressRange oldRange, AddressRange newRange) {
|
||||
public void updateViewsChangeRegionBlockRange(TraceMemoryRegion region, AddressRange oldRange,
|
||||
AddressRange newRange) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockRange(region, oldRange, newRange));
|
||||
}
|
||||
|
||||
public void updateViewsChangeRegionBlockLifespan(TraceMemoryRegion region,
|
||||
Lifespan oldLifespan, Lifespan newLifespan) {
|
||||
public void updateViewsChangeRegionBlockLifespan(TraceMemoryRegion region, Lifespan oldLifespan,
|
||||
Lifespan newLifespan) {
|
||||
allViews(v -> v.updateMemoryChangeRegionBlockLifespan(region, oldLifespan, newLifespan));
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,10 @@ import java.util.*;
|
|||
import java.util.concurrent.locks.ReadWriteLock;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.database.ProgramAddressFactory;
|
||||
import ghidra.program.database.ProgramOverlayAddressSpace;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.trace.database.DBTrace;
|
||||
import ghidra.trace.database.DBTraceManager;
|
||||
import ghidra.trace.model.Trace.TraceOverlaySpaceChangeType;
|
||||
|
@ -118,8 +121,6 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
static final String NAME_COLUMN_NAME = "Name";
|
||||
static final String BASE_COLUMN_NAME = "Base";
|
||||
|
||||
// NOTE: I don't care to record min/max limit
|
||||
|
||||
@DBAnnotatedColumn(NAME_COLUMN_NAME)
|
||||
static DBObjectColumn NAME_COLUMN;
|
||||
@DBAnnotatedColumn(BASE_COLUMN_NAME)
|
||||
|
@ -148,8 +149,6 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
protected final DBCachedObjectStore<DBTraceOverlaySpaceEntry> overlayStore;
|
||||
protected final DBCachedObjectIndex<String, DBTraceOverlaySpaceEntry> overlaysByName;
|
||||
|
||||
private final Map<Long, AddressSpace> spacesByKey = new HashMap<>();
|
||||
|
||||
public DBTraceOverlaySpaceAdapter(DBHandle dbh, DBOpenMode openMode, ReadWriteLock lock,
|
||||
TaskMonitor monitor, DBTrace trace) throws VersionException, IOException {
|
||||
this.dbh = dbh;
|
||||
|
@ -183,61 +182,92 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
}
|
||||
|
||||
protected void resyncAddressFactory(TraceAddressFactory factory) {
|
||||
// Clean and rename existing overlays, first
|
||||
|
||||
// Perform reconciliation of overlay address spaces while attempting to preserve
|
||||
// address space instances associated with a given key
|
||||
|
||||
// Put all overlay records into key-based map
|
||||
Map<Long, DBTraceOverlaySpaceEntry> keyToRecordMap = new HashMap<>(overlayStore.asMap());
|
||||
|
||||
// Examine existing overlay spaces for removals and renames
|
||||
List<ProgramOverlayAddressSpace> renameList = new ArrayList<>();
|
||||
for (AddressSpace space : factory.getAllAddressSpaces()) {
|
||||
if (!(space instanceof OverlayAddressSpace)) {
|
||||
continue;
|
||||
if (space instanceof ProgramOverlayAddressSpace os) {
|
||||
String name = os.getName();
|
||||
DBTraceOverlaySpaceEntry ent = keyToRecordMap.get(os.getKey());
|
||||
if (ent == null || !isCompatibleOverlay(os, ent, factory)) {
|
||||
// Remove overlay if entry does not exist or base space differs
|
||||
factory.removeOverlaySpace(name);
|
||||
}
|
||||
OverlayAddressSpace os = (OverlayAddressSpace) space;
|
||||
DBTraceOverlaySpaceEntry ent = overlayStore.getObjectAt(os.getDatabaseKey());
|
||||
if (ent == null) {
|
||||
spacesByKey.remove(os.getDatabaseKey());
|
||||
factory.removeOverlaySpace(os.getName());
|
||||
else if (name.equals(ent.name)) {
|
||||
keyToRecordMap.remove(os.getKey());
|
||||
continue; // no change to space
|
||||
}
|
||||
else if (!os.getName().equals(ent.name)) {
|
||||
factory.removeOverlaySpace(os.getName());
|
||||
os.setName(ent.name);
|
||||
try {
|
||||
factory.addOverlayAddressSpace(os);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertionError(); // I just removed it
|
||||
}
|
||||
}
|
||||
// else it's already in sync
|
||||
}
|
||||
// Add missing overlays
|
||||
for (DBTraceOverlaySpaceEntry ent : overlayStore.asMap().values()) {
|
||||
AddressSpace exists = factory.getAddressSpace(ent.name);
|
||||
if (exists != null) {
|
||||
// it's already in sync and/or its a physical space
|
||||
continue;
|
||||
}
|
||||
AddressSpace baseSpace = factory.getAddressSpace(ent.baseSpace);
|
||||
try {
|
||||
OverlayAddressSpace space = factory.addOverlayAddressSpace(ent.name, true,
|
||||
baseSpace, baseSpace.getMinAddress().getOffset(),
|
||||
baseSpace.getMaxAddress().getOffset());
|
||||
space.setDatabaseKey(ent.getKey());
|
||||
spacesByKey.put(space.getDatabaseKey(), space);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new AssertionError(); // Name should be validated already, no?
|
||||
else {
|
||||
// Add space to map of those that need to be renamed
|
||||
renameList.add(os);
|
||||
factory.removeOverlaySpace(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected AddressSpace doCreateOverlaySpace(String name, AddressSpace base) {
|
||||
try {
|
||||
// Handle all renamed overlays which had been temporarily removed from factory
|
||||
for (ProgramOverlayAddressSpace existingSpace : renameList) {
|
||||
long key = existingSpace.getKey();
|
||||
DBTraceOverlaySpaceEntry ent = keyToRecordMap.get(key);
|
||||
existingSpace.setName(ent.name);
|
||||
factory.addOverlaySpace(existingSpace); // re-add renamed space
|
||||
keyToRecordMap.remove(key);
|
||||
}
|
||||
|
||||
// Add any remaing overlay which are missing from factory
|
||||
for (long key : keyToRecordMap.keySet()) {
|
||||
DBTraceOverlaySpaceEntry ent = keyToRecordMap.get(key);
|
||||
String spaceName = ent.name;
|
||||
AddressSpace baseSpace = factory.getAddressSpace(ent.baseSpace);
|
||||
factory.addOverlaySpace(key, spaceName, baseSpace);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException | DuplicateNameException e) {
|
||||
throw new AssertionError("Unexpected error updating overlay address spaces", e);
|
||||
}
|
||||
|
||||
factory.refreshStaleOverlayStatus();
|
||||
}
|
||||
|
||||
private boolean isCompatibleOverlay(ProgramOverlayAddressSpace os, DBTraceOverlaySpaceEntry ent,
|
||||
ProgramAddressFactory factory) {
|
||||
AddressSpace baseSpace = factory.getAddressSpace(ent.baseSpace);
|
||||
if (baseSpace == null) {
|
||||
// Error condition should be handled better - language may have dropped original base space
|
||||
throw new RuntimeException("Base space for overlay not found: " + ent.baseSpace);
|
||||
}
|
||||
return baseSpace == os.getOverlayedSpace();
|
||||
}
|
||||
|
||||
protected AddressSpace doCreateOverlaySpace(String name, AddressSpace base)
|
||||
throws DuplicateNameException {
|
||||
TraceAddressFactory factory = trace.getInternalAddressFactory();
|
||||
OverlayAddressSpace space =
|
||||
factory.addOverlayAddressSpace(name, true, base, base.getMinAddress().getOffset(),
|
||||
base.getMaxAddress().getOffset());
|
||||
// Only if it succeeds do we store the record
|
||||
|
||||
if (!factory.isValidOverlayBaseSpace(base)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid address space for overlay: " + base.getName());
|
||||
}
|
||||
|
||||
if (factory.getAddressSpace(name) != null) {
|
||||
throw new DuplicateNameException(
|
||||
"Overlay space '" + name + "' duplicates name of another address space");
|
||||
}
|
||||
|
||||
DBTraceOverlaySpaceEntry ent = overlayStore.create();
|
||||
ProgramOverlayAddressSpace space = factory.addOverlaySpace(ent.getKey(), name, base);
|
||||
|
||||
// Only if it succeeds do we store the record
|
||||
ent.set(space.getName(), base.getName());
|
||||
trace.updateViewsAddSpaceBlock(space);
|
||||
trace.setChanged(new TraceChangeRecord<>(TraceOverlaySpaceChangeType.ADDED, null,
|
||||
trace, null, space));
|
||||
trace.setChanged(
|
||||
new TraceChangeRecord<>(TraceOverlaySpaceChangeType.ADDED, null, trace, null, space));
|
||||
return space;
|
||||
}
|
||||
|
||||
|
@ -261,8 +291,13 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
if (space != null) {
|
||||
return space.getPhysicalSpace() == base ? space : null;
|
||||
}
|
||||
try {
|
||||
return doCreateOverlaySpace(name, base);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void deleteOverlayAddressSpace(String name) {
|
||||
|
@ -280,6 +315,8 @@ public class DBTraceOverlaySpaceAdapter implements DBTraceManager {
|
|||
trace.updateViewsDeleteSpaceBlock(space);
|
||||
trace.setChanged(new TraceChangeRecord<>(TraceOverlaySpaceChangeType.DELETED, null,
|
||||
trace, space, null));
|
||||
invalidateCache(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,46 +15,51 @@
|
|||
*/
|
||||
package ghidra.trace.database.address;
|
||||
|
||||
import ghidra.program.database.ProgramAddressFactory;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.OverlayAddressSpace;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class TraceAddressFactory extends ProgramAddressFactory {
|
||||
|
||||
public TraceAddressFactory(Language language, CompilerSpec compilerSpec) {
|
||||
super(language, compilerSpec);
|
||||
public TraceAddressFactory(Language language, CompilerSpec compilerSpec,
|
||||
OverlayRegionSupplier overlayRegionSupplier) {
|
||||
super(language, compilerSpec, overlayRegionSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean validateOriginalSpace(AddressSpace originalSpace) {
|
||||
return (originalSpace.isMemorySpace() || originalSpace.isRegisterSpace()) &&
|
||||
!originalSpace.isOverlaySpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean assignUniqueID(AddressSpace originalSpace) {
|
||||
return super.assignUniqueID(originalSpace) ||
|
||||
originalSpace.getType() == AddressSpace.TYPE_REGISTER;
|
||||
protected boolean isValidOverlayBaseSpace(AddressSpace baseSpace) {
|
||||
return super.isValidOverlayBaseSpace(baseSpace) ||
|
||||
baseSpace.getType() == AddressSpace.TYPE_REGISTER;
|
||||
}
|
||||
|
||||
@Override // for peer access
|
||||
protected OverlayAddressSpace addOverlayAddressSpace(String name, boolean preserveName,
|
||||
AddressSpace originalSpace, long minOffset, long maxOffset) {
|
||||
return super.addOverlayAddressSpace(name, preserveName, originalSpace, minOffset,
|
||||
maxOffset);
|
||||
protected ProgramOverlayAddressSpace addOverlaySpace(long key, String overlayName,
|
||||
AddressSpace baseSpace) throws DuplicateNameException {
|
||||
return super.addOverlaySpace(key, overlayName, baseSpace);
|
||||
}
|
||||
|
||||
@Override // for peer access
|
||||
protected void addOverlayAddressSpace(OverlayAddressSpace ovSpace)
|
||||
protected void addOverlaySpace(ProgramOverlayAddressSpace ovSpace)
|
||||
throws DuplicateNameException {
|
||||
super.addOverlayAddressSpace(ovSpace);
|
||||
super.addOverlaySpace(ovSpace);
|
||||
}
|
||||
|
||||
@Override // for peer access
|
||||
protected void removeOverlaySpace(String name) {
|
||||
super.removeOverlaySpace(name);
|
||||
}
|
||||
|
||||
@Override // for peer access
|
||||
protected void overlaySpaceRenamed(String oldOverlaySpaceName, String newName,
|
||||
boolean refreshStatusIfNeeded) {
|
||||
super.overlaySpaceRenamed(oldOverlaySpaceName, newName, refreshStatusIfNeeded);
|
||||
}
|
||||
|
||||
@Override // for peer access
|
||||
protected void refreshStaleOverlayStatus() {
|
||||
super.refreshStaleOverlayStatus();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import ghidra.framework.model.*;
|
|||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.IntRangeMap;
|
||||
import ghidra.program.database.ProgramOverlayAddressSpace;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
|
@ -63,8 +64,7 @@ import ghidra.trace.model.thread.TraceThread;
|
|||
import ghidra.trace.util.TraceAddressSpace;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.datastruct.WeakValueHashMap;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -1021,6 +1021,25 @@ public class DBTraceProgramView implements TraceProgramView {
|
|||
return changes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramOverlayAddressSpace createOverlaySpace(String overlaySpaceName,
|
||||
AddressSpace baseSpace) throws IllegalStateException, DuplicateNameException,
|
||||
InvalidNameException, LockException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameOverlaySpace(String oldOverlaySpaceName, String newName)
|
||||
throws NotFoundException, InvalidNameException, DuplicateNameException, LockException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeOverlaySpace(String overlaySpaceName)
|
||||
throws LockException, NotFoundException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressFactory getAddressFactory() {
|
||||
return trace.getBaseAddressFactory();
|
||||
|
|
|
@ -25,6 +25,7 @@ import ghidra.framework.model.*;
|
|||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.IntRangeMap;
|
||||
import ghidra.program.database.ProgramOverlayAddressSpace;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.CategoryPath;
|
||||
|
@ -43,8 +44,8 @@ import ghidra.trace.model.data.TraceBasedDataTypeManager;
|
|||
import ghidra.trace.model.program.TraceProgramView;
|
||||
import ghidra.trace.model.program.TraceProgramViewMemory;
|
||||
import ghidra.trace.model.thread.TraceThread;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class DBTraceProgramViewRegisters implements TraceProgramView {
|
||||
|
@ -293,6 +294,25 @@ public class DBTraceProgramViewRegisters implements TraceProgramView {
|
|||
return view.getImageBase();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramOverlayAddressSpace createOverlaySpace(String overlaySpaceName,
|
||||
AddressSpace baseSpace) throws IllegalStateException, DuplicateNameException,
|
||||
InvalidNameException, LockException {
|
||||
return view.createOverlaySpace(overlaySpaceName, baseSpace);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameOverlaySpace(String overlaySpaceName, String newName)
|
||||
throws NotFoundException, InvalidNameException, DuplicateNameException, LockException {
|
||||
view.renameOverlaySpace(overlaySpaceName, newName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeOverlaySpace(String overlaySpaceName)
|
||||
throws LockException, NotFoundException {
|
||||
return view.removeOverlaySpace(overlaySpaceName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setImageBase(Address base, boolean commit)
|
||||
throws AddressOverflowException, LockException, IllegalStateException {
|
||||
|
|
|
@ -60,8 +60,23 @@
|
|||
by importers. At this point in time there is no capability provided by the Memory Map provider to create a
|
||||
new File Bytes instance.</P>
|
||||
|
||||
<P><A name="OverlayType"></A><B>Overlay</B> - Each of the above memory block types may optionally be specified as an <I>Overlay</I> at the
|
||||
time of creation. If this option is selected, the block is created in a new
|
||||
<P><A name="OverlayType"></A><B>Overlay</B> - Each of the above memory block types may
|
||||
optionally be created as an <I>Overlay</I> block. One or more memory blocks may be defined
|
||||
within the same overlay address space.
|
||||
|
||||
|
||||
An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
|
||||
|
||||
|
||||
If this option is selected, the block is created in a new
|
||||
overlay address space. Overlay blocks can serve various
|
||||
purposes where a memory range may contain different data/code or map to different areas of memory
|
||||
at any given point in time or processor state. Note that
|
||||
|
@ -87,29 +102,35 @@
|
|||
<P>Each row displays information about one of the memory blocks. The following summarizes
|
||||
the information about each block.</P>
|
||||
|
||||
<P><IMG src="help/shared/note.png" border="0">Many of the Memory Map table fields may be
|
||||
modified to alter the memory block specification (such fields are marked with an '*').</P>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<P><B><I>Name</I></B> - Name of the memory block. </P>
|
||||
<P><B><I>Name * </I></B> - Name of the memory block. </P>
|
||||
|
||||
<P><I><B>Start -</B></I> The starting address (in hex) of the memory block.</P>
|
||||
<P><I><B>Start -</B></I> The starting address (in hex) of the memory block. For overlay blocks
|
||||
this will reflect an overlay address which includes the name of the overlay address space.</P>
|
||||
|
||||
<P><B><I>End -</I></B> The Ending address (in hex) of the memory block.</P>
|
||||
<P><B><I>End -</I></B> The ending address (in hex) of the memory block. For overlay blocks
|
||||
this will reflect an overlay address which includes the name of the overlay address space.</P>
|
||||
|
||||
<P><I><B>Length -</B></I> The length (in hex) of the memory block.</P>
|
||||
|
||||
<P><I><B>R -</B></I> Indicates read permission.</P>
|
||||
<P><I><B>R * -</B></I> Indicates read permission.</P>
|
||||
|
||||
<P><I><B>W -</B></I> Indicates write permission.</P>
|
||||
<P><I><B>W * -</B></I> Indicates write permission.</P>
|
||||
|
||||
<P><I><B>X -</B></I> Indicates execute permission.</P>
|
||||
<P><I><B>X * -</B></I> Indicates execute permission.</P>
|
||||
|
||||
<P><B>Volatile</B> - Indicates a region of volatile I/O Memory.</P>
|
||||
<P><B>Volatile * </B> - Indicates a region of volatile I/O Memory.</P>
|
||||
|
||||
<P><I><B>Overlay -</B></I> Indicates if block is defined as a memory overlay.</P>
|
||||
<P><I><B>Overlayed Space -</B></I> If the block is an overlay block this column indicates the name
|
||||
of the overlayed physical memory space. This field will be empty for non-overlay blocks.</P>
|
||||
|
||||
<P><I><B>Type -</B></I> Indicates whether the block is a <A href="#DefaultType">Default</A>,
|
||||
<A href="#BitMappedType">Bit Mapped</A> or <A href="#ByteMappedType">Byte Mapped</A> type of block.</P>
|
||||
|
||||
<P><I><B>Initialized -</B></I> Indicates whether the block has been initialized with values;
|
||||
<P><I><B>Initialized * -</B></I> Indicates whether the block has been initialized with values;
|
||||
this property applies to Default and Overlay blocks.</P>
|
||||
|
||||
<P><I><B>Byte Source -</B></I> Provides information about the source of the bytes in this
|
||||
|
@ -121,11 +142,26 @@
|
|||
|
||||
<P><I><B>Source -</B></I> Description of block origination.</P>
|
||||
|
||||
<P><I><B>Comment -</B></I> User added comment about this memory block.</P>
|
||||
<P><I><B>Comment * -</B></I> User added comment about this memory block.</P>
|
||||
|
||||
<P> </P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="OverlaySpaceRename"></A>Rename Overlay Address Space</H2>
|
||||
<BLOCKQUOTE>
|
||||
<P>An overlay address space may be renamed by selecting an overlay block within the table.
|
||||
Its current overlay address space name should appear as the prefix to its Start address
|
||||
(e.g., OV1::00001000 where OV1 is the current name of the overlay space containing the
|
||||
overlay block). The popup menu action <B>Rename Overlay Space</B> may be selected after
|
||||
a right-click on the selected overlay block row. This will popup a window from which the
|
||||
overlay space may be renamed.</P>
|
||||
|
||||
<P><IMG src="help/shared/note.png" border="0">An important consideration when renaming overlay memory spaces is that any Diff operation
|
||||
between the affected Program and another Program may not behave as expected until after the
|
||||
Program is closed and re-opened. This is caused by address comparison and ordering which
|
||||
will continue to use the original overlay space name until the program is re-opened.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H2><A name="MemoryBlockEdits"></A>Memory Block Edits</H2>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
|
@ -190,12 +226,10 @@
|
|||
|
||||
<H3><A name="Add_Block"></A><B><IMG src="images/Plus.png" border="0"> Add</B></H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>Select <B>Add</B> to bring up the <I>Add Memory Block</I> dialog. Fill in the
|
||||
requested information and select the <B>OK</B> button.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P> </P>
|
||||
|
||||
|
@ -209,7 +243,6 @@
|
|||
<BR>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P> </P>
|
||||
|
||||
|
@ -218,8 +251,9 @@
|
|||
<P><B><I>Start Addr</I></B> - Enter the start address of the new memory block. If the
|
||||
program language defines multiple address spaces, the address space must also be
|
||||
specified. The address space selection will not appear if only one is defined.
|
||||
Overlay spaces are not included in the list of spaces. Within the defaul address
|
||||
space, a block may not span across the current Image Base Address.<BR>
|
||||
If creating an overlay memory block within an existing overlay address space that
|
||||
space should be selected. A block within the default address space may not span across
|
||||
the current Image Base Address.<BR>
|
||||
</P>
|
||||
|
||||
<P><B><I>Length -</I></B> Enter the length of the new memory block.</P>
|
||||
|
@ -234,7 +268,15 @@
|
|||
|
||||
<P><B>Volatile</B> - Marks this block as volatile I/O memory.</P>
|
||||
|
||||
<P><B>Overlay</B> - Creates the block as an overlay within a corresponding overlay address space.</P>
|
||||
<P><B>Overlay</B> - Creates the block as an overlay block. An overlay memory block may be
|
||||
created in two ways:
|
||||
<ul>
|
||||
<li>Specifying a <B>Start Addr</B> within an existing overlay address space
|
||||
(this <B>Overlay</B> option is redudant and ignored), or</li>
|
||||
<li>Specifying a <B>Start Addr</B> within a physical memory address space and enabling
|
||||
this <B>Overlay</B> option. This use case will force the creation of a new unique overlay
|
||||
address space.</li>
|
||||
</ul>
|
||||
|
||||
<P><B><I>Block Types</I></B> - Select the block type from the combo box: <I><B>Default, Bit
|
||||
Mapped or Byte Mapped</B></I>.</P>
|
||||
|
@ -291,7 +333,6 @@
|
|||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<DIV align="center">
|
||||
<CENTER>
|
||||
|
@ -307,13 +348,11 @@
|
|||
|
||||
<H3><A name="Move_Block"></A><IMG src="images/move.png" border="0"> Move</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>Select <B>Move</B> to bring up the <I>Move Memory Block</I> dialog. The <I>Move</I>
|
||||
action is enabled when exactly one memory block is selected. Enter either a new start
|
||||
or end address to cause the block to be moved.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P> </P>
|
||||
|
||||
|
@ -327,7 +366,6 @@
|
|||
<BR>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P> </P>
|
||||
|
||||
|
@ -357,11 +395,9 @@
|
|||
<LI><I>The block is an <A href="#OverlayType">Overlay</A> block.</I></LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Split_Block"></A><IMG src="images/verticalSplit.png" border="0"> Split</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>Select <B>Split</B> to bring up the <I>Split Block</I> Dialog. The <I>Split</I> action
|
||||
is enabled when exactly one memory block is selected. Use the <I>Split Block</I>
|
||||
|
@ -378,7 +414,6 @@
|
|||
<LI>Enter a length for the second block (new block).</LI>
|
||||
</UL>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P> </P>
|
||||
|
||||
|
@ -394,7 +429,6 @@
|
|||
|
||||
<H3> </H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P><B><FONT color="#000080">Block to Split</FONT></B></P>
|
||||
|
||||
|
@ -424,12 +458,10 @@
|
|||
<P><I><IMG src="help/shared/note.png" border="0><a href=">Overlay type blocks cannot
|
||||
be split. </I></P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Expand_Block_Up"></A><IMG src="images/collapse.gif" border="0"> Expand
|
||||
Up</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>Select <B>Expand Up</B> to bring up the <I>Expand Block Up</I> Dialog. The <I>Expand
|
||||
Up</I> action is enabled when exactly one memory block is selected. Use the <I>Expand
|
||||
|
@ -437,7 +469,6 @@
|
|||
memory block. The block can be expanded by either entering a new start address or a
|
||||
new length.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P> </P>
|
||||
|
||||
|
@ -451,7 +482,6 @@
|
|||
<BR>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P><B><I>New Start Address -</I></B> A new start address can be entered here. It must
|
||||
be before the current start address.</P>
|
||||
|
@ -464,12 +494,10 @@
|
|||
<P><I><IMG src="help/shared/note.png" border="0"><A href="#OverlayType">Overlay</A> type
|
||||
blocks cannot be expanded. </I></P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Expand_Block_Down"></A><IMG src="images/expand.gif" border="0"> Expand
|
||||
Down</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>Select <B>Expand Down</B> to bring up the <I>Expand Block Down</I> Dialog. The <I>Expand
|
||||
Down</I> action is enabled when exactly one memory block is selected. Use the
|
||||
|
@ -477,7 +505,6 @@
|
|||
AFTER the memory block. The block can be expanded by either entering a new end address or a
|
||||
new length.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P> </P>
|
||||
|
||||
|
@ -491,7 +518,6 @@
|
|||
<BR>
|
||||
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P><I><B>Start Address -</B></I> Displays the start address of the block (not
|
||||
editable).</P>
|
||||
|
@ -505,11 +531,9 @@
|
|||
<P><I><IMG src="help/shared/note.png" border="0"><A href="#OverlayType">Overlay</A> type
|
||||
blocks cannot be expanded. </I></P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Merge_Blocks"></A><IMG src="images/Merge.png" border="0"> Merge</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>The <I>Merge</I> action is enabled when two or more memory blocks are selected. It
|
||||
attempts to merge all selected blocks into one block. Any "gaps" will be "filled in"
|
||||
|
@ -525,11 +549,9 @@
|
|||
initialization state can be merged.</P>
|
||||
<P><I><IMG src="help/shared/note.png" border="0"></I>Overlay type blocks cannot be merged.</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Delete_Block"></A><IMG src="images/edit-delete.png" border="0"> Delete</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>The <I>Delete</I> action is enabled when one or more memory blocks are selected.
|
||||
All selected blocks will be deleted. If the blocks contained defined data or instructions,
|
||||
|
@ -539,13 +561,15 @@
|
|||
<P><IMG src="help/shared/tip.png" border="0">For large blocks that may contain many
|
||||
symbols, references, instructions, etc., the delete operation may take a while to complete.
|
||||
You can cancel the delete operation at any time.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<P><I><IMG src="help/shared/note.png" border="0">When removing an overlay memory block the
|
||||
corresponding overlay address space will also be removed if no other overlay blocks
|
||||
exist within that space.</P>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<H3><A name="Set_Image_Base"></A><IMG src="images/house.png" border="0"> Set Image
|
||||
Base</H3>
|
||||
|
||||
<BLOCKQUOTE>
|
||||
<BLOCKQUOTE>
|
||||
<P>The <I>Set Image Base</I> action allows you to change the base address of a
|
||||
program. This action is useful when working with relocatable code such as DLLs or
|
||||
|
@ -560,7 +584,6 @@
|
|||
<I>OK</I> button.<BR>
|
||||
</P>
|
||||
</BLOCKQUOTE>
|
||||
</BLOCKQUOTE>
|
||||
|
||||
<DIV align="left">
|
||||
<TABLE border="0" width="100%">
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 32 KiB |
|
@ -23,6 +23,7 @@ import docking.ActionContext;
|
|||
import docking.ComponentProvider;
|
||||
import docking.action.DockingAction;
|
||||
import docking.widgets.fieldpanel.*;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import ghidra.GhidraOptions;
|
||||
import ghidra.app.context.ListingActionContext;
|
||||
|
@ -268,8 +269,9 @@ public abstract class AbstractPatchAction extends DockingAction {
|
|||
BigInteger index = adapter.getAddressIndexMap().getIndex(address);
|
||||
int count = layout.getNumFields();
|
||||
for (int i = 0; i < count; i++) {
|
||||
ListingField field = (ListingField) layout.getField(i);
|
||||
if (field.getFieldFactory().getFieldName().equals(fieldName)) {
|
||||
Field f = layout.getField(i);
|
||||
if ((f instanceof ListingField field) &&
|
||||
field.getFieldFactory().getFieldName().equals(fieldName)) {
|
||||
return new FieldLocation(index, i);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -734,8 +734,9 @@ public abstract class AbstractCodeBrowserPlugin<P extends CodeViewerProvider> ex
|
|||
|
||||
int instanceNum = 0;
|
||||
for (int i = 0; i < layout.getNumFields(); i++) {
|
||||
ListingField bf = (ListingField) layout.getField(i);
|
||||
if (bf.getFieldFactory().getFieldName().equals(fieldName)) {
|
||||
Field f = layout.getField(i);
|
||||
if ((f instanceof ListingField bf) &&
|
||||
bf.getFieldFactory().getFieldName().equals(fieldName)) {
|
||||
if (instanceNum++ == occurrence) {
|
||||
fieldNum = i;
|
||||
break;
|
||||
|
|
|
@ -544,7 +544,8 @@ class AddBlockDialog extends DialogComponentProvider implements ChangeListener {
|
|||
addrField = new AddressInput();
|
||||
addrField.setName("Start Addr");
|
||||
addrFactory = model.getProgram().getAddressFactory();
|
||||
addrField.setAddressFactory(addrFactory, true, true);
|
||||
addrField.setAddressFactory(addrFactory,
|
||||
AddressInput.INCLUDE_OTHER_AND_LOADED_MEMORY_SPACES);
|
||||
addrField.addChangeListener(ev -> addrChanged());
|
||||
return addrField;
|
||||
}
|
||||
|
|
|
@ -161,11 +161,12 @@ abstract class ExpandBlockModel implements DomainObjectListener {
|
|||
Program prog = (Program) obj;
|
||||
Memory memory = prog.getMemory();
|
||||
try {
|
||||
String blockName = expandBlock.getName();
|
||||
MemoryBlock newBlock = memory.createBlock(expandBlock,
|
||||
expandBlock.getName() + ".exp", startAddr, length);
|
||||
MemoryBlock b = memory.join(expandBlock, newBlock);
|
||||
if (!b.getName().endsWith(".exp")) {
|
||||
b.setName(b.getName() + ".exp");
|
||||
if (!b.getName().equals(blockName)) {
|
||||
b.setName(blockName); // preserve block name
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -121,9 +121,10 @@ class MemoryMapManager {
|
|||
// make sure that the block after the first block is the second block
|
||||
Address nextStart = blockA.getEnd();
|
||||
AddressSpace space = nextStart.getAddressSpace();
|
||||
if (space.isOverlaySpace()) {
|
||||
if (space.isOverlaySpace() && space.isNonLoadedMemorySpace()) {
|
||||
// impose convention-based restriction
|
||||
Msg.showError(this, plugin.getMemoryMapProvider().getComponent(),
|
||||
"Merge Blocks Failed", "Can't merge overlay blocks");
|
||||
"Merge Blocks Failed", "Cannot merge OTHER overlay blocks");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
final static String WRITE_COL = "W";
|
||||
final static String EXECUTE_COL = "X";
|
||||
final static String VOLATILE_COL = "Volatile";
|
||||
final static String OVERLAY_COL = "Overlay";
|
||||
final static String OVERLAY_COL = "Overlayed Space";
|
||||
final static String BLOCK_TYPE_COL = "Type";
|
||||
final static String INIT_COL = "Initialized";
|
||||
final static String BYTE_SOURCE_COL = "Byte Source";
|
||||
|
@ -124,7 +124,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
@Override
|
||||
public boolean isSortable(int columnIndex) {
|
||||
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
|
||||
columnIndex == VOLATILE || columnIndex == OVERLAY || columnIndex == INIT) {
|
||||
columnIndex == VOLATILE || columnIndex == INIT) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -163,7 +163,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
@Override
|
||||
public Class<?> getColumnClass(int columnIndex) {
|
||||
if (columnIndex == READ || columnIndex == WRITE || columnIndex == EXECUTE ||
|
||||
columnIndex == VOLATILE || columnIndex == OVERLAY || columnIndex == INIT) {
|
||||
columnIndex == VOLATILE || columnIndex == INIT) {
|
||||
return Boolean.class;
|
||||
}
|
||||
return String.class;
|
||||
|
@ -198,12 +198,6 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
}
|
||||
|
||||
private String getAddressString(Address address) {
|
||||
AddressSpace space = address.getAddressSpace();
|
||||
if (space.isOverlaySpace()) {
|
||||
OverlayAddressSpace ovSpace = (OverlayAddressSpace) space;
|
||||
AddressSpace baseSpace = ovSpace.getOverlayedSpace();
|
||||
address = baseSpace.getAddress(address.getOffset());
|
||||
}
|
||||
return address.toString();
|
||||
}
|
||||
|
||||
|
@ -435,7 +429,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
case VOLATILE:
|
||||
return block.isVolatile() ? Boolean.TRUE : Boolean.FALSE;
|
||||
case OVERLAY:
|
||||
return block.isOverlay() ? Boolean.TRUE : Boolean.FALSE;
|
||||
return getOverlayBaseSpaceName(block);
|
||||
case INIT:
|
||||
MemoryBlockType blockType = block.getType();
|
||||
if (blockType == MemoryBlockType.BIT_MAPPED) {
|
||||
|
@ -532,6 +526,14 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
return program;
|
||||
}
|
||||
|
||||
private String getOverlayBaseSpaceName(MemoryBlock block) {
|
||||
AddressSpace space = block.getStart().getAddressSpace();
|
||||
if (space instanceof OverlayAddressSpace ovSpace) {
|
||||
return ovSpace.getOverlayedSpace().getName();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private class MemoryMapComparator implements Comparator<MemoryBlock> {
|
||||
private final int sortColumn;
|
||||
|
||||
|
@ -568,9 +570,9 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> implements Pr
|
|||
int b2v = (b2.isVolatile() ? 1 : -1);
|
||||
return (b1v - b2v);
|
||||
case OVERLAY:
|
||||
int b1o = (b1.isOverlay() ? 1 : -1);
|
||||
int b2o = (b2.isOverlay() ? 1 : -1);
|
||||
return (b1o - b2o);
|
||||
String ov1 = getOverlayBaseSpaceName(b1);
|
||||
String ov2 = getOverlayBaseSpaceName(b2);
|
||||
return ov1.compareTo(ov2);
|
||||
case INIT:
|
||||
int b1init = (b1.isInitialized() ? 1 : -1);
|
||||
int b2init = (b2.isInitialized() ? 1 : -1);
|
||||
|
|
|
@ -18,6 +18,7 @@ package ghidra.app.plugin.core.memory;
|
|||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableColumn;
|
||||
|
@ -26,6 +27,8 @@ import javax.swing.table.TableModel;
|
|||
import docking.ActionContext;
|
||||
import docking.action.DockingAction;
|
||||
import docking.action.ToolBarData;
|
||||
import docking.action.builder.ActionBuilder;
|
||||
import docking.widgets.OptionDialog;
|
||||
import docking.widgets.table.*;
|
||||
import docking.widgets.textfield.GValidatedTextField.MaxLengthField;
|
||||
import generic.theme.GIcon;
|
||||
|
@ -34,11 +37,12 @@ import ghidra.framework.model.DomainFile;
|
|||
import ghidra.framework.plugintool.ComponentProviderAdapter;
|
||||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.OverlayAddressSpace;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.mem.MemoryBlockType;
|
||||
import ghidra.program.model.mem.*;
|
||||
import ghidra.util.HelpLocation;
|
||||
import ghidra.util.Msg;
|
||||
import ghidra.util.exception.UsrException;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.table.GhidraTableFilterPanel;
|
||||
import ghidra.util.table.actions.MakeProgramSelectionAction;
|
||||
|
@ -149,8 +153,6 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
column = table.getColumn(MemoryMapModel.VOLATILE_COL);
|
||||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
column = table.getColumn(MemoryMapModel.OVERLAY_COL);
|
||||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
column = table.getColumn(MemoryMapModel.INIT_COL);
|
||||
column.setCellRenderer(new GBooleanCellRenderer());
|
||||
|
||||
|
@ -182,10 +184,25 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
return memPanel;
|
||||
}
|
||||
|
||||
private boolean canRenameOverlaySpace(ActionContext context) {
|
||||
if (context.getContextObject() != getTable()) {
|
||||
return false;
|
||||
}
|
||||
MemoryBlock block = getSelectedBlock();
|
||||
return block != null && block.isOverlay();
|
||||
}
|
||||
|
||||
private void addLocalActions() {
|
||||
|
||||
Icon addImage = new GIcon("icon.plugin.memorymap.add");
|
||||
// Add popup menu action for renaming overlay space on selected overlay block
|
||||
new ActionBuilder("Rename Overlay Space", plugin.getName())
|
||||
.helpLocation(new HelpLocation("MemoryMapPlugin", "OverlaySpaceRename"))
|
||||
.popupMenuPath("Rename Overlay Space")
|
||||
.enabledWhen(c -> canRenameOverlaySpace(c))
|
||||
.onAction(c -> renameOverlaySpace(c))
|
||||
.buildAndInstallLocal(this);
|
||||
|
||||
Icon addImage = new GIcon("icon.plugin.memorymap.add");
|
||||
addAction = new MemoryMapAction("Add Block", addImage) {
|
||||
@Override
|
||||
public void actionPerformed(ActionContext context) {
|
||||
|
@ -300,6 +317,24 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
tool.addLocalAction(this, action);
|
||||
}
|
||||
|
||||
private boolean checkExclusiveAccess() {
|
||||
if (program.hasExclusiveAccess()) {
|
||||
return true;
|
||||
}
|
||||
String msg = "Close the file and undo your checkout,\n" +
|
||||
"then do a checkout with the exclusive lock.";
|
||||
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df.modifiedSinceCheckout() || df.isChanged()) {
|
||||
msg = "Check in this file, then do a checkout with the\n" + "exclusive lock.";
|
||||
}
|
||||
|
||||
Msg.showInfo(getClass(), MemoryMapProvider.this.getComponent(),
|
||||
"Exclusive Checkout Required", "An exclusive checkout is required in order to\n" +
|
||||
"manipulate memory blocks or change the image base.\n" + msg);
|
||||
return false;
|
||||
}
|
||||
|
||||
private void setBase() {
|
||||
ImageBaseDialog dialog = new ImageBaseDialog(tool, program, program.getImageBase());
|
||||
tool.showDialog(dialog, this);
|
||||
|
@ -445,23 +480,16 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
column.setResizable(false);
|
||||
}
|
||||
|
||||
column = table.getColumn(MemoryMapModel.OVERLAY_COL);
|
||||
if (column != null) {
|
||||
column.setMaxWidth(65);
|
||||
column.setMinWidth(65);
|
||||
column.setResizable(false);
|
||||
}
|
||||
|
||||
column = table.getColumn(MemoryMapModel.BLOCK_TYPE_COL);
|
||||
if (column != null) {
|
||||
column.setMinWidth(60);
|
||||
column.setMinWidth(25);
|
||||
// column.setResizable(true);
|
||||
}
|
||||
|
||||
column = table.getColumn(MemoryMapModel.INIT_COL);
|
||||
if (column != null) {
|
||||
column.setMaxWidth(80);
|
||||
column.setMinWidth(80);
|
||||
column.setMaxWidth(25);
|
||||
column.setMinWidth(25);
|
||||
column.setResizable(false);
|
||||
}
|
||||
}
|
||||
|
@ -522,6 +550,37 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
return tableModel.getBlockAt(row);
|
||||
}
|
||||
|
||||
private void renameOverlaySpace(ActionContext c) {
|
||||
if (!checkExclusiveAccess()) {
|
||||
return;
|
||||
}
|
||||
if (!program.canLock()) {
|
||||
setStatusText("Program is busy, try again later");
|
||||
return;
|
||||
}
|
||||
MemoryBlock block = getSelectedBlock();
|
||||
if (block == null || !block.isOverlay()) {
|
||||
return;
|
||||
}
|
||||
OverlayAddressSpace overlaySpace = (OverlayAddressSpace) block.getStart().getAddressSpace();
|
||||
String oldName = overlaySpace.getName();
|
||||
|
||||
String newName = OptionDialog.showInputSingleLineDialog(getComponent(),
|
||||
"Rename Overlay Space", "New Name:", oldName);
|
||||
if (newName == null || oldName.equals(newName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
program.withTransaction("Rename Overlay Space: " + oldName, () -> {
|
||||
program.renameOverlaySpace(oldName, newName);
|
||||
});
|
||||
}
|
||||
catch (UsrException e) {
|
||||
Msg.showError(this, getComponent(), "Rename Overlay Error", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the selected blocks.
|
||||
*/
|
||||
|
@ -560,14 +619,23 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
if (block.isOverlay()) {
|
||||
Msg.showInfo(getClass(), getComponent(), "Expand Overlay Block Not Allowed",
|
||||
"Overlay blocks cannot be expanded.");
|
||||
|
||||
// Check for expansion of FileBytes use
|
||||
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||
int sourceIndex = dialogType == ExpandBlockDialog.EXPAND_UP ? 0 : (sourceInfos.size() - 1);
|
||||
MemoryBlockSourceInfo sourceInfo = sourceInfos.get(sourceIndex);
|
||||
if (sourceInfo.getFileBytes().isPresent()) {
|
||||
int choice = OptionDialog.showOptionDialogWithCancelAsDefaultButton(getComponent(),
|
||||
"Expanding File Bytes Block",
|
||||
"Block use of File Bytes will be expanded with a 0-filled region. Continue?",
|
||||
"Continue...");
|
||||
if (choice != OptionDialog.OPTION_ONE) {
|
||||
return;
|
||||
}
|
||||
else {
|
||||
}
|
||||
|
||||
showExpandBlockDialog(dialogType, block);
|
||||
}
|
||||
}
|
||||
|
||||
private void moveBlock() {
|
||||
if (!program.canLock()) {
|
||||
|
@ -579,9 +647,10 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
return;
|
||||
}
|
||||
|
||||
if (block.isOverlay()) {
|
||||
Msg.showInfo(getClass(), getComponent(), "Move Overlay Block Not Allowed",
|
||||
"Overlay blocks cannot be moved.");
|
||||
if (block.isOverlay() && block.getStart().isNonLoadedMemoryAddress()) {
|
||||
// impose convention-based restriction
|
||||
Msg.showInfo(getClass(), getComponent(), "Moving OTHER Overlay Block Not Allowed",
|
||||
"OTHER overlay blocks cannot be moved.");
|
||||
}
|
||||
else {
|
||||
showMoveBlockDialog(block);
|
||||
|
@ -596,9 +665,10 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
if (block == null) {
|
||||
return;
|
||||
}
|
||||
if (block.isOverlay()) {
|
||||
Msg.showInfo(getClass(), getComponent(), "Split Overlay Block Not Allowed",
|
||||
"Overlay blocks cannot be split.");
|
||||
if (block.isOverlay() && block.getStart().isNonLoadedMemoryAddress()) {
|
||||
// impose convention-based restriction
|
||||
Msg.showInfo(getClass(), getComponent(), "Split OTHER Overlay Block Not Allowed",
|
||||
"OTHER overlay blocks can not be split.");
|
||||
}
|
||||
else {
|
||||
SplitBlockDialog d = new SplitBlockDialog(plugin, block, program.getAddressFactory());
|
||||
|
@ -690,23 +760,5 @@ class MemoryMapProvider extends ComponentProviderAdapter {
|
|||
super(name, plugin.getName());
|
||||
this.setToolBarData(new ToolBarData(icon, "A"));
|
||||
}
|
||||
|
||||
public boolean checkExclusiveAccess() {
|
||||
if (program.hasExclusiveAccess()) {
|
||||
return true;
|
||||
}
|
||||
String msg = "Close the file and undo your checkout,\n" +
|
||||
"then do a checkout with the exclusive lock.";
|
||||
|
||||
DomainFile df = program.getDomainFile();
|
||||
if (df.modifiedSinceCheckout() || df.isChanged()) {
|
||||
msg = "Check in this file, then do a checkout with the\n" + "exclusive lock.";
|
||||
}
|
||||
|
||||
Msg.showInfo(getClass(), MemoryMapProvider.this.getComponent(),
|
||||
"Exclusive Checkout Required", "An exclusive checkout is required in order to\n" +
|
||||
"manipulate memory blocks or change the image base.\n" + msg);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -83,8 +83,8 @@ public class MoveBlockDialog extends DialogComponentProvider implements MoveBloc
|
|||
changing = true;
|
||||
if (!isVisible()) {
|
||||
AddressFactory factory = model.getAddressFactory();
|
||||
newStartField.setAddressFactory(factory, true, false);
|
||||
newEndField.setAddressFactory(factory, true, false);
|
||||
newStartField.setAddressFactory(factory);
|
||||
newEndField.setAddressFactory(factory);
|
||||
}
|
||||
Address newStart = model.getNewStartAddress();
|
||||
if (newStart != null) {
|
||||
|
|
|
@ -19,8 +19,9 @@ import java.awt.*;
|
|||
import java.awt.event.*;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.LineBorder;
|
||||
|
@ -198,7 +199,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
toAddr = toAddr.subtractWrap(defaultOffset);
|
||||
}
|
||||
|
||||
toAddressField.setAddressFactory(fromCu.getProgram().getAddressFactory(), false, false);
|
||||
toAddressField.setAddressFactory(fromCu.getProgram().getAddressFactory());
|
||||
toAddressField.setAddress(toAddr);
|
||||
enableOffsetField(editReference.isOffsetReference());
|
||||
|
||||
|
@ -223,7 +224,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
|
||||
addrHistoryButton.setEnabled(getAddressHistorySize(p) != 0);
|
||||
|
||||
toAddressField.setAddressFactory(p.getAddressFactory(), false, false);
|
||||
toAddressField.setAddressFactory(p.getAddressFactory());
|
||||
|
||||
Address cuAddr = fromCu.getMinAddress();
|
||||
|
||||
|
@ -297,8 +298,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
}
|
||||
if (toAddr != null) {
|
||||
Reference r = p.getReferenceManager()
|
||||
.getReference(fromCu.getMinAddress(), toAddr,
|
||||
fromOpIndex);
|
||||
.getReference(fromCu.getMinAddress(), toAddr, fromOpIndex);
|
||||
if (r != null) {
|
||||
toAddr = null;
|
||||
if (r.isOffsetReference()) {
|
||||
|
@ -582,8 +582,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
historyWin.setLocation(p);
|
||||
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.addPropertyChangeListener(
|
||||
"focusOwner", new PropertyChangeListener() {
|
||||
.addPropertyChangeListener("focusOwner", new PropertyChangeListener() {
|
||||
boolean hasFocus = false;
|
||||
|
||||
@Override
|
||||
|
@ -595,8 +594,7 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
else if (hasFocus) {
|
||||
hasFocus = false;
|
||||
KeyboardFocusManager.getCurrentKeyboardFocusManager()
|
||||
.removePropertyChangeListener(
|
||||
"focusOwner", this);
|
||||
.removePropertyChangeListener("focusOwner", this);
|
||||
hideAddressHistoryPopup();
|
||||
}
|
||||
}
|
||||
|
@ -669,17 +667,13 @@ class EditMemoryReferencePanel extends EditReferencePanel {
|
|||
@SuppressWarnings("unchecked")
|
||||
void readXmlDataState(Element element) {
|
||||
List<Element> programElements = element.getChildren("ADDR_HISTORY");
|
||||
Iterator<Element> iter = programElements.iterator();
|
||||
while (iter.hasNext()) {
|
||||
Element programElement = iter.next();
|
||||
for (Element programElement : programElements) {
|
||||
String programName = programElement.getAttributeValue("PROGRAM");
|
||||
Program program = getOpenProgram(programName);
|
||||
if (program != null) {
|
||||
AddressFactory addrFactory = program.getAddressFactory();
|
||||
List<Element> addrElements = programElement.getChildren("ADDRESS");
|
||||
Iterator<Element> addrIter = addrElements.iterator();
|
||||
while (addrIter.hasNext()) {
|
||||
Element addrElement = addrIter.next();
|
||||
for (Element addrElement : addrElements) {
|
||||
String addrStr = addrElement.getAttributeValue("VALUE");
|
||||
if (addrStr != null) {
|
||||
Address addr = addrFactory.getAddress(addrStr);
|
||||
|
|
|
@ -21,6 +21,7 @@ import java.util.regex.Matcher;
|
|||
import java.util.regex.Pattern;
|
||||
|
||||
import docking.widgets.fieldpanel.Layout;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.FieldLocation;
|
||||
import docking.widgets.fieldpanel.support.RowColLocation;
|
||||
import ghidra.app.plugin.core.searchtext.iterators.*;
|
||||
|
@ -287,15 +288,15 @@ class ListingDisplaySearcher implements Searcher {
|
|||
}
|
||||
|
||||
if (options.isForward()) {
|
||||
while (!monitor.isCancelled() && results.size() == 0 &&
|
||||
currentLayout != null && currentFieldIndex < currentLayout.getNumFields()) {
|
||||
while (!monitor.isCancelled() && results.size() == 0 && currentLayout != null &&
|
||||
currentFieldIndex < currentLayout.getNumFields()) {
|
||||
findNextMatch();
|
||||
}
|
||||
}
|
||||
else {
|
||||
currentFieldIndex = currentLayout.getNumFields() - 1;
|
||||
while (!monitor.isCancelled() && results.size() == 0 &&
|
||||
currentLayout != null && currentFieldIndex >= 0) {
|
||||
while (!monitor.isCancelled() && results.size() == 0 && currentLayout != null &&
|
||||
currentFieldIndex >= 0) {
|
||||
findNextMatch();
|
||||
}
|
||||
}
|
||||
|
@ -343,7 +344,10 @@ class ListingDisplaySearcher implements Searcher {
|
|||
* Returns the number of fields used in the match.
|
||||
*/
|
||||
private int findLocations(int fieldIndex) {
|
||||
ListingField field = (ListingField) currentLayout.getField(fieldIndex);
|
||||
Field f = currentLayout.getField(fieldIndex);
|
||||
if (!(f instanceof ListingField field)) {
|
||||
return 0;
|
||||
}
|
||||
FieldFactory ff = field.getFieldFactory();
|
||||
String fieldName = ff.getFieldName();
|
||||
if (!doSearchField(fieldName)) {
|
||||
|
@ -360,10 +364,14 @@ class ListingDisplaySearcher implements Searcher {
|
|||
options.searchBothInstructionMnemonicAndOperands();
|
||||
if (isMnemonic && isInstructionsOrData) {
|
||||
if (currentFieldIndex <= currentLayout.getNumFields() - 2) {
|
||||
ListingField opField = (ListingField) currentLayout.getField(fieldIndex + 1);
|
||||
Field f2 = currentLayout.getField(fieldIndex + 1);
|
||||
if ((f2 instanceof ListingField opField) && opField.getFieldFactory()
|
||||
.getFieldName()
|
||||
.equals(OperandFieldFactory.FIELD_NAME)) {
|
||||
findMnemonicOperandLocations(field, opField);
|
||||
fieldCount = 2; // if we match here, then signal that we matched across two fields
|
||||
}
|
||||
}
|
||||
else {
|
||||
findLocations(field);
|
||||
}
|
||||
|
@ -389,8 +397,8 @@ class ListingDisplaySearcher implements Searcher {
|
|||
if (startLocation.getAddress().equals(currentAddress)) {
|
||||
// set the current Field index to correspond to the program location
|
||||
for (int i = 0; i < currentLayout.getNumFields(); i++) {
|
||||
ListingField field = (ListingField) currentLayout.getField(i);
|
||||
if (getFieldForLocation(field, i)) {
|
||||
Field f = currentLayout.getField(i);
|
||||
if ((f instanceof ListingField field) && getFieldForLocation(field, i)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -248,8 +248,6 @@ class SelectBlockDialog extends ReusableDialogComponentProvider {
|
|||
|
||||
clearStatusText();
|
||||
|
||||
// the number value is a byte size, which means we need to adjust that value by
|
||||
// the addressable unit size of the processor
|
||||
Address currentAddress = navigatable.getLocation().getAddress();
|
||||
|
||||
AddressSet addressSet = new AddressSet(navigatable.getSelection());
|
||||
|
@ -257,15 +255,16 @@ class SelectBlockDialog extends ReusableDialogComponentProvider {
|
|||
if (addressSet.isEmpty()) {
|
||||
addressSet.addRange(currentAddress, currentAddress);
|
||||
}
|
||||
length *= currentAddress.getAddressSpace().getAddressableUnitSize();
|
||||
|
||||
AddressRangeIterator aiter = addressSet.getAddressRanges();
|
||||
AddressSet newSet = new AddressSet();
|
||||
while (aiter.hasNext()) {
|
||||
AddressRange range = aiter.next();
|
||||
Address toAddress = createForwardToAddress(range.getMinAddress(), length - 1);
|
||||
if (toAddress != null) {
|
||||
newSet.addRange(range.getMinAddress(), toAddress);
|
||||
}
|
||||
}
|
||||
ProgramSelection selection = new ProgramSelection(newSet);
|
||||
NavigationUtils.setSelection(tool, navigatable, selection);
|
||||
}
|
||||
|
@ -279,11 +278,7 @@ class SelectBlockDialog extends ReusableDialogComponentProvider {
|
|||
}
|
||||
clearStatusText();
|
||||
|
||||
// the number value is a byte size, which means we need to adjust that value by
|
||||
// the addressable unit size of the processor
|
||||
Address currentAddress = navigatable.getLocation().getAddress();
|
||||
length *= currentAddress.getAddressSpace().getAddressableUnitSize();
|
||||
|
||||
AddressSet addressSet = new AddressSet(navigatable.getSelection());
|
||||
if (addressSet.isEmpty()) {
|
||||
addressSet.addRange(currentAddress, currentAddress);
|
||||
|
@ -295,54 +290,69 @@ class SelectBlockDialog extends ReusableDialogComponentProvider {
|
|||
AddressRange range = aiter.next();
|
||||
|
||||
Address fromAddress = createBackwardToAddress(range.getMaxAddress(), length - 1);
|
||||
if (fromAddress != null) {
|
||||
newSet.addRange(fromAddress, range.getMaxAddress());
|
||||
}
|
||||
}
|
||||
ProgramSelection selection = new ProgramSelection(newSet);
|
||||
NavigationUtils.setSelection(tool, navigatable, selection);
|
||||
}
|
||||
|
||||
private Address createBackwardToAddress(Address startAddress, long length) {
|
||||
AddressSpace addressSpace = startAddress.getAddressSpace();
|
||||
private Address createBackwardToAddress(Address toAddress, long length) {
|
||||
AddressSpace addressSpace = toAddress.getAddressSpace();
|
||||
if (addressSpace.isOverlaySpace()) {
|
||||
OverlayAddressSpace oas = (OverlayAddressSpace) addressSpace;
|
||||
if (startAddress.getOffset() - length < oas.getMinOffset()) {
|
||||
AddressRange range = oas.getOverlayAddressSet().getRangeContaining(toAddress);
|
||||
if (range == null) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
return addressSpace.getAddress(oas.getMinOffset());
|
||||
}
|
||||
}
|
||||
|
||||
Address toAddress = null;
|
||||
try {
|
||||
toAddress = startAddress.subtract(length);
|
||||
}
|
||||
catch (AddressOutOfBoundsException aoobe) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
toAddress = addressSpace.getMinAddress();
|
||||
}
|
||||
|
||||
return toAddress;
|
||||
}
|
||||
long avail = toAddress.subtract(range.getMinAddress());
|
||||
if (avail < (length - 1)) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
return range.getMinAddress();
|
||||
}
|
||||
}
|
||||
|
||||
private Address createForwardToAddress(Address startAddress, long length) {
|
||||
AddressSpace addressSpace = startAddress.getAddressSpace();
|
||||
Address addr = null;
|
||||
try {
|
||||
addr = toAddress.subtractNoWrap(length);
|
||||
}
|
||||
catch (AddressOverflowException aoobe) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
addr = addressSpace.getMinAddress();
|
||||
}
|
||||
|
||||
return addr;
|
||||
}
|
||||
|
||||
private Address createForwardToAddress(Address fromAddress, long length) {
|
||||
|
||||
AddressSpace addressSpace = fromAddress.getAddressSpace();
|
||||
if (addressSpace.isOverlaySpace()) {
|
||||
OverlayAddressSpace oas = (OverlayAddressSpace) addressSpace;
|
||||
if (startAddress.getOffset() + length > oas.getMaxOffset()) {
|
||||
AddressRange range = oas.getOverlayAddressSet().getRangeContaining(fromAddress);
|
||||
if (range == null) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
return addressSpace.getAddress(oas.getMaxOffset());
|
||||
return fromAddress;
|
||||
}
|
||||
long avail = range.getMaxAddress().subtract(fromAddress);
|
||||
if (avail < (length - 1)) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
return range.getMaxAddress();
|
||||
}
|
||||
}
|
||||
|
||||
Address toAddress = null;
|
||||
Address addr = null;
|
||||
try {
|
||||
toAddress = startAddress.add(length);
|
||||
addr = fromAddress.addNoWrap(length);
|
||||
}
|
||||
catch (AddressOutOfBoundsException aoobe) {
|
||||
catch (AddressOverflowException aoobe) {
|
||||
showWarningDialog(OVERFLOW_SELECTION_WARNING);
|
||||
toAddress = addressSpace.getMaxAddress();
|
||||
addr = addressSpace.getMaxAddress();
|
||||
}
|
||||
|
||||
return toAddress;
|
||||
return addr;
|
||||
}
|
||||
|
||||
private void showWarningDialog(final String text) {
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.awt.FontMetrics;
|
|||
import java.awt.event.ActionListener;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.border.Border;
|
||||
|
@ -44,8 +45,7 @@ public class AddressInput extends JPanel implements FocusableEditor {
|
|||
private boolean stateChanging;
|
||||
private JTextField spaceField;
|
||||
|
||||
private static final Comparator<AddressSpace> ADDRESS_SPACE_SORT_COMPARATOR =
|
||||
(s1, s2) -> {
|
||||
private static final Comparator<AddressSpace> ADDRESS_SPACE_SORT_COMPARATOR = (s1, s2) -> {
|
||||
if (s1.isOverlaySpace()) {
|
||||
if (!s2.isOverlaySpace()) {
|
||||
return 1;
|
||||
|
@ -160,30 +160,47 @@ public class AddressInput extends JPanel implements FocusableEditor {
|
|||
return textField.getText().length() != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address factory to be used to parse addresses. Also
|
||||
* used to set the combo box with the list of valid address spaces
|
||||
* if there is more than one space.
|
||||
*/
|
||||
public void setAddressFactory(AddressFactory factory) {
|
||||
setAddressFactory(factory, false, false);
|
||||
}
|
||||
|
||||
public AddressFactory getAddressFactory() {
|
||||
return addrFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address factory to be used to parse addresses. Also used to set the combo box
|
||||
* with the list of valid address spaces if there is more than one space.
|
||||
* @param factory address factory to use
|
||||
* @param filterOverlaySpaces true if overlay spaces should not appear in the combo box
|
||||
* for the address spaces.
|
||||
* @param allowOtherSpace true if the OTHER space should appear in the combo box for
|
||||
* the address spaces
|
||||
* Address Space predicate which includes all loaded memory spaces.
|
||||
* See {@link AddressSpace#isLoadedMemorySpace()}.
|
||||
* Intended for use with {@link #setAddressFactory(AddressFactory, Predicate)}.
|
||||
*/
|
||||
public void setAddressFactory(AddressFactory factory, boolean filterOverlaySpaces,
|
||||
boolean allowOtherSpace) {
|
||||
public final static Predicate<AddressSpace> INCLUDE_LOADED_MEMORY_SPACES = (s) -> {
|
||||
return s.isLoadedMemorySpace();
|
||||
};
|
||||
|
||||
/**
|
||||
* Address Space predicate which include all loaded memory spaces plus the
|
||||
* {@link AddressSpace#OTHER_SPACE}. See {@link AddressSpace#isLoadedMemorySpace()}.
|
||||
* Intended for use with {@link #setAddressFactory(AddressFactory, Predicate)}.
|
||||
*/
|
||||
public final static Predicate<AddressSpace> INCLUDE_OTHER_AND_LOADED_MEMORY_SPACES = (s) -> {
|
||||
return s.isLoadedMemorySpace() || s.equals(AddressSpace.OTHER_SPACE);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set the address factory to be used to parse addresses. Also
|
||||
* used to set the combo box with the list of valid address spaces
|
||||
* if there is more than one space. Only loaded memory spaces
|
||||
* will be allowed (see {@link AddressSpace#isLoadedMemorySpace()}).
|
||||
* @param factory address factory to use
|
||||
*/
|
||||
public void setAddressFactory(AddressFactory factory) {
|
||||
setAddressFactory(factory, INCLUDE_LOADED_MEMORY_SPACES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address factory to be used to parse addresses. Also used to set the combo box
|
||||
* with the list of valid address spaces if there is more than one space. The specified
|
||||
* predicate will be used to determine if an address space should be included.
|
||||
* @param factory address factory to use
|
||||
* @param predicate callback used to determine if an address space should be included for selection
|
||||
*/
|
||||
public void setAddressFactory(AddressFactory factory, Predicate<AddressSpace> predicate) {
|
||||
this.addrFactory = factory;
|
||||
AddressSpace[] spaces = factory.getAddressSpaces();
|
||||
|
||||
|
@ -194,14 +211,9 @@ public class AddressInput extends JPanel implements FocusableEditor {
|
|||
FontMetrics fm = combo.getFontMetrics(combo.getFont());
|
||||
int width = 0;
|
||||
for (AddressSpace space : spaces) {
|
||||
if (filterOverlaySpaces && space.isOverlaySpace()) {
|
||||
if (!predicate.test(space)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!allowOtherSpace && space.equals(AddressSpace.OTHER_SPACE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String s = space.toString();
|
||||
width = Math.max(width, fm.stringWidth(s));
|
||||
|
||||
|
@ -260,13 +272,25 @@ public class AddressInput extends JPanel implements FocusableEditor {
|
|||
}
|
||||
|
||||
/**
|
||||
* Set the offset part of the address field.
|
||||
* Set the offset part of the address offset field without changing address space.
|
||||
* NOTE: This method is intended for test use only and mimicks user input.
|
||||
* @param value the offset value string
|
||||
*/
|
||||
public void setValue(String value) {
|
||||
textField.setText(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the address space and offset.
|
||||
* NOTE: Unlike {@link #setAddress(Address)} this method is intended for test use only
|
||||
* and mimicks user input with {@link #stateChanged()} notification.
|
||||
* @param addr the address value
|
||||
*/
|
||||
public void setValue(Address addr) {
|
||||
setAddress(addr);
|
||||
stateChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return textField.isEnabled();
|
||||
|
|
|
@ -49,11 +49,10 @@ public class ListingHoverProvider extends AbstractHoverProvider {
|
|||
Rectangle fieldBounds, MouseEvent event) {
|
||||
|
||||
ProgramLocation loc = null;
|
||||
if (field instanceof ListingField) {
|
||||
ListingField listingField = (ListingField) field;
|
||||
if (field instanceof ListingField listingField) {
|
||||
loc = listingField.getFieldFactory()
|
||||
.getProgramLocation(fieldLocation.getRow(),
|
||||
fieldLocation.getCol(), listingField);
|
||||
.getProgramLocation(fieldLocation.getRow(), fieldLocation.getCol(),
|
||||
listingField);
|
||||
}
|
||||
|
||||
return loc;
|
||||
|
|
|
@ -247,14 +247,17 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
|
|||
|
||||
int defaultFieldIndex = 0;
|
||||
for (int i = 0; i < layout.getNumFields(); i++) {
|
||||
ListingField f = (ListingField) layout.getField(i);
|
||||
FieldFactory factory = f.getFieldFactory();
|
||||
Field f = layout.getField(i);
|
||||
if (!(f instanceof ListingField field)) {
|
||||
continue;
|
||||
}
|
||||
FieldFactory factory = field.getFieldFactory();
|
||||
if (factory.getClass() == defaultFieldFactoryClass) {
|
||||
defaultFieldIndex = i;
|
||||
}
|
||||
|
||||
// this method only returns a location if all information matches.
|
||||
FieldLocation floc = factory.getFieldLocation(f, index, i, location);
|
||||
FieldLocation floc = factory.getFieldLocation(field, index, i, location);
|
||||
if (floc != null) {
|
||||
return floc;
|
||||
}
|
||||
|
@ -297,21 +300,18 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
|
|||
return addr != null ? new ProgramLocation(model.getProgram(), addr) : null;
|
||||
}
|
||||
|
||||
ListingField bf = null;
|
||||
|
||||
Field f;
|
||||
if (floc.getFieldNum() >= layout.getNumFields()) {
|
||||
bf = (ListingField) layout.getField(0);
|
||||
f = layout.getField(0);
|
||||
}
|
||||
else {
|
||||
bf = (ListingField) layout.getField(floc.getFieldNum());
|
||||
f = layout.getField(floc.getFieldNum());
|
||||
}
|
||||
|
||||
return getProgramLocation(floc, bf);
|
||||
return (f instanceof ListingField bf) ? getProgramLocation(floc, bf) : null;
|
||||
}
|
||||
|
||||
public ProgramLocation getProgramLocation(FieldLocation location, Field field) {
|
||||
ListingField lf = (ListingField) field;
|
||||
if (lf != null) {
|
||||
if (field instanceof ListingField lf) {
|
||||
FieldFactory factory = lf.getFieldFactory();
|
||||
|
||||
ProgramLocation pLoc =
|
||||
|
@ -502,7 +502,6 @@ public class ListingModelAdapter implements LayoutModel, ListingModelListener {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
public Layout getLayout(Address addr) {
|
||||
BigInteger index = addressToIndexMap.getIndex(addr);
|
||||
return getLayout(index);
|
||||
|
|
|
@ -238,8 +238,8 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
|||
if (show) {
|
||||
headerPanel = new FieldHeader(formatManager, scroller, fieldPanel);
|
||||
// set the model to that of the field at the cursor location
|
||||
ListingField currentField = (ListingField) fieldPanel.getCurrentField();
|
||||
if (currentField != null) {
|
||||
Field f = fieldPanel.getCurrentField();
|
||||
if (f instanceof ListingField currentField) {
|
||||
headerPanel.setSelectedFieldFactory(currentField.getFieldFactory());
|
||||
}
|
||||
}
|
||||
|
@ -771,12 +771,12 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
|||
|
||||
@Override
|
||||
public void buttonPressed(FieldLocation fieldLocation, Field field, MouseEvent mouseEvent) {
|
||||
if (fieldLocation == null || field == null) {
|
||||
if (fieldLocation == null || !(field instanceof ListingField listingField)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ListingField listingField = (ListingField) field;
|
||||
ProgramLocation programLocation = layoutModel.getProgramLocation(fieldLocation, field);
|
||||
ProgramLocation programLocation =
|
||||
layoutModel.getProgramLocation(fieldLocation, listingField);
|
||||
if (programLocation == null) {
|
||||
return;
|
||||
}
|
||||
|
@ -798,8 +798,7 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
|||
|
||||
@Override
|
||||
public void fieldLocationChanged(FieldLocation location, Field field, EventTrigger trigger) {
|
||||
ListingField lf = (ListingField) field;
|
||||
if (lf == null) {
|
||||
if (!(field instanceof ListingField lf)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -905,10 +904,9 @@ public class ListingPanel extends JPanel implements FieldMouseListener, FieldLoc
|
|||
*/
|
||||
public ProgramLocation getProgramLocation(Point point) {
|
||||
FieldLocation dropLoc = new FieldLocation();
|
||||
ListingField field = (ListingField) fieldPanel.getFieldAt(point.x, point.y, dropLoc);
|
||||
if (field != null) {
|
||||
return field.getFieldFactory()
|
||||
.getProgramLocation(dropLoc.getRow(), dropLoc.getCol(), field);
|
||||
Field field = fieldPanel.getFieldAt(point.x, point.y, dropLoc);
|
||||
if (field instanceof ListingField lf) {
|
||||
return lf.getFieldFactory().getProgramLocation(dropLoc.getRow(), dropLoc.getCol(), lf);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,13 +15,13 @@
|
|||
*/
|
||||
package ghidra.app.util.viewer.multilisting;
|
||||
|
||||
import ghidra.app.util.viewer.field.DummyFieldFactory;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
||||
import docking.widgets.fieldpanel.Layout;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.support.MultiRowLayout;
|
||||
import docking.widgets.fieldpanel.support.RowLayout;
|
||||
import ghidra.app.util.viewer.field.DummyFieldFactory;
|
||||
import ghidra.app.util.viewer.format.FormatManager;
|
||||
import ghidra.app.util.viewer.proxy.EmptyProxy;
|
||||
|
||||
class MultiLayout {
|
||||
private Layout[] layouts;
|
||||
|
@ -30,10 +29,6 @@ class MultiLayout {
|
|||
public MultiLayout() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param index2
|
||||
* @param layouts
|
||||
*/
|
||||
public MultiLayout(Layout[] layouts, FormatManager formatMgr, DummyFieldFactory factory) {
|
||||
this.layouts = layouts;
|
||||
int[] rowHeights = new int[formatMgr.getMaxNumRows()];
|
||||
|
@ -41,17 +36,15 @@ class MultiLayout {
|
|||
for (int i = 0; i < layouts.length; i++) {
|
||||
MultiRowLayout layout = (MultiRowLayout) layouts[i];
|
||||
if (layout == null) {
|
||||
layout =
|
||||
new MultiRowLayout(new RowLayout(new Field[] { factory.getField(
|
||||
EmptyProxy.EMPTY_PROXY, 0) }, id), 1);
|
||||
layout = new MultiRowLayout(
|
||||
new RowLayout(new Field[] { factory.getField(EmptyProxy.EMPTY_PROXY, 0) }, id),
|
||||
1);
|
||||
layouts[i] = layout;
|
||||
}
|
||||
layout.fillHeights(rowHeights);
|
||||
|
||||
}
|
||||
for (int i = 0; i < layouts.length; i++) {
|
||||
MultiRowLayout layout = (MultiRowLayout) layouts[i];
|
||||
layout.align(rowHeights);
|
||||
for (Layout layout : layouts) {
|
||||
((MultiRowLayout) layout).align(rowHeights);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -18,8 +17,7 @@ package ghidra.program.util;
|
|||
|
||||
import java.util.Iterator;
|
||||
|
||||
import ghidra.program.model.address.AddressRange;
|
||||
import ghidra.program.model.address.AddressRangeIterator;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Program;
|
||||
|
||||
public class AddressRangeIteratorConverter implements AddressRangeIterator {
|
||||
|
@ -33,14 +31,17 @@ public class AddressRangeIteratorConverter implements AddressRangeIterator {
|
|||
this.program = program;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<AddressRange> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
if (nextRange != null) {
|
||||
return true;
|
||||
|
@ -48,15 +49,17 @@ public class AddressRangeIteratorConverter implements AddressRangeIterator {
|
|||
while (iterator.hasNext()) {
|
||||
AddressRange range = iterator.next();
|
||||
// TODO Future change: May want to get as much of the range as you can if you can't get it all.
|
||||
AddressRange convertedRange = DiffUtility.getCompatibleAddressRange(range, program);
|
||||
if (convertedRange != null) {
|
||||
nextRange = convertedRange;
|
||||
AddressSet convertedRangeSet =
|
||||
DiffUtility.getCompatibleAddressSet(range, program, true);
|
||||
if (convertedRangeSet != null && !convertedRangeSet.isEmpty()) {
|
||||
nextRange = convertedRangeSet.getFirstRange();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressRange next() {
|
||||
if (nextRange != null) {
|
||||
AddressRange convertedRange = nextRange;
|
||||
|
|
|
@ -28,23 +28,28 @@ public class DefaultAddressTranslator implements AddressTranslator {
|
|||
this.sourceProgram = sourceProgram;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program getDestinationProgram() {
|
||||
return destinationProgram;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Program getSourceProgram() {
|
||||
return sourceProgram;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress(Address sourceAddress) {
|
||||
return SimpleDiffUtility.getCompatibleAddress(sourceProgram, sourceAddress,
|
||||
destinationProgram);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOneForOneTranslator() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSet getAddressSet(AddressSetView sourceAddressSet) {
|
||||
if (sourceAddressSet == null) {
|
||||
return null; // FIXME
|
||||
|
@ -55,7 +60,12 @@ public class DefaultAddressTranslator implements AddressTranslator {
|
|||
@Override
|
||||
public AddressRange getAddressRange(AddressRange sourceAddressRange)
|
||||
throws AddressTranslationException {
|
||||
return DiffUtility.getCompatibleAddressRange(sourceAddressRange, destinationProgram);
|
||||
AddressSet destinationRange =
|
||||
DiffUtility.getCompatibleAddressSet(sourceAddressRange, destinationProgram, true);
|
||||
if (destinationRange != null && !destinationRange.isEmpty()) {
|
||||
return destinationRange.getFirstRange();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,6 +15,10 @@
|
|||
*/
|
||||
package ghidra.program.util;
|
||||
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.apache.commons.lang3.Range;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.Register;
|
||||
import ghidra.program.model.listing.*;
|
||||
|
@ -55,80 +59,55 @@ public class DiffUtility extends SimpleDiffUtility {
|
|||
AddressRangeIterator rangeIter = set.getAddressRanges();
|
||||
while (rangeIter.hasNext()) {
|
||||
AddressRange range = rangeIter.next();
|
||||
AddressRange compatibleAddressRange = getCompatibleAddressRange(range, otherProgram);
|
||||
if (compatibleAddressRange != null) {
|
||||
otherSet.add(compatibleAddressRange);
|
||||
AddressSet compatibleSet = getCompatibleAddressSet(range, otherProgram, false);
|
||||
if (compatibleSet != null) {
|
||||
otherSet.add(compatibleSet);
|
||||
}
|
||||
}
|
||||
return otherSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce an address-set from one program to the set of addresses that are incompatible with
|
||||
* the specified otherProgram.
|
||||
* @param set address-set corresponding to one program
|
||||
* @param otherProgram the addresses are incompatible with this other program.
|
||||
* @return incompatible address-set
|
||||
*/
|
||||
public static AddressSet getNonCompatibleAddressSet(AddressSetView set, Program otherProgram) {
|
||||
AddressSet nonCompatibleSet = new AddressSet();
|
||||
AddressRangeIterator rangeIter = set.getAddressRanges();
|
||||
while (rangeIter.hasNext()) {
|
||||
AddressRange range = rangeIter.next();
|
||||
AddressRange compatibleAddressRange = getCompatibleAddressRange(range, otherProgram);
|
||||
if (compatibleAddressRange == null) {
|
||||
nonCompatibleSet.add(range);
|
||||
}
|
||||
}
|
||||
return nonCompatibleSet;
|
||||
private static final Comparator<Long> unsignedLongComparator = new Comparator<>() {
|
||||
|
||||
@Override
|
||||
public int compare(Long o1, Long o2) {
|
||||
return Long.compareUnsigned(o1, o2);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert an address range from one program to a compatible address range in the
|
||||
* Convert an address range from one program to a compatible address set in the
|
||||
* specified otherProgram. Only memory addresses will be considered.
|
||||
* If the entire range cannot be converted then null is returned.
|
||||
* If none of the range can be converted then null is returned.
|
||||
* @param range address range to convert
|
||||
* @param otherProgram target program which corresponds to the returned address range.
|
||||
* @return translated address range or null if a compatible range could not be
|
||||
* determined in the other program.
|
||||
* @param exactMatchOnly if true and a one-to-one address mapping cannot be identified null
|
||||
* will be returned, otherwise a partial set may be returned or null if no valid translation
|
||||
* was found.
|
||||
* @return compatible address set or null
|
||||
*/
|
||||
public static AddressRange getCompatibleAddressRange(AddressRange range, Program otherProgram) {
|
||||
Address nextMin = range.getMinAddress();
|
||||
Address nextMax = range.getMaxAddress();
|
||||
Address newMinAddress = translateMemoryAddress(nextMin, otherProgram, false);
|
||||
Address newMaxAddress = translateMemoryAddress(nextMax, otherProgram, true);
|
||||
try {
|
||||
// while (newMinAddress == null) {
|
||||
// nextMin = nextMin.add(1L);
|
||||
// int compareMinToMax = nextMin.compareTo(nextMax);
|
||||
// if (compareMinToMax > 0) {
|
||||
// break;
|
||||
// }
|
||||
// newMinAddress = translateMemoryAddress(nextMin, otherProgram, true);
|
||||
// if (compareMinToMax == 0) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
while (newMaxAddress == null && nextMin != null) {
|
||||
nextMax = nextMax.subtract(1L);
|
||||
int compareMaxToMin = nextMax.compareTo(nextMin);
|
||||
if (compareMaxToMin < 0) {
|
||||
break;
|
||||
}
|
||||
newMaxAddress = translateMemoryAddress(nextMax, otherProgram, true);
|
||||
if (compareMaxToMin == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
// Won't be able to add 1 at end of block or subtract 1 at start of block.
|
||||
}
|
||||
if (newMinAddress == null || newMaxAddress == null ||
|
||||
newMinAddress.getOffset() > newMaxAddress.getOffset()) {
|
||||
public static AddressSet getCompatibleAddressSet(AddressRange range, Program otherProgram,
|
||||
boolean exactMatchOnly) {
|
||||
AddressSpace addrSpace = range.getMinAddress().getAddressSpace();
|
||||
AddressSpace otherSpace = getCompatibleAddressSpace(addrSpace, otherProgram);
|
||||
if (otherSpace == null) {
|
||||
return null;
|
||||
}
|
||||
return new AddressRangeImpl(newMinAddress, newMaxAddress);
|
||||
Range<Long> r = Range.between(range.getMinAddress().getOffset(),
|
||||
range.getMaxAddress().getOffset(), unsignedLongComparator);
|
||||
Range<Long> otherSpaceRange = Range.between(otherSpace.getMinAddress().getOffset(),
|
||||
otherSpace.getMaxAddress().getOffset(), unsignedLongComparator);
|
||||
if (!r.isOverlappedBy(otherSpaceRange)) {
|
||||
return null;
|
||||
}
|
||||
r = r.intersectionWith(otherSpaceRange);
|
||||
Address min = otherSpace.getAddressInThisSpaceOnly(r.getMinimum());
|
||||
Address max = otherSpace.getAddressInThisSpaceOnly(r.getMaximum());
|
||||
AddressSet set = new AddressSet(min, max);
|
||||
if (exactMatchOnly && set.getNumAddresses() != range.getLength()) {
|
||||
return null;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -200,64 +179,6 @@ public class DiffUtility extends SimpleDiffUtility {
|
|||
.createNameSpace(otherParentNamespace, namespace.getName(), source);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Given a symbol for a specified program, get the corresponding symbol from the
|
||||
// * specified otherProgram.
|
||||
// * @param program program which contains the specified symbol instance
|
||||
// * @param p2Symbol symbol to look for
|
||||
// * @param otherProgram other program
|
||||
// * @return corresponding symbol for otherProgram or null if no such symbol exists.
|
||||
// */
|
||||
// public static Symbol getSymbol(AddressTranslator p2ToP1Translator, Symbol p2Symbol) {
|
||||
//
|
||||
// if (p2Symbol == null) {
|
||||
// return null;
|
||||
// }
|
||||
// Program otherProgram = p2ToP1Translator.getDestinationProgram();
|
||||
// SymbolType st = p2Symbol.getSymbolType();
|
||||
// if (st == SymbolType.GLOBAL) {
|
||||
// return otherProgram.getGlobalNamespace().getSymbol();
|
||||
// }
|
||||
// if (st == SymbolType.FUNCTION) {
|
||||
// Function func = (Function) p2Symbol.getObject();
|
||||
// Address p1Entry = p2ToP1Translator.getAddress(func.getEntryPoint());
|
||||
// if (p1Entry == null) {
|
||||
// return null;
|
||||
// }
|
||||
// func = otherProgram.getFunctionManager().getFunctionAt(p1Entry);
|
||||
// return func != null ? func.getSymbol() : null;
|
||||
// }
|
||||
//
|
||||
// SymbolTable otherSymTable = otherProgram.getSymbolTable();
|
||||
// Address addr2 = p2Symbol.getAddress();
|
||||
// if (addr2.isVariableAddress()) {
|
||||
// Variable var2 = (Variable) p2Symbol.getObject();
|
||||
// Symbol otherFuncSym = getSymbol(p2ToP1Translator, p2Symbol.getParentSymbol());
|
||||
// Address storeAddr = p2ToP1Translator.getAddress(var2.getStorageAddress());
|
||||
// return getVariableSymbol(otherSymTable, var2, otherFuncSym, storeAddr);
|
||||
// }
|
||||
//
|
||||
// Symbol parent1 = getSymbol(p2ToP1Translator, p2Symbol.getParentSymbol());
|
||||
// if (parent1 == null) {
|
||||
// return null;
|
||||
// }
|
||||
// Namespace namespace = (Namespace)parent1.getObject();
|
||||
// String name2 = p2Symbol.getName();
|
||||
//
|
||||
// AddressSpace addrSpace = addr2.getAddressSpace();
|
||||
// if (addrSpace.getType() == AddressSpace.TYPE_NONE || addr2.isExternalAddress()) {
|
||||
// Symbol s = otherSymTable.getSymbol(name2, namespace);
|
||||
// return (s != null && st == s.getSymbolType()) ? s : null;
|
||||
// }
|
||||
//
|
||||
// if (addr2.isMemoryAddress()) {
|
||||
// Symbol s = otherSymTable.getSymbol(name2, addr2, namespace);
|
||||
// return (s != null && st == s.getSymbolType()) ? s : null;
|
||||
// }
|
||||
//
|
||||
// return null;
|
||||
// }
|
||||
|
||||
/**
|
||||
* Determine if the specified variables have overlapping storage.
|
||||
* Variable storage check includes dynamically mapped storage for parameters. This method
|
||||
|
@ -341,10 +262,10 @@ public class DiffUtility extends SimpleDiffUtility {
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param p2ToP1Translator
|
||||
* @param p2Ref
|
||||
* @return
|
||||
* Translate reference from program p2 to target program p1
|
||||
* @param p2ToP1Translator program address translater
|
||||
* @param p2Ref original reference to be copied
|
||||
* @return translated reference or null
|
||||
*/
|
||||
public static Reference getReference(AddressTranslator p2ToP1Translator, Reference p2Ref) {
|
||||
Program program = p2ToP1Translator.getDestinationProgram();
|
||||
|
@ -374,7 +295,10 @@ public class DiffUtility extends SimpleDiffUtility {
|
|||
* @param extLoc existing external location to be copied
|
||||
* @param otherProgram target program
|
||||
* @return new external location
|
||||
* @throws InvalidInputException
|
||||
* @throws InvalidInputException if {@code libraryName} is invalid or null, or an invalid
|
||||
* {@code extlabel} is specified. Names with spaces or the empty string are not permitted.
|
||||
* Neither {@code extLabel} nor {@code extAddr} was specified properly.
|
||||
* @throws DuplicateNameException if another non-Library namespace has the same name
|
||||
*/
|
||||
public static ExternalLocation createExtLocation(Program program, ExternalLocation extLoc,
|
||||
Program otherProgram) throws InvalidInputException, DuplicateNameException {
|
||||
|
|
|
@ -644,8 +644,7 @@ public class ProgramDiff {
|
|||
monitorMsg = "Checking Repeatable Comment Differences";
|
||||
monitor.setMessage(monitorMsg);
|
||||
as = getCommentDiffs(CodeUnit.REPEATABLE_COMMENT, addrs,
|
||||
new CommentTypeComparator(CodeUnit.REPEATABLE_COMMENT),
|
||||
monitor);
|
||||
new CommentTypeComparator(CodeUnit.REPEATABLE_COMMENT), monitor);
|
||||
break;
|
||||
case ProgramDiffFilter.PRE_COMMENT_DIFFS:
|
||||
monitorMsg = "Checking Pre-Comment Differences";
|
||||
|
@ -928,8 +927,7 @@ public class ProgramDiff {
|
|||
monitorMsg = "Checking Repeatable Comment Differences";
|
||||
monitor.setMessage(monitorMsg);
|
||||
as = getCommentDiffs(CodeUnit.REPEATABLE_COMMENT, checkAddressSet,
|
||||
new CommentTypeComparator(CodeUnit.REPEATABLE_COMMENT),
|
||||
monitor);
|
||||
new CommentTypeComparator(CodeUnit.REPEATABLE_COMMENT), monitor);
|
||||
break;
|
||||
case ProgramDiffFilter.PRE_COMMENT_DIFFS:
|
||||
monitorMsg = "Checking Pre-Comment Differences";
|
||||
|
@ -1417,17 +1415,16 @@ public class ProgramDiff {
|
|||
*/
|
||||
private AddressSet getLabelDifferences(AddressSetView addressSet, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
SymbolIterator iter1;
|
||||
SymbolIterator iter2;
|
||||
|
||||
if (addressSet == null) {
|
||||
iter1 = program1.getSymbolTable().getPrimarySymbolIterator(true);
|
||||
iter2 = program2.getSymbolTable().getPrimarySymbolIterator(true);
|
||||
}
|
||||
else {
|
||||
iter1 = program1.getSymbolTable().getPrimarySymbolIterator(addressSet, true);
|
||||
AddressSet addressSet2 = DiffUtility.getCompatibleAddressSet(addressSet, program2);
|
||||
iter2 = program2.getSymbolTable().getPrimarySymbolIterator(addressSet2, true);
|
||||
addressSet = program1.getMemory();
|
||||
}
|
||||
|
||||
SymbolIterator iter1 = program1.getSymbolTable().getPrimarySymbolIterator(addressSet, true);
|
||||
AddressSetView addressSet2 = DiffUtility.getCompatibleAddressSet(addressSet, program2);
|
||||
SymbolIterator iter2 =
|
||||
program2.getSymbolTable().getPrimarySymbolIterator(addressSet2, true);
|
||||
|
||||
SymbolComparator c = new SymbolComparator();
|
||||
return c.getObjectDiffs(iter1, iter2, monitor);
|
||||
}
|
||||
|
@ -1534,17 +1531,15 @@ public class ProgramDiff {
|
|||
*/
|
||||
private AddressSet getFunctionDifferences(AddressSetView addressSet, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
FunctionIterator iter1;
|
||||
FunctionIterator iter2;
|
||||
|
||||
if (addressSet == null) {
|
||||
iter1 = program1.getListing().getFunctions(true);
|
||||
iter2 = program2.getListing().getFunctions(true);
|
||||
}
|
||||
else {
|
||||
iter1 = program1.getListing().getFunctions(addressSet, true);
|
||||
AddressSet addressSet2 = DiffUtility.getCompatibleAddressSet(addressSet, program2);
|
||||
iter2 = program2.getListing().getFunctions(addressSet2, true);
|
||||
addressSet = program1.getMemory();
|
||||
}
|
||||
|
||||
FunctionIterator iter1 = program1.getListing().getFunctions(addressSet, true);
|
||||
AddressSetView addressSet2 = DiffUtility.getCompatibleAddressSet(addressSet, program2);
|
||||
FunctionIterator iter2 = program2.getListing().getFunctions(addressSet2, true);
|
||||
|
||||
FunctionComparator c = new FunctionComparator();
|
||||
return c.getObjectDiffs(iter1, iter2, monitor);
|
||||
}
|
||||
|
@ -1588,8 +1583,7 @@ public class ProgramDiff {
|
|||
* @see ghidra.program.model.listing.CodeUnit
|
||||
*/
|
||||
private AddressSet getCuiDiffs(String cuiType, AddressSetView addressSet,
|
||||
CodeUnitComparator<CodeUnit> c,
|
||||
TaskMonitor monitor) throws CancelledException {
|
||||
CodeUnitComparator<CodeUnit> c, TaskMonitor monitor) throws CancelledException {
|
||||
CodeUnitIterator iter1 = listing1.getCodeUnitIterator(cuiType, addressSet, true);
|
||||
AddressSet addressSet2 = DiffUtility.getCompatibleAddressSet(addressSet, program2);
|
||||
CodeUnitIterator iter2 = listing2.getCodeUnitIterator(cuiType, addressSet2, true);
|
||||
|
@ -2682,8 +2676,9 @@ public class ProgramDiff {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
Symbol p1Symbol = p2ToP1Translator.getDestinationProgram().getSymbolTable().getSymbol(
|
||||
p1Ref.getSymbolID());
|
||||
Symbol p1Symbol = p2ToP1Translator.getDestinationProgram()
|
||||
.getSymbolTable()
|
||||
.getSymbol(p1Ref.getSymbolID());
|
||||
Symbol p2Symbol =
|
||||
p2ToP1Translator.getSourceProgram().getSymbolTable().getSymbol(p2Ref.getSymbolID());
|
||||
if (!ProgramDiff.equivalentSymbols(p2ToP1Translator, p1Symbol, p2Symbol)) {
|
||||
|
|
|
@ -152,7 +152,7 @@ public class ProgramMemoryUtil {
|
|||
throws MemoryAccessException {
|
||||
|
||||
// TODO: Addresses from one program cannot be used with another program (e.g., overlays)
|
||||
// TODO: Should be using AddressTranslator
|
||||
// TODO: Should be using AddressTranslator (see DiffUtility.getCompatibleAddressRange)
|
||||
// TODO: Method relies too heavily on caller limiting range to valid initialized memory in both programs
|
||||
|
||||
// Copy the bytes for this range
|
||||
|
@ -777,7 +777,8 @@ public class ProgramMemoryUtil {
|
|||
* @param monitor a task monitor to allow
|
||||
* @throws CancelledException if the user cancels
|
||||
*/
|
||||
public static void locateString(String searchString, TerminatingConsumer<Address> foundLocationConsumer, Program program,
|
||||
public static void locateString(String searchString,
|
||||
TerminatingConsumer<Address> foundLocationConsumer, Program program,
|
||||
List<MemoryBlock> blocks, AddressSetView set, TaskMonitor monitor)
|
||||
throws CancelledException {
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import java.util.List;
|
|||
import org.junit.After;
|
||||
|
||||
import docking.widgets.fieldpanel.*;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import ghidra.app.plugin.core.codebrowser.CodeBrowserPlugin;
|
||||
import ghidra.app.util.viewer.field.ListingField;
|
||||
import ghidra.app.util.viewer.listingpanel.ListingPanel;
|
||||
|
@ -246,8 +247,9 @@ public abstract class AbstractProgramBasedTest extends AbstractGhidraHeadedInteg
|
|||
|
||||
int instanceNum = 1;
|
||||
for (int i = 0; i < layout.getNumFields(); i++) {
|
||||
ListingField bf = (ListingField) layout.getField(i);
|
||||
if (bf.getFieldFactory().getFieldName().equals(fieldName)) {
|
||||
Field f = layout.getField(i);
|
||||
if ((f instanceof ListingField bf) &&
|
||||
bf.getFieldFactory().getFieldName().equals(fieldName)) {
|
||||
if (instanceNum++ == occurrence) {
|
||||
return bf;
|
||||
}
|
||||
|
|
|
@ -113,7 +113,8 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
|||
table.addRowSelectionInterval(0, 0);
|
||||
Set<DockingActionIf> actions = getActionsByOwner(tool, plugin.getName());
|
||||
for (DockingActionIf action : actions) {
|
||||
if (action.getName().equals("Merge Blocks") || action.getName().equals("Local Menu")) {
|
||||
if (action.getName().equals("Merge Blocks") || action.getName().equals("Local Menu") ||
|
||||
action.getName().equals("Rename Overlay Space")) {
|
||||
assertFalse(action.isEnabled());
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -19,6 +19,7 @@ import static org.junit.Assert.*;
|
|||
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.TableModel;
|
||||
|
@ -207,7 +208,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE));
|
||||
|
@ -281,7 +282,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE));
|
||||
|
@ -544,7 +545,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("Default", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.SOURCE));
|
||||
|
@ -628,15 +629,15 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
MemoryBlock[] blocks = program.getMemory().getBlocks();
|
||||
int row = blocks.length - 1;
|
||||
assertEquals(".test", model.getValueAt(row, MemoryMapModel.NAME));
|
||||
assertEquals("00000000", model.getValueAt(row, MemoryMapModel.START));
|
||||
assertEquals(".test::00000000", model.getValueAt(row, MemoryMapModel.START));
|
||||
assertEquals(".test::00000000", block.getStart().toString());
|
||||
assertEquals("000000ff", model.getValueAt(row, MemoryMapModel.END));
|
||||
assertEquals(".test::000000ff", model.getValueAt(row, MemoryMapModel.END));
|
||||
assertEquals(".test::000000ff", block.getEnd().toString());
|
||||
assertEquals("0x100", model.getValueAt(row, MemoryMapModel.LENGTH));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.OVERLAY));
|
||||
assertEquals("ram", model.getValueAt(row, MemoryMapModel.OVERLAY));
|
||||
assertEquals(MemoryBlockType.DEFAULT.toString(),
|
||||
model.getValueAt(row, MemoryMapModel.BLOCK_TYPE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.INIT));
|
||||
|
@ -707,15 +708,15 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
MemoryBlock[] blocks = program.getMemory().getBlocks();
|
||||
int row = blocks.length - 1;
|
||||
assertEquals(".test", model.getValueAt(row, MemoryMapModel.NAME));
|
||||
assertEquals("00000000", model.getValueAt(row, MemoryMapModel.START));
|
||||
assertEquals(".test::00000000", model.getValueAt(row, MemoryMapModel.START));
|
||||
assertEquals(".test::00000000", block.getStart().toString());
|
||||
assertEquals("000000ff", model.getValueAt(row, MemoryMapModel.END));
|
||||
assertEquals(".test::000000ff", model.getValueAt(row, MemoryMapModel.END));
|
||||
assertEquals(".test::000000ff", block.getEnd().toString());
|
||||
assertEquals("0x100", model.getValueAt(row, MemoryMapModel.LENGTH));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(row, MemoryMapModel.OVERLAY));
|
||||
assertEquals("ram", model.getValueAt(row, MemoryMapModel.OVERLAY));
|
||||
assertEquals(MemoryBlockType.DEFAULT.toString(),
|
||||
model.getValueAt(row, MemoryMapModel.BLOCK_TYPE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(row, MemoryMapModel.INIT));
|
||||
|
@ -792,7 +793,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("Bit Mapped", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
|
||||
assertNull(model.getValueAt(0, MemoryMapModel.INIT));
|
||||
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE));
|
||||
|
@ -868,7 +869,7 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.READ));
|
||||
assertEquals(Boolean.TRUE, model.getValueAt(0, MemoryMapModel.WRITE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.EXECUTE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("", model.getValueAt(0, MemoryMapModel.OVERLAY));
|
||||
assertEquals("Byte Mapped", model.getValueAt(0, MemoryMapModel.BLOCK_TYPE));
|
||||
assertEquals(Boolean.FALSE, model.getValueAt(0, MemoryMapModel.INIT));
|
||||
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.SOURCE));
|
||||
|
@ -945,8 +946,8 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
public void testMoveBlockNotAllowed() throws Exception {
|
||||
// create an overlay block
|
||||
tx(program, () -> {
|
||||
memory.createInitializedBlock(".overlay", getAddr(0), 0x100, (byte) 0xa,
|
||||
TaskMonitor.DUMMY, true);
|
||||
memory.createInitializedBlock("other.overlay", AddressSpace.OTHER_SPACE.getAddress(0),
|
||||
0x100, (byte) 0xa, TaskMonitor.DUMMY, true);
|
||||
});
|
||||
|
||||
int row = table.getModel().getRowCount() - 1;
|
||||
|
@ -956,18 +957,45 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
performAction(action, false);
|
||||
OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d);
|
||||
assertEquals("Move Overlay Block Not Allowed", d.getTitle());
|
||||
assertEquals("Moving OTHER Overlay Block Not Allowed", d.getTitle());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveBlock() throws Exception {
|
||||
doTextMoveBlock(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMoveOverlayBlock() throws Exception {
|
||||
doTextMoveBlock(true);
|
||||
}
|
||||
|
||||
private void doTextMoveBlock(boolean overlay) throws Exception {
|
||||
// add a block at 0, length 0x100
|
||||
tx(program, () -> {
|
||||
memory.createInitializedBlock(".test", getAddr(0), 0x100, (byte) 0, TaskMonitor.DUMMY,
|
||||
false);
|
||||
overlay);
|
||||
});
|
||||
|
||||
table.setRowSelectionInterval(0, 0);
|
||||
MemoryBlock block = program.getMemory().getBlock(".test");
|
||||
assertNotNull(block);
|
||||
assertEquals(overlay, block.isOverlay());
|
||||
Address startAddr = block.getStart();
|
||||
Address endAddr = block.getEnd();
|
||||
|
||||
// Select correct row
|
||||
AtomicInteger row = new AtomicInteger();
|
||||
runSwing(() -> {
|
||||
for (int i = 0; i < table.getRowCount(); i++) {
|
||||
if (".test".equals(table.getModel().getValueAt(i, 0))) {
|
||||
table.setRowSelectionInterval(i, i);
|
||||
row.set(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
waitForSwing();
|
||||
|
||||
DockingActionIf action = getAction(plugin, "Move Block");
|
||||
assertTrue(action.isEnabled());
|
||||
|
@ -986,11 +1014,11 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
|
||||
JLabel origStartLabel = (JLabel) findComponentByName(d.getComponent(), "origStart");
|
||||
assertNotNull(origStartLabel);
|
||||
assertEquals(getAddr(0).toString(), origStartLabel.getText());
|
||||
assertEquals(startAddr.toString(), origStartLabel.getText());
|
||||
|
||||
JLabel origEndLabel = (JLabel) findComponentByName(d.getComponent(), "origEnd");
|
||||
assertNotNull(origEndLabel);
|
||||
assertEquals(getAddr(0xffL).toString(), origEndLabel.getText());
|
||||
assertEquals(endAddr.toString(), origEndLabel.getText());
|
||||
|
||||
JLabel lengthLabel = (JLabel) findComponentByName(d.getComponent(), "length");
|
||||
assertNotNull(lengthLabel);
|
||||
|
@ -999,19 +1027,21 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
AddressInput startField = (AddressInput) findComponentByName(d.getComponent(), "newStart");
|
||||
|
||||
assertNotNull(startField);
|
||||
assertEquals(getAddr(0), startField.getAddress());
|
||||
assertEquals(startAddr, startField.getAddress());
|
||||
|
||||
AddressInput endField = (AddressInput) findComponentByName(d.getComponent(), "newEnd");
|
||||
assertNotNull(endField);
|
||||
assertEquals(getAddr(0xffL), endField.getAddress());
|
||||
assertEquals(endAddr, endField.getAddress());
|
||||
|
||||
JButton okButton = findButton(d.getComponent(), "OK");
|
||||
assertNotNull(okButton);
|
||||
assertFalse(okButton.isEnabled());
|
||||
|
||||
// move the block to 0x300
|
||||
runSwing(() -> startField.setValue(getAddr(0x0300).toString()));
|
||||
assertEquals(getAddr(0x3ff), endField.getAddress());
|
||||
Address newStart = startAddr.getAddressSpace().getAddressInThisSpaceOnly(0x300);
|
||||
Address newEnd = startAddr.getAddressSpace().getAddressInThisSpaceOnly(0x3ff);
|
||||
runSwing(() -> startField.setValue(newStart));
|
||||
assertEquals(newEnd, endField.getAddress());
|
||||
assertTrue(okButton.isEnabled());
|
||||
|
||||
runSwing(() -> okButton.getActionListeners()[0].actionPerformed(null));
|
||||
|
@ -1024,9 +1054,9 @@ public class MemoryMapProvider2Test extends AbstractGhidraHeadedIntegrationTest
|
|||
|
||||
program.flushEvents();
|
||||
waitForSwing();
|
||||
assertEquals(".test", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(getAddr(0x300).toString(), model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals(getAddr(0x3ff).toString(), model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals(".test", model.getValueAt(row.get(), MemoryMapModel.NAME));
|
||||
assertEquals(newStart.toString(), model.getValueAt(row.get(), MemoryMapModel.START));
|
||||
assertEquals(newEnd.toString(), model.getValueAt(row.get(), MemoryMapModel.END));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -35,6 +35,7 @@ import ghidra.app.util.AddressInput;
|
|||
import ghidra.framework.plugintool.PluginTool;
|
||||
import ghidra.program.database.ProgramBuilder;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
|
@ -436,8 +437,8 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
public void testSplitNotAllowed() throws Exception {
|
||||
// create an overlay block
|
||||
tx(program, () -> {
|
||||
memory.createInitializedBlock(".overlay", getAddr(0), 0x100, (byte) 0xa,
|
||||
TaskMonitor.DUMMY, true);
|
||||
memory.createInitializedBlock(".overlay", AddressSpace.OTHER_SPACE.getAddress(0), 0x100,
|
||||
(byte) 0xa, TaskMonitor.DUMMY, true);
|
||||
});
|
||||
|
||||
int row = table.getModel().getRowCount() - 1;
|
||||
|
@ -446,35 +447,35 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
performAction(action, false);
|
||||
OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d);
|
||||
assertEquals("Split Overlay Block Not Allowed", d.getTitle());
|
||||
assertEquals("Split OTHER Overlay Block Not Allowed", d.getTitle());
|
||||
close(d);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExpandBlockNotAllowed() throws Exception {
|
||||
// create an overlay block
|
||||
tx(program, () -> {
|
||||
memory.createInitializedBlock(".overlay", getAddr(0), 0x100, (byte) 0xa,
|
||||
TaskMonitor.DUMMY, true);
|
||||
});
|
||||
|
||||
int row = table.getModel().getRowCount() - 1;
|
||||
table.setRowSelectionInterval(row, row);
|
||||
DockingActionIf action = getAction(plugin, "Expand Block Up");
|
||||
performAction(action, false);
|
||||
OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d);
|
||||
assertEquals("Expand Overlay Block Not Allowed", d.getTitle());
|
||||
close(d);
|
||||
|
||||
action = getAction(plugin, "Expand Block Down");
|
||||
performAction(action, false);
|
||||
|
||||
OptionDialog d2 = waitForDialogComponent(OptionDialog.class);
|
||||
assertNotNull(d2);
|
||||
assertEquals("Expand Overlay Block Not Allowed", d2.getTitle());
|
||||
runSwing(() -> d2.close());
|
||||
}
|
||||
// @Test
|
||||
// public void testExpandBlockNotAllowed() throws Exception {
|
||||
// // create an overlay block
|
||||
// tx(program, () -> {
|
||||
// memory.createInitializedBlock(".overlay", getAddr(0), 0x100, (byte) 0xa,
|
||||
// TaskMonitor.DUMMY, true);
|
||||
// });
|
||||
//
|
||||
// int row = table.getModel().getRowCount() - 1;
|
||||
// table.setRowSelectionInterval(row, row);
|
||||
// DockingActionIf action = getAction(plugin, "Expand Block Up");
|
||||
// performAction(action, false);
|
||||
// OptionDialog d = waitForDialogComponent(OptionDialog.class);
|
||||
// assertNotNull(d);
|
||||
// assertEquals("Expand Overlay Block Not Allowed", d.getTitle());
|
||||
// close(d);
|
||||
//
|
||||
// action = getAction(plugin, "Expand Block Down");
|
||||
// performAction(action, false);
|
||||
//
|
||||
// OptionDialog d2 = waitForDialogComponent(OptionDialog.class);
|
||||
// assertNotNull(d2);
|
||||
// assertEquals("Expand Overlay Block Not Allowed", d2.getTitle());
|
||||
// runSwing(() -> d2.close());
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testExpandBlockUpSetup() {
|
||||
|
@ -536,7 +537,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
runSwing(() -> okButton.getActionListeners()[0].actionPerformed(null));
|
||||
waitForSwing();
|
||||
|
||||
assertEquals(".text.exp", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(".text", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals("00002000", model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals("010075ff", model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals("0x1005600", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
@ -548,7 +549,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals("0x6600", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
||||
redo(program);
|
||||
assertEquals(".text.exp", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(".text", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals("00002000", model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals("010075ff", model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals("0x1005600", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
@ -606,7 +607,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
runSwing(() -> okButton.getActionListeners()[0].actionPerformed(null));
|
||||
waitForSwing();
|
||||
|
||||
assertEquals(".text.exp", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(".text", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals("01000000", model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals("010075ff", model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals("0x7600", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
@ -618,7 +619,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals("0x6600", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
||||
redo(program);
|
||||
assertEquals(".text.exp", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(".text", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals("01000000", model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals("010075ff", model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals("0x7600", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
@ -736,7 +737,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
runSwing(() -> okButton.getActionListeners()[0].actionPerformed(null));
|
||||
waitForSwing();
|
||||
|
||||
assertEquals(".text.exp", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(".text", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals("01007700", model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals("0x6701", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
@ -763,7 +764,7 @@ public class MemoryMapProvider3Test extends AbstractGhidraHeadedIntegrationTest
|
|||
runSwing(() -> okButton.getActionListeners()[0].actionPerformed(null));
|
||||
waitForSwing();
|
||||
|
||||
assertEquals(".text.exp", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals(".text", model.getValueAt(0, MemoryMapModel.NAME));
|
||||
assertEquals("01001000", model.getValueAt(0, MemoryMapModel.START));
|
||||
assertEquals("010076ff", model.getValueAt(0, MemoryMapModel.END));
|
||||
assertEquals("0x6700", model.getValueAt(0, MemoryMapModel.LENGTH));
|
||||
|
|
|
@ -130,7 +130,7 @@ public class OverlayAddressSpaceTest extends AbstractGhidraHeadedIntegrationTest
|
|||
space3 = factory.getAddressSpace(space3.getName());
|
||||
|
||||
OverlayAddressSpace space1Overlay =
|
||||
new OverlayAddressSpace("Overlay1", space1, 4, 0x20, 0x30);
|
||||
new SingleRangeOverlayAddressSpace("Overlay1", space1, 4, 0x20, 0x30, "Overlay1");
|
||||
|
||||
Address space1Address = space1.getAddress(0x20);
|
||||
Address space1OverlayAddress = space1Overlay.getAddress(0x22);
|
||||
|
@ -192,7 +192,7 @@ public class OverlayAddressSpaceTest extends AbstractGhidraHeadedIntegrationTest
|
|||
space1 = factory.getAddressSpace(space1.getName());
|
||||
|
||||
OverlayAddressSpace space1Overlay =
|
||||
new OverlayAddressSpace("Overlay1", space1, 4, 0x20, 0x30);
|
||||
new SingleRangeOverlayAddressSpace("Overlay1", space1, 4, 0x20, 0x30, "Overlay1");
|
||||
|
||||
assertEquals(0x25, space1Overlay.truncateOffset(0x25));
|
||||
assertEquals(0x40, space1Overlay.truncateOffset(0x40));
|
||||
|
@ -223,7 +223,7 @@ public class OverlayAddressSpaceTest extends AbstractGhidraHeadedIntegrationTest
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOverlayRename() throws Exception {
|
||||
public void testOverlayRenameAndDelete() throws Exception {
|
||||
|
||||
ProgramBuilder builder = new ProgramBuilder("Test", ProgramBuilder._TOY, this);
|
||||
program = builder.getProgram();
|
||||
|
@ -242,18 +242,42 @@ public class OverlayAddressSpaceTest extends AbstractGhidraHeadedIntegrationTest
|
|||
assertEquals("my_overlay_x", overlayBlock1.getStart().getAddressSpace().getName());
|
||||
assertEquals("my_overlay_x.1", overlayBlock2.getStart().getAddressSpace().getName());
|
||||
|
||||
overlayBlock1.setName("my new name");
|
||||
overlayBlock1.setName("my new name"); // does not rename overlay space
|
||||
assertEquals("my new name", overlayBlock1.getName());
|
||||
assertEquals("my_new_name", overlayBlock1.getStart().getAddressSpace().getName());
|
||||
assertNull(af.getAddressSpace("my_overlay_x"));
|
||||
assertNotNull(af.getAddressSpace("my_new_name"));
|
||||
assertEquals("my_overlay_x", overlayBlock1.getStart().getAddressSpace().getName());
|
||||
assertNotNull(af.getAddressSpace("my_overlay_x"));
|
||||
assertNull(af.getAddressSpace("my_new_name"));
|
||||
|
||||
overlayBlock2.setName("my new name");
|
||||
overlayBlock2.setName("my new name"); // does not rename overlay space
|
||||
assertEquals("my new name", overlayBlock2.getName());
|
||||
assertEquals("my_new_name.1", overlayBlock2.getStart().getAddressSpace().getName());
|
||||
assertNull(af.getAddressSpace("my_overlay_x.1"));
|
||||
assertNotNull(af.getAddressSpace("my_new_name.1"));
|
||||
assertEquals("my_overlay_x.1", overlayBlock2.getStart().getAddressSpace().getName());
|
||||
assertNotNull(af.getAddressSpace("my_overlay_x.1"));
|
||||
assertNull(af.getAddressSpace("my_new_name.1"));
|
||||
|
||||
overlayBlock2.setName("my overlay:x"); // restore non-duplicate block name
|
||||
|
||||
program.renameOverlaySpace("my_overlay_x", "my_overlay_x2");
|
||||
program.renameOverlaySpace("my_overlay_x.1", "my_overlay_x2.1");
|
||||
|
||||
// must reacquire block instances due to imposed memory reload/restore
|
||||
|
||||
overlayBlock1 = program.getMemory().getBlock("my new name");
|
||||
assertEquals("my_overlay_x2", overlayBlock1.getStart().getAddressSpace().getName());
|
||||
assertNull(af.getAddressSpace("my_overlay_x"));
|
||||
assertNotNull(af.getAddressSpace("my_overlay_x2"));
|
||||
|
||||
overlayBlock2 = program.getMemory().getBlock("my overlay:x");
|
||||
assertEquals("my_overlay_x2.1", overlayBlock2.getStart().getAddressSpace().getName());
|
||||
assertNull(af.getAddressSpace("my_overlay_x.1"));
|
||||
assertNotNull(af.getAddressSpace("my_overlay_x2.1"));
|
||||
|
||||
// Overlay Space removal will occur after block removal
|
||||
|
||||
assertFalse(
|
||||
program.removeOverlaySpace(overlayBlock1.getStart().getAddressSpace().getName()));
|
||||
assertNotNull(af.getAddressSpace("my_overlay_x2"));
|
||||
program.getMemory().removeBlock(overlayBlock1, TaskMonitor.DUMMY); // should remove space
|
||||
assertNull(af.getAddressSpace("my_overlay_x2"));
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
|
@ -270,8 +294,9 @@ public class OverlayAddressSpaceTest extends AbstractGhidraHeadedIntegrationTest
|
|||
int transactionID = program.startTransaction(testName.getMethodName());
|
||||
MemoryBlock overlayBlock1 = null;
|
||||
try {
|
||||
overlayBlock1 = program.getMemory().createInitializedBlock(".overlay1",
|
||||
af.getAddress("1000"), 0x100, (byte) 0x11, TaskMonitor.DUMMY, true);
|
||||
overlayBlock1 = program.getMemory()
|
||||
.createInitializedBlock(".overlay1", af.getAddress("1000"), 0x100, (byte) 0x11,
|
||||
TaskMonitor.DUMMY, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
|
@ -305,14 +330,15 @@ public class OverlayAddressSpaceTest extends AbstractGhidraHeadedIntegrationTest
|
|||
MemoryBlock overlayBlock3 = null;
|
||||
MemoryBlock overlayBlock4 = null;
|
||||
try {
|
||||
overlayBlock2 = program.getMemory().createInitializedBlock(".overlay2",
|
||||
af.getAddress("2000"), 0x200, (byte) 0x22, TaskMonitor.DUMMY, true);
|
||||
overlayBlock2 = program.getMemory()
|
||||
.createInitializedBlock(".overlay2", af.getAddress("2000"), 0x200, (byte) 0x22,
|
||||
TaskMonitor.DUMMY, true);
|
||||
overlayBlock3 = program.getMemory()
|
||||
.createInitializedBlock("my_overlay_x",
|
||||
af.getAddress("3000"), 0x300, (byte) 0x33, TaskMonitor.DUMMY, true);
|
||||
.createInitializedBlock("my_overlay_x", af.getAddress("3000"), 0x300,
|
||||
(byte) 0x33, TaskMonitor.DUMMY, true);
|
||||
overlayBlock4 = program.getMemory()
|
||||
.createInitializedBlock("my overlay:x",
|
||||
af.getAddress("4000"), 0x400, (byte) 0x44, TaskMonitor.DUMMY, true);
|
||||
.createInitializedBlock("my overlay:x", af.getAddress("4000"), 0x400,
|
||||
(byte) 0x44, TaskMonitor.DUMMY, true);
|
||||
}
|
||||
finally {
|
||||
program.endTransaction(transactionID, true);
|
||||
|
|
|
@ -48,8 +48,8 @@ public class ByteMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTe
|
|||
space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
transactionID = program.startTransaction("Test");
|
||||
|
||||
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0),
|
||||
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
block = memory.createInitializedBlock("BYTE_BLOCK", space.getAddress(0), bytes.length,
|
||||
(byte) 0, TaskMonitor.DUMMY, false);
|
||||
memory.setBytes(block.getStart(), bytes);
|
||||
}
|
||||
|
||||
|
@ -101,8 +101,7 @@ public class ByteMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTe
|
|||
}
|
||||
|
||||
MemoryBlock block2 = memory.createInitializedBlock("BYTE_BLOCK2", space.getAddress(0x100),
|
||||
bytes.length,
|
||||
(byte) 0, TaskMonitor.DUMMY, false);
|
||||
bytes.length, (byte) 0, TaskMonitor.DUMMY, false);
|
||||
|
||||
set.add(addr(0x100), addr(0x1FF));
|
||||
set.add(addr(0x1080), addr(0x10FF));
|
||||
|
@ -279,11 +278,15 @@ public class ByteMappedMemoryBlockTest extends AbstractGhidraHeadedIntegrationTe
|
|||
MemoryBlock byteMappedBlock = memory.createByteMappedBlock("test", addr(0x1000), addr(0x80),
|
||||
0x100, new ByteMappingScheme(2, 4), true);
|
||||
assertTrue(byteMappedBlock.isOverlay());
|
||||
AddressSpace testSpace = program.getAddressFactory().getAddressSpace("test");
|
||||
OverlayAddressSpace testSpace =
|
||||
(OverlayAddressSpace) program.getAddressFactory().getAddressSpace("test");
|
||||
assertNotNull(testSpace);
|
||||
assertEquals(space, testSpace.getPhysicalSpace());
|
||||
assertEquals(testSpace.getAddress(0x1000), testSpace.getMinAddress());
|
||||
assertEquals(testSpace.getAddress(0x10FF), testSpace.getMaxAddress());
|
||||
AddressSetView testSet = testSpace.getOverlayAddressSet();
|
||||
assertEquals(1, testSet.getNumAddressRanges());
|
||||
AddressRange r = testSet.getFirstRange();
|
||||
assertEquals(testSpace.getAddress(0x1000), r.getMinAddress());
|
||||
assertEquals(testSpace.getAddress(0x10FF), r.getMaxAddress());
|
||||
assertEquals(0x100, byteMappedBlock.getSize());
|
||||
assertEquals(testSpace.getAddress(0x1000), byteMappedBlock.getStart());
|
||||
assertEquals(testSpace.getAddress(0x10FF), byteMappedBlock.getEnd());
|
||||
|
|
|
@ -391,7 +391,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertTrue(executeSet.isEmpty() != true);
|
||||
Address start = block.getStart();
|
||||
Address end = block.getEnd();
|
||||
assertTrue(executeSet.contains(start,end));
|
||||
assertTrue(executeSet.contains(start, end));
|
||||
|
||||
// non-existent block
|
||||
block = mem.getBlock("NoExist");
|
||||
|
@ -408,10 +408,10 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
start = block.getStart();
|
||||
end = block.getEnd();
|
||||
// should be same block
|
||||
assertTrue(executeSet.contains(start,end));
|
||||
assertTrue(executeSet.contains(start, end));
|
||||
block.setExecute(false);
|
||||
executeSet = mem.getExecuteSet();
|
||||
assertTrue(executeSet.contains(start,end) == false);
|
||||
assertTrue(executeSet.contains(start, end) == false);
|
||||
|
||||
block2.setExecute(true);
|
||||
Address start2 = block2.getStart();
|
||||
|
@ -426,14 +426,14 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
|
||||
// should be execute set on block2, deleted, then undone
|
||||
executeSet = mem.getExecuteSet();
|
||||
assertTrue(executeSet.contains(start2,end2) == false);
|
||||
assertTrue(executeSet.contains(start2, end2) == false);
|
||||
|
||||
// undid set execute block should now be contained
|
||||
block = mem.getBlock("Test1");
|
||||
start = block.getStart();
|
||||
end = block.getEnd();
|
||||
executeSet = mem.getExecuteSet();
|
||||
assertTrue(executeSet.contains(start,end));
|
||||
assertTrue(executeSet.contains(start, end));
|
||||
|
||||
mem.split(block, addr(150));
|
||||
block = mem.getBlock("Test1");
|
||||
|
@ -1062,11 +1062,23 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
|||
(byte) 0xa, TaskMonitor.DUMMY, true);
|
||||
|
||||
try {
|
||||
mem.join(blockOne, blockTwo);
|
||||
mem.join(blockOne, blockTwo); // two different overlay spaces
|
||||
Assert.fail("Join should have caused and Exception!");
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
catch (MemoryBlockException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
AddressSpace overlaySpace = blockOne.getStart().getAddressSpace();
|
||||
|
||||
MemoryBlock blockThree =
|
||||
mem.createInitializedBlock(".overlay3", overlaySpace.getAddressInThisSpaceOnly(0x1000),
|
||||
0x100, (byte) 0xa, TaskMonitor.DUMMY, true);
|
||||
|
||||
MemoryBlock joinedBlock = mem.join(blockOne, blockThree); // same overlay space
|
||||
assertEquals(".overlay", joinedBlock.getName()); // use name of min block
|
||||
assertEquals(0x1100, joinedBlock.getSize());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -15,14 +15,14 @@
|
|||
*/
|
||||
package ghidra.program.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.listing.Function;
|
||||
import ghidra.program.model.listing.Program;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.ClassicSampleX86ProgramBuilder;
|
||||
import ghidra.test.AbstractGhidraHeadedIntegrationTest;
|
||||
import ghidra.test.ClassicSampleX86ProgramBuilder;
|
||||
import ghidra.util.exception.CancelledException;
|
||||
|
||||
public class AbstractProgramDiffTest extends AbstractGhidraHeadedIntegrationTest {
|
||||
|
@ -33,17 +33,34 @@ public class AbstractProgramDiffTest extends AbstractGhidraHeadedIntegrationTest
|
|||
protected Program p1;
|
||||
protected Program p2;
|
||||
|
||||
/**
|
||||
* Generate address in p1's default address space
|
||||
* @param offset address offset
|
||||
* @return address
|
||||
*/
|
||||
protected Address addr(int offset) {
|
||||
AddressSpace space = p1.getAddressFactory().getDefaultAddressSpace();
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
protected Address addr(Program program, int offset) {
|
||||
/**
|
||||
* Generate address in specified program's default address space
|
||||
* @param program target program
|
||||
* @param offset address offset
|
||||
* @return address
|
||||
*/
|
||||
protected static Address addr(Program program, int offset) {
|
||||
AddressSpace space = program.getAddressFactory().getDefaultAddressSpace();
|
||||
return space.getAddress(offset);
|
||||
}
|
||||
|
||||
protected Address addr(Program program, String addrString) {
|
||||
/**
|
||||
* Generate address from parsed string within specified program.
|
||||
* @param program target program
|
||||
* @param addrString address string (w/ optional space name) to be parsed
|
||||
* @return addressor null if parse fails
|
||||
*/
|
||||
protected static Address addr(Program program, String addrString) {
|
||||
return program.getAddressFactory().getAddress(addrString);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,8 +21,7 @@
|
|||
|
||||
package ghidra.program.util;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
|
@ -35,7 +34,6 @@ import ghidra.program.model.listing.*;
|
|||
import ghidra.program.model.mem.Memory;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* <CODE>ProgramDiffTest</CODE> tests the <CODE>ProgramDiff</CODE> class
|
||||
|
@ -710,7 +708,9 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
// P1 program
|
||||
try {
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Foo", addr(program, "0x01000000"), 0x200L,
|
||||
memory.createInitializedBlock("Foo1", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
memory.createInitializedBlock("Foo2", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -723,7 +723,9 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
// P2 program
|
||||
try {
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Foo", addr(program, "0x01000000"), 0x200L,
|
||||
memory.createInitializedBlock("Foo2", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
memory.createInitializedBlock("Foo1", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -742,14 +744,16 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testDiffOverlaysDiffNames() throws Exception {
|
||||
public void testDiffOverlaysDiffRegion() throws Exception {
|
||||
mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
try {
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Foo", addr(program, "0x01000000"), 0x200L,
|
||||
memory.createInitializedBlock("Foo1", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
memory.createInitializedBlock("Foo2", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -762,7 +766,9 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
// P2 program
|
||||
try {
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Bar", addr(program, "0x01000000"), 0x200L,
|
||||
memory.createInitializedBlock("Foo2", addr(program, "0x02000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
memory.createInitializedBlock("Foo1", addr(program, "0x02000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
@ -776,7 +782,57 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
|
||||
programDiff = new ProgramDiff(p1, p2);
|
||||
AddressSet as = new AddressSet();
|
||||
as.addRange(addr(p1, "Foo:0x01000000"), addr(p1, "Foo:0x010001ff"));
|
||||
// All overlay blocks in common Foo overlay space is considered
|
||||
as.addRange(addr(p1, "Foo1:0x01000000"), addr(p1, "Foo1:0x010001ff"));
|
||||
as.addRange(addr(p1, "Foo1::02000000"), addr(p1, "Foo1::020001ff"));
|
||||
as.addRange(addr(p1, "Foo2:0x01000000"), addr(p1, "Foo2:0x010001ff"));
|
||||
as.addRange(addr(p1, "Foo2::02000000"), addr(p1, "Foo2::020001ff"));
|
||||
programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.ALL_DIFFS));
|
||||
assertEquals(as, programDiff.getDifferences(programDiff.getFilter(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffOverlaysDiffNames() throws Exception {
|
||||
mtf.initialize("NotepadMergeListingTest", new ProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
try {
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Foo1", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
memory.createInitializedBlock("Foo2", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
try {
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Bar1", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
memory.createInitializedBlock("Bar2", addr(program, "0x01000000"), 0x200L,
|
||||
(byte) 0x0, null, true);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
p1 = mtf.getResultProgram();
|
||||
p2 = mtf.getPrivateProgram();
|
||||
|
||||
programDiff = new ProgramDiff(p1, p2);
|
||||
AddressSet as = new AddressSet();
|
||||
// Only block regions in p1 are considered
|
||||
as.addRange(addr(p1, "Foo1:0x01000000"), addr(p1, "Foo1:0x010001ff"));
|
||||
as.addRange(addr(p1, "Foo2:0x01000000"), addr(p1, "Foo2:0x010001ff"));
|
||||
programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.ALL_DIFFS));
|
||||
assertEquals(as, programDiff.getDifferences(programDiff.getFilter(), null));
|
||||
}
|
||||
|
@ -794,8 +850,8 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
Namespace globalNamespace = program.getGlobalNamespace();
|
||||
st.createLabel(addr(program, "Foo:0x01000030"), "Sample0030",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000030"), "Sample0030", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
|
@ -812,8 +868,8 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
Namespace globalNamespace = program.getGlobalNamespace();
|
||||
st.createLabel(addr(program, "Foo:0x01000050"), "Other0050",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000050"), "Other0050", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
|
@ -839,18 +895,19 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
try {
|
||||
// Overlay Foo 0x01000000 - 0x0100017f
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Foo", addr(program, "0x01000000"), 0x180L,
|
||||
(byte) 0x0, null, true);
|
||||
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
Namespace globalNamespace = program.getGlobalNamespace();
|
||||
st.createLabel(addr(program, "Foo:0x01000030"), "Sample0030",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000079"), "Sample0079",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x0100017f"), "Sample017f",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000030"), "Sample0030", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000179"), "Sample0179", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x0100017f"), "Sample017f", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
|
@ -861,18 +918,19 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
try {
|
||||
// Overlapping overlay with the same name 0x01000080 - 0x0100017f
|
||||
Memory memory = program.getMemory();
|
||||
memory.createInitializedBlock("Foo", addr(program, "0x01000080"), 0x180L,
|
||||
(byte) 0x0, null, true);
|
||||
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
Namespace globalNamespace = program.getGlobalNamespace();
|
||||
st.createLabel(addr(program, "Foo:0x01000080"), "Other0080",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000180"), "Other0180",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000200"), "Other0200",
|
||||
globalNamespace, SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000080"), "Other0080", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000162"), "Other0162", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000200"), "Other0200", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
|
@ -883,13 +941,17 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
p1 = mtf.getResultProgram();
|
||||
p2 = mtf.getPrivateProgram();
|
||||
|
||||
// No addresses should be considered to be in common for the overlays.
|
||||
// All overlay blocks in common Foo overlay space is considered
|
||||
programDiff = new ProgramDiff(p1, p2);
|
||||
AddressSet as = new AddressSet();
|
||||
as.addRange(addr(p1, "Foo:0x01000000"), addr(p1, "Foo:0x0100017f"));
|
||||
programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.ALL_DIFFS));
|
||||
AddressSetView diffs = programDiff.getDifferences(programDiff.getFilter(), null);
|
||||
assertEquals(as, diffs);
|
||||
|
||||
AddressSet expectedDiffAs = new AddressSet();
|
||||
expectedDiffAs.addRange(addr(p1, "Foo:0x01000000"), addr(p1, "Foo:0x01000080")); // not found in p2
|
||||
expectedDiffAs.add(addr(p1, "Foo:0x01000162")); // Other0162 not found in p1
|
||||
expectedDiffAs.add(addr(p1, "Foo:0x01000179")); // Sample0179 not found in p2
|
||||
expectedDiffAs.addRange(addr(p1, "Foo:0x0100017f"), addr(p1, "Foo:0x010001ff")); // not found in p1
|
||||
assertEquals(expectedDiffAs, diffs);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1084,61 +1146,6 @@ public class ProgramDiff2Test extends AbstractProgramDiffTest {
|
|||
assertEquals(as, programDiff.getDifferences(programDiff.getFilter(), null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffOverlayOrder() throws Exception {
|
||||
mtf.initialize("overlayCalc", new ProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
try {
|
||||
program.getMemory().createInitializedBlock("SomeOverlay",
|
||||
addr(program, "0x01001630"), 0x200, (byte) 0, TaskMonitor.DUMMY, true);
|
||||
program.getMemory().createInitializedBlock("OtherOverlay",
|
||||
addr(program, "0x01001630"), 0x300, (byte) 0, TaskMonitor.DUMMY, true);
|
||||
st.createLabel(addr(program, "SomeOverlay::01001630"), "OVL1630",
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "OtherOverlay::01001866"), "OVL1866",
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
try {
|
||||
program.getMemory().createInitializedBlock("OtherOverlay",
|
||||
addr(program, "0x01001630"), 0x200, (byte) 0, TaskMonitor.DUMMY, true);
|
||||
program.getMemory().createInitializedBlock("SomeOverlay",
|
||||
addr(program, "0x01001630"), 0x300, (byte) 0, TaskMonitor.DUMMY, true);
|
||||
st.createLabel(addr(program, "SomeOverlay::01001889"), "OVL1889",
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "OtherOverlay::01001646"), "OVL1646",
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
p1 = mtf.getResultProgram();
|
||||
p2 = mtf.getPrivateProgram();
|
||||
|
||||
programDiff = new ProgramDiff(p1, p2);
|
||||
AddressSet as = new AddressSet();
|
||||
as.addRange(addr(p1, "SomeOverlay::01001630"), addr(p1, "SomeOverlay::01001630"));
|
||||
// Diff won't detect SomeOverlay::01001889 because it isn't in p1.
|
||||
as.addRange(addr(p1, "OtherOverlay::01001646"), addr(p1, "OtherOverlay::01001646"));
|
||||
as.addRange(addr(p1, "OtherOverlay::01001866"), addr(p1, "OtherOverlay::01001866"));
|
||||
programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.SYMBOL_DIFFS));
|
||||
assertEquals(as, programDiff.getDifferences(programDiff.getFilter(), null));
|
||||
}
|
||||
|
||||
// private void printAddressSet(AddressSetView diffAs) {
|
||||
// System.out.println("=====");
|
||||
// for (AddressRange addressRange : diffAs) {
|
||||
|
|
|
@ -0,0 +1,325 @@
|
|||
/* ###
|
||||
* 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.
|
||||
*/
|
||||
/*
|
||||
* ProgramDiffTest.java
|
||||
*
|
||||
* Created on January 3, 2002, 9:55 AM
|
||||
*/
|
||||
|
||||
package ghidra.program.util;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.symbol.SourceType;
|
||||
import ghidra.program.model.symbol.SymbolTable;
|
||||
import ghidra.test.TestEnv;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* <CODE>ProgramDiffTest</CODE> tests the <CODE>ProgramDiff</CODE> class
|
||||
* to verify it correctly determines various types of program differences.
|
||||
* The setup for this test class loads two programs that were saved to the
|
||||
* testdata directory as XML. The tests will determine the differences between
|
||||
* these two programs.
|
||||
*/
|
||||
public class ProgramDiffMergeOverlayTest extends AbstractProgramDiffTest {
|
||||
|
||||
protected MergeTestFacilitator mtf;
|
||||
protected Program originalProgram;
|
||||
protected Program latestProgram;
|
||||
protected Program myProgram;
|
||||
protected Program resultProgram;
|
||||
|
||||
public ProgramDiffMergeOverlayTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
|
||||
fixupGUI();
|
||||
mtf = new MergeTestFacilitator();
|
||||
TestEnv testEnv = mtf.getTestEnvironment();
|
||||
testEnv.getTool().setToolName("TestTool");
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
try {
|
||||
if (resultProgram != null) {
|
||||
resultProgram.flushEvents();
|
||||
}
|
||||
waitForSwing();
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
mtf.dispose();// Get rid of the merge environment.
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffMergeOverlayFunctionTags() throws Exception {
|
||||
mtf.initialize("overlayCalc", new MultiOverlayProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
super.modifyLatest(program);
|
||||
try {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
Function f = listing.getFunctionAt(addr(program, "OtherOverlay:0x01001680"));
|
||||
f.addTag("Tag1");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
super.modifyPrivate(program);
|
||||
try {
|
||||
Listing listing = program.getListing();
|
||||
Function f = listing.getFunctionAt(addr(program, "SomeOverlay:0x01001780"));
|
||||
f.addTag("Tag2");
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
p1 = mtf.getResultProgram();
|
||||
p2 = mtf.getPrivateProgram();
|
||||
|
||||
AddressSet as = new AddressSet();
|
||||
as.addRange(addr(p1, "SomeOverlay::01001780"), addr(p1, "SomeOverlay::01001780"));
|
||||
as.addRange(addr(p1, "OtherOverlay::01001680"), addr(p1, "OtherOverlay::01001680"));
|
||||
|
||||
ProgramMergeManager programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY);
|
||||
programMerge.setDiffFilter(new ProgramDiffFilter(
|
||||
ProgramDiffFilter.FUNCTION_DIFFS | ProgramDiffFilter.FUNCTION_TAG_DIFFS));
|
||||
programMerge.setMergeFilter(
|
||||
new ProgramMergeFilter(ProgramMergeFilter.FUNCTIONS | ProgramMergeFilter.FUNCTION_TAGS,
|
||||
ProgramMergeFilter.REPLACE));
|
||||
assertEquals(as, programMerge.getFilteredDifferences());
|
||||
|
||||
p1.withTransaction("merge", () -> programMerge.merge(as, TaskMonitor.DUMMY));
|
||||
assertEquals(new AddressSet(), programMerge.getFilteredDifferences());
|
||||
|
||||
Listing listing1 = p1.getListing();
|
||||
Function f = listing1.getFunctionAt(addr(p1, "SomeOverlay:0x01001780"));
|
||||
assertNotNull(f);
|
||||
Set<FunctionTag> tags = f.getTags();
|
||||
assertEquals(1, tags.size());
|
||||
FunctionTag tag = tags.iterator().next();
|
||||
assertEquals("Tag2", tag.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffMergeOverlayFunctions() throws Exception {
|
||||
mtf.initialize("overlayCalc", new MultiOverlayProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
super.modifyLatest(program);
|
||||
try {
|
||||
Listing listing = program.getListing();
|
||||
Function f = listing.getFunctionAt(addr(program, "OtherOverlay:0x01001680"));
|
||||
f.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
super.modifyPrivate(program);
|
||||
try {
|
||||
Listing listing = program.getListing();
|
||||
Function f = listing.getFunctionAt(addr(program, "SomeOverlay:0x01001780"));
|
||||
f.setCallingConvention(CompilerSpec.CALLING_CONVENTION_thiscall);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
p1 = mtf.getResultProgram();
|
||||
p2 = mtf.getPrivateProgram();
|
||||
|
||||
programDiff = new ProgramDiff(p1, p2);
|
||||
AddressSet as = new AddressSet();
|
||||
as.addRange(addr(p1, "SomeOverlay::01001780"), addr(p1, "SomeOverlay::01001780"));
|
||||
as.addRange(addr(p1, "OtherOverlay::01001680"), addr(p1, "OtherOverlay::01001680"));
|
||||
programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.FUNCTION_DIFFS));
|
||||
assertEquals(as, programDiff.getDifferences(programDiff.getFilter(), null));
|
||||
|
||||
ProgramMergeManager programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY);
|
||||
programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.FUNCTION_DIFFS));
|
||||
programMerge.setMergeFilter(
|
||||
new ProgramMergeFilter(ProgramMergeFilter.FUNCTIONS, ProgramMergeFilter.REPLACE));
|
||||
assertEquals(as, programMerge.getFilteredDifferences());
|
||||
|
||||
p1.withTransaction("merge", () -> programMerge.merge(as, TaskMonitor.DUMMY));
|
||||
assertEquals(new AddressSet(), programMerge.getFilteredDifferences());
|
||||
|
||||
Listing listing1 = p1.getListing();
|
||||
assertNotNull(listing1.getFunctionAt(addr(p1, "OtherOverlay:0x01001680")));
|
||||
assertNotNull(listing1.getFunctionAt(addr(p1, "SomeOverlay:0x01001780")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDiffMergeOverlayLabels() throws Exception {
|
||||
mtf.initialize("overlayCalc", new MultiOverlayProgramModifierListener() {
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
super.modifyLatest(program);
|
||||
try {
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
st.createLabel(addr(program, "SomeOverlay::01001630"), "OVL1630",
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "OtherOverlay::01001866"), "OVL1866",
|
||||
SourceType.USER_DEFINED);
|
||||
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
super.modifyPrivate(program);
|
||||
try {
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
st.createLabel(addr(program, "SomeOverlay::01001889"), "OVL1889",
|
||||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "OtherOverlay::01001646"), "OVL1646",
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
p1 = mtf.getResultProgram();
|
||||
p2 = mtf.getPrivateProgram();
|
||||
|
||||
programDiff = new ProgramDiff(p1, p2);
|
||||
final AddressSet as = new AddressSet();
|
||||
as.addRange(addr(p1, "SomeOverlay::01001630"), addr(p1, "SomeOverlay::01001630"));
|
||||
as.addRange(addr(p1, "SomeOverlay::01001889"), addr(p1, "SomeOverlay::01001889"));
|
||||
as.addRange(addr(p1, "OtherOverlay::01001646"), addr(p1, "OtherOverlay::01001646"));
|
||||
as.addRange(addr(p1, "OtherOverlay::01001866"), addr(p1, "OtherOverlay::01001866"));
|
||||
programDiff.setFilter(new ProgramDiffFilter(ProgramDiffFilter.SYMBOL_DIFFS));
|
||||
assertEquals(as, programDiff.getDifferences(programDiff.getFilter(), null));
|
||||
|
||||
ProgramMergeManager programMerge = new ProgramMergeManager(p1, p2, TaskMonitor.DUMMY);
|
||||
programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.SYMBOL_DIFFS));
|
||||
programMerge.setMergeFilter(
|
||||
new ProgramMergeFilter(ProgramMergeFilter.SYMBOLS | ProgramMergeFilter.PRIMARY_SYMBOL,
|
||||
ProgramMergeFilter.REPLACE));
|
||||
assertEquals(as, programMerge.getFilteredDifferences());
|
||||
|
||||
p1.withTransaction("merge", () -> programMerge.merge(as, TaskMonitor.DUMMY));
|
||||
AddressSet as2 = new AddressSet();
|
||||
// Symbol removal not handled - only replace or add
|
||||
as2.addRange(addr(p1, "OtherOverlay::01001866"), addr(p1, "OtherOverlay::01001866"));
|
||||
assertEquals(as2, programMerge.getFilteredDifferences());
|
||||
|
||||
SymbolTable st1 = p1.getSymbolTable();
|
||||
assertNotNull(st1.getSymbol("OVL1889", addr(p1, "SomeOverlay::01001889"), null));
|
||||
assertNotNull(st1.getSymbol("OVL1646", addr(p1, "OtherOverlay::01001646"), null));
|
||||
}
|
||||
|
||||
// private void printAddressSet(AddressSetView as) {
|
||||
// System.out.println("=====");
|
||||
// for (AddressRange r : as) {
|
||||
// System.out.println("[" + r.getMinAddress() + "," + r.getMaxAddress() + "]");
|
||||
// }
|
||||
// System.out.println("-----");
|
||||
// }
|
||||
|
||||
private class MultiOverlayProgramModifierListener implements ProgramModifierListener {
|
||||
|
||||
@Override
|
||||
public void modifyLatest(ProgramDB program) {
|
||||
// P1 program
|
||||
try {
|
||||
program.getMemory()
|
||||
.createInitializedBlock("SomeOverlay", addr(program, "0x01001630"), 0x200,
|
||||
(byte) 0, TaskMonitor.DUMMY, true);
|
||||
program.getMemory()
|
||||
.createInitializedBlock("OtherOverlay", addr(program, "0x01001630"), 0x300,
|
||||
(byte) 0, TaskMonitor.DUMMY, true);
|
||||
|
||||
initProgramCommon(program);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifyPrivate(ProgramDB program) {
|
||||
// P2 program
|
||||
try {
|
||||
program.getMemory()
|
||||
.createInitializedBlock("OtherOverlay", addr(program, "0x01001630"), 0x200,
|
||||
(byte) 0, TaskMonitor.DUMMY, true);
|
||||
program.getMemory()
|
||||
.createInitializedBlock("SomeOverlay", addr(program, "0x01001630"), 0x300,
|
||||
(byte) 0, TaskMonitor.DUMMY, true);
|
||||
|
||||
initProgramCommon(program);
|
||||
}
|
||||
catch (Exception e) {
|
||||
Assert.fail(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void initProgramCommon(Program program) throws Exception {
|
||||
Listing listing = program.getListing();
|
||||
|
||||
Address a = addr(program, "OtherOverlay:0x01001680");
|
||||
listing.createFunction("oFunc", a, new AddressSet(a, a), SourceType.USER_DEFINED);
|
||||
|
||||
a = addr(program, "SomeOverlay:0x01001780");
|
||||
listing.createFunction("sFunc", a, new AddressSet(a, a), SourceType.USER_DEFINED);
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -29,8 +29,7 @@ import org.junit.*;
|
|||
|
||||
import ghidra.app.cmd.function.CreateFunctionCmd;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressSet;
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.data.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.listing.*;
|
||||
|
@ -3221,6 +3220,8 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
SourceType.USER_DEFINED);
|
||||
st.createLabel(addr(program, "Foo:0x01000180"), "Other0180", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
// TODO: No CodeUnit at Foo:0x01000200 - outside memory block
|
||||
// Should symbols be handled by Diff/Merge outside of memory blocks?
|
||||
st.createLabel(addr(program, "Foo:0x01000200"), "Other0200", globalNamespace,
|
||||
SourceType.USER_DEFINED);
|
||||
}
|
||||
|
@ -3238,16 +3239,32 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
try {
|
||||
programMerge = new ProgramMergeManager(p1, p2, null, TaskMonitor.DUMMY);
|
||||
|
||||
programMerge.setDiffFilter(new ProgramDiffFilter(
|
||||
ProgramDiffFilter.SYMBOL_DIFFS | ProgramDiffFilter.FUNCTION_DIFFS));
|
||||
programMerge.setMergeFilter(
|
||||
new ProgramMergeFilter(ProgramMergeFilter.FUNCTIONS, ProgramMergeFilter.REPLACE));
|
||||
// Only program1's symbol Diffs are found since program2's overlay is not compatible with program1.
|
||||
programMerge.setDiffFilter(new ProgramDiffFilter(ProgramDiffFilter.SYMBOL_DIFFS));
|
||||
|
||||
AddressSetView diffSet = programMerge.getFilteredDifferences();
|
||||
|
||||
AddressSet expectedDiffs = new AddressSet();
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x01000030"), addr(p1, "Foo:0x01000030"));
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x01000079"), addr(p1, "Foo:0x01000079"));
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x0100017f"), addr(p1, "Foo:0x0100017f"));
|
||||
assertEquals(expectedDiffs, programMerge.getFilteredDifferences());
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x01000080"), addr(p1, "Foo:0x01000080"));
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x0100017f"), addr(p1, "Foo:0x01000180"));
|
||||
assertEquals(expectedDiffs, diffSet);
|
||||
|
||||
programMerge.setMergeFilter(new ProgramMergeFilter(
|
||||
ProgramMergeFilter.SYMBOLS | ProgramMergeFilter.PRIMARY_SYMBOL,
|
||||
ProgramMergeFilter.REPLACE));
|
||||
|
||||
// must intersect diff set with p1 memory to avoid skipping merge
|
||||
programMerge.merge(expectedDiffs.intersect(p1.getMemory()), TaskMonitor.DUMMY);
|
||||
|
||||
diffSet = programMerge.getFilteredDifferences();
|
||||
expectedDiffs = new AddressSet();
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x01000030"), addr(p1, "Foo:0x01000030"));
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x01000079"), addr(p1, "Foo:0x01000079"));
|
||||
// Foo:0x01000180 not applied to p1 since outside defined memory block
|
||||
expectedDiffs.addRange(addr(p1, "Foo:0x01000180"), addr(p1, "Foo:0x01000180"));
|
||||
assertEquals(expectedDiffs, diffSet);
|
||||
|
||||
commit = true;
|
||||
}
|
||||
finally {
|
||||
|
@ -4395,6 +4412,8 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
AddressSet expectedDiffs = new AddressSet();
|
||||
expectedDiffs.addRange(addr(p1, "SomeOverlay::01001630"),
|
||||
addr(p1, "SomeOverlay::01001630"));
|
||||
expectedDiffs.addRange(addr(p1, "SomeOverlay::01001889"),
|
||||
addr(p1, "SomeOverlay::01001889"));
|
||||
expectedDiffs.addRange(addr(p1, "OtherOverlay::01001646"),
|
||||
addr(p1, "OtherOverlay::01001646"));
|
||||
expectedDiffs.addRange(addr(p1, "OtherOverlay::01001866"),
|
||||
|
@ -4426,7 +4445,7 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals("OVL1630", symbols[0].getName());
|
||||
|
||||
symbols = resultSymTab.getSymbols(addr(p1, "SomeOverlay::01001889"));
|
||||
assertEquals(0, symbols.length); // Not part of the merge set.
|
||||
assertEquals(1, symbols.length);
|
||||
|
||||
symbols = resultSymTab.getSymbols(addr(p1, "OtherOverlay::01001646"));
|
||||
assertEquals(1, symbols.length);
|
||||
|
@ -4502,6 +4521,8 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
AddressSet expectedDiffs = new AddressSet();
|
||||
expectedDiffs.addRange(addr(p1, "SomeOverlay::01001630"),
|
||||
addr(p1, "SomeOverlay::01001630"));
|
||||
expectedDiffs.addRange(addr(p1, "SomeOverlay::01001889"),
|
||||
addr(p1, "SomeOverlay::01001889"));
|
||||
expectedDiffs.addRange(addr(p1, "OtherOverlay::01001646"),
|
||||
addr(p1, "OtherOverlay::01001646"));
|
||||
expectedDiffs.addRange(addr(p1, "OtherOverlay::01001866"),
|
||||
|
@ -4530,7 +4551,7 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
assertEquals(0, symbols.length);
|
||||
|
||||
symbols = resultSymTab.getSymbols(addr(p1, "SomeOverlay::01001889"));
|
||||
assertEquals(0, symbols.length); // Not part of the merge set.
|
||||
assertEquals(1, symbols.length);
|
||||
|
||||
symbols = resultSymTab.getSymbols(addr(p1, "OtherOverlay::01001646"));
|
||||
assertEquals(1, symbols.length);
|
||||
|
@ -4649,9 +4670,11 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
// P1 program
|
||||
SymbolTable st = program.getSymbolTable();
|
||||
try {
|
||||
// SomeOverlay 0x01001630 - 0x0100182f
|
||||
program.getMemory()
|
||||
.createInitializedBlock("SomeOverlay", addr(program, "0x01001630"),
|
||||
0x200, (byte) 0, TaskMonitor.DUMMY, true);
|
||||
// OtherOverlay 0x01001630 - 0x0100192f
|
||||
program.getMemory()
|
||||
.createInitializedBlock("OtherOverlay", addr(program, "0x01001630"),
|
||||
0x300, (byte) 0, TaskMonitor.DUMMY, true);
|
||||
|
@ -4712,13 +4735,30 @@ public class ProgramMerge2Test extends AbstractGhidraHeadedIntegrationTest {
|
|||
addr(p1, "OtherOverlay::01001646"));
|
||||
assertEquals(expectedDiffs, programMerge.getFilteredDifferences());
|
||||
|
||||
SymbolTable st1 = p1.getSymbolTable();
|
||||
Address a1 = addr(p1, "SomeOverlay::01001630");
|
||||
Address a2 = addr(p1, "OtherOverlay::01001646");
|
||||
System.out.println("Before:");
|
||||
for (Symbol s : st1.getSymbols(a1)) {
|
||||
System.out.println(a1 + " " + s.getName());
|
||||
}
|
||||
for (Symbol s : st1.getSymbols(a2)) {
|
||||
System.out.println(a2 + " " + s.getName());
|
||||
}
|
||||
|
||||
programMerge.setMergeFilter(
|
||||
new ProgramMergeFilter(ProgramMergeFilter.SYMBOLS, ProgramMergeFilter.REPLACE));
|
||||
programMerge.merge(expectedDiffs, TaskMonitor.DUMMY);
|
||||
|
||||
AddressSet expectedPostMergeDiffs = new AddressSet();
|
||||
assertEquals(expectedPostMergeDiffs, programMerge.getFilteredDifferences());
|
||||
System.out.println("After:");
|
||||
for (Symbol s : st1.getSymbols(a1)) {
|
||||
System.out.println(a1 + " " + s.getName());
|
||||
}
|
||||
for (Symbol s : st1.getSymbols(a2)) {
|
||||
System.out.println(a2 + " " + s.getName());
|
||||
}
|
||||
|
||||
AddressSet expectedPostMergeDiffs = new AddressSet();
|
||||
assertEquals(expectedPostMergeDiffs, programMerge.getFilteredDifferences());
|
||||
commit = true;
|
||||
}
|
||||
|
|
|
@ -136,12 +136,13 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
assertNotNull(block);
|
||||
assertEquals(100, block.getSize());
|
||||
AddressSpace space = x08.getAddressFactory().getAddressSpace(".testBit");
|
||||
assertNotNull(space);
|
||||
assertTrue(space instanceof OverlayAddressSpace);
|
||||
OverlayAddressSpace ospace = (OverlayAddressSpace) space;
|
||||
assertTrue(space.isOverlaySpace());
|
||||
assertEquals(space.getAddress(0x3000), block.getStart());
|
||||
assertEquals(space.getAddress(0x3063), block.getEnd());
|
||||
assertEquals(block.getStart(), space.getMinAddress());
|
||||
assertEquals(block.getEnd(), space.getMaxAddress());
|
||||
assertEquals(block.getStart(), ospace.getOverlayAddressSet().getMinAddress());
|
||||
assertEquals(block.getEnd(), ospace.getOverlayAddressSet().getMaxAddress());
|
||||
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||
AddressRange mappedRange = info.getMappedRange().get();
|
||||
assertEquals(13, mappedRange.getLength());
|
||||
|
@ -198,12 +199,13 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
assertNotNull(block);
|
||||
assertEquals(100, block.getSize());
|
||||
AddressSpace space = x08.getAddressFactory().getAddressSpace(".testByte");
|
||||
assertNotNull(space);
|
||||
assertTrue(space instanceof OverlayAddressSpace);
|
||||
OverlayAddressSpace ospace = (OverlayAddressSpace) space;
|
||||
assertTrue(space.isOverlaySpace());
|
||||
assertEquals(space.getAddress(0x3000), block.getStart());
|
||||
assertEquals(space.getAddress(0x3063), block.getEnd());
|
||||
assertEquals(block.getStart(), space.getMinAddress());
|
||||
assertEquals(block.getEnd(), space.getMaxAddress());
|
||||
assertEquals(block.getStart(), ospace.getOverlayAddressSet().getMinAddress());
|
||||
assertEquals(block.getEnd(), ospace.getOverlayAddressSet().getMaxAddress());
|
||||
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||
AddressRange mappedRange = info.getMappedRange().get();
|
||||
assertEquals(100, mappedRange.getLength());
|
||||
|
@ -226,12 +228,13 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
|||
assertNotNull(block);
|
||||
assertEquals(100, block.getSize());
|
||||
AddressSpace space = x08.getAddressFactory().getAddressSpace(".testByte");
|
||||
assertNotNull(space);
|
||||
assertTrue(space instanceof OverlayAddressSpace);
|
||||
OverlayAddressSpace ospace = (OverlayAddressSpace) space;
|
||||
assertTrue(space.isOverlaySpace());
|
||||
assertEquals(space.getAddress(0x3000), block.getStart());
|
||||
assertEquals(space.getAddress(0x3063), block.getEnd());
|
||||
assertEquals(block.getStart(), space.getMinAddress());
|
||||
assertEquals(block.getEnd(), space.getMaxAddress());
|
||||
assertEquals(block.getStart(), ospace.getOverlayAddressSet().getMinAddress());
|
||||
assertEquals(block.getEnd(), ospace.getOverlayAddressSet().getMaxAddress());
|
||||
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||
AddressRange mappedRange = info.getMappedRange().get();
|
||||
assertEquals(198, mappedRange.getLength());
|
||||
|
|
|
@ -0,0 +1,117 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.*;
|
||||
|
||||
import generic.test.AbstractGenericTest;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
|
||||
public class ProgramAddressFactoryOverlayTest extends AbstractGenericTest {
|
||||
|
||||
private ProgramDB p;
|
||||
ProgramAddressFactory factory;
|
||||
private AddressSpace defaultSpace;
|
||||
|
||||
public ProgramAddressFactoryOverlayTest() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
ProgramBuilder builder = new ProgramBuilder("Test", ProgramBuilder._TOY);
|
||||
p = builder.getProgram();
|
||||
factory = p.getAddressFactory();
|
||||
defaultSpace = p.getAddressFactory().getDefaultAddressSpace();
|
||||
p.addConsumer(this);
|
||||
builder.dispose();
|
||||
|
||||
p.withTransaction("Add Overlays", () -> {
|
||||
p.createOverlaySpace("A", defaultSpace);
|
||||
p.createOverlaySpace("B", defaultSpace);
|
||||
p.createOverlaySpace("C", defaultSpace);
|
||||
});
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() throws Exception {
|
||||
p.release(this);
|
||||
}
|
||||
|
||||
private int getSpaceId(String spaceName) {
|
||||
AddressSpace space = factory.getAddressSpace(spaceName);
|
||||
assertNotNull("Space " + spaceName + " not found", space);
|
||||
return System.identityHashCode(space);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOverlayRename() throws Exception {
|
||||
|
||||
AddressSpace aSpace = factory.getAddressSpace("A");
|
||||
int aId = System.identityHashCode(aSpace);
|
||||
AddressSpace bSpace = factory.getAddressSpace("B");
|
||||
int bId = System.identityHashCode(bSpace);
|
||||
AddressSpace cSpace = factory.getAddressSpace("C");
|
||||
int cId = System.identityHashCode(cSpace);
|
||||
|
||||
// Perform extensive renames within single transaction
|
||||
p.withTransaction("Add Overlays", () -> {
|
||||
p.renameOverlaySpace("C", "Ctmp");
|
||||
p.renameOverlaySpace("A", "C");
|
||||
p.renameOverlaySpace("B", "A");
|
||||
p.renameOverlaySpace("Ctmp", "B");
|
||||
|
||||
p.createOverlaySpace("D", defaultSpace);
|
||||
});
|
||||
|
||||
assertEquals(aId, getSpaceId("C"));
|
||||
assertEquals(bId, getSpaceId("A"));
|
||||
assertEquals(cId, getSpaceId("B"));
|
||||
|
||||
assertEquals("C", aSpace.getName());
|
||||
assertEquals("A", bSpace.getName());
|
||||
assertEquals("B", cSpace.getName());
|
||||
|
||||
assertNotNull(factory.getAddressSpace("D"));
|
||||
|
||||
p.undo();
|
||||
|
||||
assertEquals(aId, getSpaceId("A"));
|
||||
assertEquals(bId, getSpaceId("B"));
|
||||
assertEquals(cId, getSpaceId("C"));
|
||||
|
||||
assertEquals("A", aSpace.getName());
|
||||
assertEquals("B", bSpace.getName());
|
||||
assertEquals("C", cSpace.getName());
|
||||
|
||||
assertNull(factory.getAddressSpace("D"));
|
||||
|
||||
p.redo();
|
||||
|
||||
assertEquals(aId, getSpaceId("C"));
|
||||
assertEquals(bId, getSpaceId("A"));
|
||||
assertEquals(cId, getSpaceId("B"));
|
||||
|
||||
assertEquals("C", aSpace.getName());
|
||||
assertEquals("A", bSpace.getName());
|
||||
assertEquals("B", cSpace.getName());
|
||||
|
||||
assertNotNull(factory.getAddressSpace("D"));
|
||||
|
||||
}
|
||||
}
|
|
@ -71,8 +71,9 @@ public class ProgramOverlaysTest extends AbstractGenericTest {
|
|||
AddressSpace space = p.getAddressFactory().getAddressSpace("OV1");
|
||||
assertNotNull(space);
|
||||
memory.setBytes(space.getAddress(0x100), fillB);
|
||||
p.getReferenceManager().addMemoryReference(addr(p, "0x1001003"), addr(p, "OV1:0x100"),
|
||||
RefType.DATA, SourceType.USER_DEFINED, 0);
|
||||
p.getReferenceManager()
|
||||
.addMemoryReference(addr(p, "0x1001003"), addr(p, "OV1:0x100"), RefType.DATA,
|
||||
SourceType.USER_DEFINED, 0);
|
||||
p.endTransaction(id, true);
|
||||
|
||||
return space;
|
||||
|
@ -140,18 +141,18 @@ public class ProgramOverlaysTest extends AbstractGenericTest {
|
|||
assertNotNull(block);
|
||||
|
||||
int id = p.startTransaction("");
|
||||
block.setName("BOB");
|
||||
block.setName("BOB"); // does not affect name of overlay which was created with block creation
|
||||
p.endTransaction(id, true);
|
||||
|
||||
assertEquals("BOB", block.getName());
|
||||
assertEquals(block, memory.getBlock("BOB"));
|
||||
|
||||
assertEquals("BOB", space.getName());
|
||||
assertEquals(space, p.getAddressFactory().getAddressSpace("BOB"));
|
||||
assertEquals("OV1", space.getName());
|
||||
assertEquals(space, p.getAddressFactory().getAddressSpace("OV1"));
|
||||
|
||||
Reference[] refs = p.getReferenceManager().getReferencesFrom(addr(p, "0x1001003"));
|
||||
assertEquals(1, refs.length);
|
||||
assertEquals("BOB::00000100", refs[0].getToAddress().toString());
|
||||
assertEquals("OV1::00000100", refs[0].getToAddress().toString());
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -300,9 +300,8 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
DiffUtility.getCompatibleAddressSet(p1AddressSet, secondaryDiffProgram);
|
||||
AddressIndexMap p2IndexMap = new AddressIndexMap(p1AddressSetAsP2);
|
||||
markerManager.getOverviewProvider().setProgram(secondaryDiffProgram, p2IndexMap);
|
||||
fp.setBackgroundColorModel(
|
||||
new MarkerServiceBackgroundColorModel(markerManager, secondaryDiffProgram,
|
||||
p2IndexMap));
|
||||
fp.setBackgroundColorModel(new MarkerServiceBackgroundColorModel(markerManager,
|
||||
secondaryDiffProgram, p2IndexMap));
|
||||
|
||||
currentSelection = previousP1Selection;
|
||||
p2DiffHighlight = previousP2DiffHighlight;
|
||||
|
@ -1062,9 +1061,7 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
setProgram2Selection(p2Selection);
|
||||
clearDiff();
|
||||
if (secondaryDiffProgram != null) {
|
||||
Iterator<BookmarkNavigator> iter = bookmarkMap.values().iterator();
|
||||
while (iter.hasNext()) {
|
||||
BookmarkNavigator nav = iter.next();
|
||||
for (BookmarkNavigator nav : bookmarkMap.values()) {
|
||||
nav.dispose();
|
||||
}
|
||||
bookmarkMap.clear();
|
||||
|
@ -1140,6 +1137,10 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
}
|
||||
|
||||
private void selectAndOpenProgram2() {
|
||||
if (checkStaleOverlays(currentProgram)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final OpenVersionedFileDialog<Program> dialog = getOpenVersionedFileDialog();
|
||||
|
||||
List<Program> openProgramList = getOpenProgramList();
|
||||
|
@ -1161,6 +1162,30 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
dialog.showComponent();
|
||||
}
|
||||
|
||||
private boolean hasStaleOverlays(Program p) {
|
||||
return p.getAddressFactory().hasStaleOverlayCondition();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check program's address factory for stale overlay condition.
|
||||
* @param p program to check
|
||||
* @return true if user chose to cancel operation due to stale overlays
|
||||
*/
|
||||
private boolean checkStaleOverlays(Program p) {
|
||||
if (!hasStaleOverlays(p)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String usage = (p == currentProgram) ? "current" : "selected";
|
||||
|
||||
int rc = OptionDialog.showOptionDialogWithCancelAsDefaultButton(null, "Diff Warning",
|
||||
"The " + usage +
|
||||
" program has recently had an overlay space renamed which may prevent an accurate Diff.\n" +
|
||||
"It is recommended that the program be closed and re-opened before performing Diff.",
|
||||
"Continue");
|
||||
return (rc != OptionDialog.OPTION_ONE);
|
||||
}
|
||||
|
||||
private OpenVersionedFileDialog<Program> getOpenVersionedFileDialog() {
|
||||
|
||||
if (openVersionedFileDialog != null) {
|
||||
|
@ -1567,6 +1592,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
newProgram.release(this);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!hasStaleOverlays(currentProgram) && checkStaleOverlays(newProgram)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProgramMemoryComparator programMemoryComparator = null;
|
||||
try {
|
||||
programMemoryComparator = new ProgramMemoryComparator(currentProgram, newProgram);
|
||||
|
@ -1629,14 +1659,19 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
secondaryDiffProgram);
|
||||
actionManager.secondProgramOpened();
|
||||
actionManager.addActions();
|
||||
diffListingPanel.goTo(currentLocation);
|
||||
|
||||
MarkerSet cursorMarkers = getCursorMarkers();
|
||||
Address currentP2Address = currentLocation.getAddress();
|
||||
ProgramLocation current2PLocation = currentLocation;
|
||||
if (currentLocation.getProgram() != secondaryDiffProgram) { // Make sure address is from P2.
|
||||
currentP2Address = SimpleDiffUtility.getCompatibleAddress(currentLocation.getProgram(),
|
||||
currentLocation.getAddress(), secondaryDiffProgram);
|
||||
if (currentP2Address != null) {
|
||||
current2PLocation = ProgramLocation.getTranslatedCopy(currentLocation,
|
||||
secondaryDiffProgram, currentP2Address);
|
||||
}
|
||||
}
|
||||
diffListingPanel.goTo(current2PLocation);
|
||||
if (currentP2Address != null) {
|
||||
cursorMarkers.setAddressSet(new AddressSet(currentP2Address));
|
||||
}
|
||||
|
@ -1812,10 +1847,11 @@ public class ProgramDiffPlugin extends ProgramPlugin
|
|||
return;
|
||||
}
|
||||
|
||||
ListingField lf = (ListingField) field;
|
||||
ProgramLocation pLoc = null;
|
||||
if (field instanceof ListingField lf) {
|
||||
FieldFactory factory = lf.getFieldFactory();
|
||||
ProgramLocation pLoc =
|
||||
factory.getProgramLocation(location.getRow(), location.getCol(), lf);
|
||||
pLoc = factory.getProgramLocation(location.getRow(), location.getCol(), lf);
|
||||
}
|
||||
|
||||
// if clicked in dummy field, try and find the address for the white space.
|
||||
if (pLoc == null) {
|
||||
|
|
|
@ -17,10 +17,13 @@ package docking.widgets.fieldpanel.support;
|
|||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JComponent;
|
||||
|
||||
import docking.widgets.fieldpanel.Layout;
|
||||
import docking.widgets.fieldpanel.field.EmptyTextField;
|
||||
import docking.widgets.fieldpanel.field.Field;
|
||||
import docking.widgets.fieldpanel.internal.*;
|
||||
|
||||
|
@ -54,9 +57,9 @@ public class MultiRowLayout implements Layout {
|
|||
this.indexSize = indexSize;
|
||||
this.layouts = layouts;
|
||||
int height = 0;
|
||||
for (int i = 0; i < layouts.length; i++) {
|
||||
numFields += layouts[i].getNumFields();
|
||||
height += layouts[i].getHeight();
|
||||
for (RowLayout layout : layouts) {
|
||||
numFields += layout.getNumFields();
|
||||
height += layout.getHeight();
|
||||
}
|
||||
heightAbove = layouts[0].getHeightAbove();
|
||||
heightBelow = height - heightAbove;
|
||||
|
@ -313,65 +316,6 @@ public class MultiRowLayout implements Layout {
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* <CODE>synchronize</CODE> adjusts this layout and the layout passed as a
|
||||
* parameter by adding and resizing rows as necessary to make their
|
||||
* vertical layouts match.
|
||||
*
|
||||
* @param layout the other multi-row layout that is to be synchronized with.
|
||||
* @param dummyField empty field used for spacing.
|
||||
*/
|
||||
public void align(MultiRowLayout layout, Field dummyField) {
|
||||
int myNumRows = layouts.length;
|
||||
int otherNumRows = layout.layouts.length;
|
||||
int myRow = 0;
|
||||
int otherRow = 0;
|
||||
int myHeight = layouts[myRow].getHeight();
|
||||
int otherHeight = layout.layouts[otherRow].getHeight();
|
||||
primaryOffset = -1;
|
||||
|
||||
while (myRow < myNumRows && otherRow < otherNumRows) {
|
||||
int myId = layouts[myRow].getRowID();
|
||||
int otherId = layout.layouts[otherRow].getRowID();
|
||||
|
||||
if (myId < otherId) {
|
||||
layout.layouts[otherRow].insertSpaceAbove(myHeight);
|
||||
if (++myRow < myNumRows)
|
||||
myHeight = layouts[myRow].getHeight();
|
||||
}
|
||||
else if (myId > otherId) {
|
||||
layouts[myRow].insertSpaceAbove(otherHeight);
|
||||
if (++otherRow < otherNumRows)
|
||||
otherHeight = layout.layouts[otherRow].getHeight();
|
||||
}
|
||||
else {
|
||||
int myEnd = layouts[myRow].getHeight();
|
||||
int otherEnd = layout.layouts[otherRow].getHeight();
|
||||
if (myEnd > otherEnd) {
|
||||
layout.layouts[otherRow].insertSpaceBelow(myEnd - otherEnd);
|
||||
}
|
||||
else if (otherEnd > myEnd) {
|
||||
layouts[myRow].insertSpaceBelow(otherEnd - myEnd);
|
||||
}
|
||||
if (++myRow < myNumRows)
|
||||
myHeight = layouts[myRow].getHeight();
|
||||
if (++otherRow < otherNumRows)
|
||||
otherHeight = layout.layouts[otherRow].getHeight();
|
||||
}
|
||||
}
|
||||
while (myRow < myNumRows) {
|
||||
layout.layouts[otherNumRows - 1].insertSpaceBelow(myHeight);
|
||||
if (++myRow < myNumRows)
|
||||
myHeight = layouts[myRow].getHeight();
|
||||
}
|
||||
|
||||
while (otherRow < otherNumRows) {
|
||||
layouts[myNumRows - 1].insertSpaceBelow(otherHeight);
|
||||
if (++otherRow < otherNumRows)
|
||||
otherHeight = layout.layouts[otherRow].getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPrimaryOffset() {
|
||||
if (primaryOffset == -1) {
|
||||
|
@ -382,11 +326,11 @@ public class MultiRowLayout implements Layout {
|
|||
|
||||
private void findPrimaryOffset() {
|
||||
primaryOffset = 0;
|
||||
for (int i = 0; i < layouts.length; i++) {
|
||||
if (layouts[i].isPrimary()) {
|
||||
for (RowLayout layout : layouts) {
|
||||
if (layout.isPrimary()) {
|
||||
return;
|
||||
}
|
||||
primaryOffset += layouts[i].getHeight();
|
||||
primaryOffset += layout.getHeight();
|
||||
}
|
||||
primaryOffset = 0;
|
||||
}
|
||||
|
@ -426,17 +370,17 @@ public class MultiRowLayout implements Layout {
|
|||
public void fillHeights(int[] rowHeights) {
|
||||
int lastId = -1;
|
||||
int height = 0;
|
||||
for (int i = 0; i < layouts.length; i++) {
|
||||
int id = layouts[i].getRowID();
|
||||
for (RowLayout layout : layouts) {
|
||||
int id = layout.getRowID();
|
||||
if (id == lastId) {
|
||||
height += layouts[i].getHeight();
|
||||
height += layout.getHeight();
|
||||
}
|
||||
else {
|
||||
if (lastId >= 0) {
|
||||
rowHeights[lastId] = Math.max(rowHeights[lastId], height);
|
||||
}
|
||||
lastId = id;
|
||||
height = layouts[i].getHeight();
|
||||
height = layout.getHeight();
|
||||
}
|
||||
}
|
||||
if (lastId >= 0) {
|
||||
|
@ -444,6 +388,17 @@ public class MultiRowLayout implements Layout {
|
|||
}
|
||||
}
|
||||
|
||||
private class EmptyRowLayout extends RowLayout {
|
||||
|
||||
public EmptyRowLayout(int rowId, int height) {
|
||||
super(getEmptyFields(height), rowId);
|
||||
}
|
||||
|
||||
private static Field[] getEmptyFields(int height) {
|
||||
return new Field[] { new EmptyTextField(height, 0, 0, 0) };
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Aligns the heights in this MultiRowLayout to match those in the give row heights array.
|
||||
* Extra is inserted to align the rows in this layout to match those specified in the given array.
|
||||
|
@ -451,36 +406,39 @@ public class MultiRowLayout implements Layout {
|
|||
*/
|
||||
public void align(int[] rowHeights) {
|
||||
int row = 0;
|
||||
int totalAbove = 0;
|
||||
int lastId = -1;
|
||||
for (int i = 0; i < layouts.length; i++) {
|
||||
int id = layouts[i].getRowID();
|
||||
if (id != lastId) {
|
||||
for (; row < id; row++) {
|
||||
totalAbove += rowHeights[row];
|
||||
List<RowLayout> updatedRows = new ArrayList<>();
|
||||
for (RowLayout layout : layouts) {
|
||||
int id = layout.getRowID();
|
||||
for (; row <= id; row++) {
|
||||
if (rowHeights[row] == 0) {
|
||||
continue;
|
||||
}
|
||||
int origHeight = layouts[i].getHeight();
|
||||
layouts[i].insertSpaceAbove(totalAbove);
|
||||
totalAbove = rowHeights[id] - origHeight;
|
||||
lastId = id;
|
||||
row++;
|
||||
if (row == id) {
|
||||
layout.insertSpaceBelow(rowHeights[id] - layout.getHeight());
|
||||
updatedRows.add(layout);
|
||||
}
|
||||
else {
|
||||
totalAbove -= layouts[i].getHeight();
|
||||
updatedRows.add(new EmptyRowLayout(row, rowHeights[row]));
|
||||
}
|
||||
}
|
||||
int totalBelow = totalAbove;
|
||||
}
|
||||
|
||||
for (; row < rowHeights.length; row++) {
|
||||
totalBelow += rowHeights[row];
|
||||
if (rowHeights[row] != 0) {
|
||||
updatedRows.add(new EmptyRowLayout(row, rowHeights[row]));
|
||||
}
|
||||
}
|
||||
insertSpaceBelow(totalBelow);
|
||||
|
||||
int height = 0;
|
||||
layouts = new RowLayout[updatedRows.size()];
|
||||
for (int i = 0; i < layouts.length; i++) {
|
||||
layouts[i] = updatedRows.get(i);
|
||||
height += layouts[i].getHeight();
|
||||
}
|
||||
|
||||
heightAbove = layouts[0].getHeightAbove();
|
||||
heightBelow = height - heightAbove;
|
||||
buildOffsets();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import ghidra.program.model.address.AddressSetView;
|
||||
import ghidra.program.model.address.OverlayAddressSpace;
|
||||
|
||||
/**
|
||||
* {@link OverlayRegionSupplier} provides a callback mechanism which allows a
|
||||
* {@link ProgramOverlayAddressSpace} to identify defined memory regions within its
|
||||
* space so that it may properly implement the {@link OverlayAddressSpace#contains(long)}
|
||||
* method.
|
||||
*/
|
||||
public interface OverlayRegionSupplier {
|
||||
|
||||
/**
|
||||
* Get the set of memory address defined within the specified overlay space.
|
||||
* @param overlaySpace overlay address space
|
||||
* @return set of memory address defined within the specified overlay space or null
|
||||
*/
|
||||
AddressSetView getOverlayAddressSet(OverlayAddressSpace overlaySpace);
|
||||
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.address.OverlayAddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.util.LanguageTranslator;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
class OverlaySpaceAdapterDB {
|
||||
private static String TABLE_NAME = "Overlay Spaces";
|
||||
static final Schema SCHEMA = new Schema(0, "ID",
|
||||
new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE,
|
||||
LongField.INSTANCE },
|
||||
new String[] { "Overlay Space", "Template Space", "Minimum Offset", "Maximum Offset" });
|
||||
|
||||
private static final int OV_SPACE_NAME_COL = 0;
|
||||
private static final int OV_SPACE_BASE_COL = 1;
|
||||
private static final int OV_MIN_OFFSET_COL = 2;
|
||||
private static final int OV_MAX_OFFSET_COL = 3;
|
||||
|
||||
DBHandle db;
|
||||
|
||||
OverlaySpaceAdapterDB(DBHandle dbHandle) {
|
||||
this.db = dbHandle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds existing overlay spaces to the factory.
|
||||
* @param factory the factory to add overlay spaces to
|
||||
* @throws IOException
|
||||
*/
|
||||
void initializeOverlaySpaces(ProgramAddressFactory factory) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String spaceName = rec.getString(OV_SPACE_NAME_COL);
|
||||
String templateSpaceName = rec.getString(OV_SPACE_BASE_COL);
|
||||
long minOffset = rec.getLongValue(OV_MIN_OFFSET_COL);
|
||||
long maxOffset = rec.getLongValue(OV_MAX_OFFSET_COL);
|
||||
AddressSpace space = factory.getAddressSpace(templateSpaceName);
|
||||
try {
|
||||
OverlayAddressSpace sp =
|
||||
factory.addOverlayAddressSpace(spaceName, true, space, minOffset, maxOffset);
|
||||
sp.setDatabaseKey(rec.getKey());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected error initializing overlay address spaces", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new overlay space to the database
|
||||
* @param id the name of the new overlay space to add
|
||||
* @param space the template space used to create the new space.
|
||||
* @param minOffset the lowest offset in this overlay.
|
||||
* @param maxOffset the highest offset in this overlay.
|
||||
* @throws IOException
|
||||
*/
|
||||
void addOverlaySpace(OverlayAddressSpace ovSpace) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
table = db.createTable(TABLE_NAME, SCHEMA);
|
||||
}
|
||||
DBRecord rec = SCHEMA.createRecord(table.getKey());
|
||||
rec.setString(0, ovSpace.getName());
|
||||
rec.setString(1, ovSpace.getOverlayedSpace().getName());
|
||||
rec.setLongValue(OV_MIN_OFFSET_COL, ovSpace.getMinOffset());
|
||||
rec.setLongValue(OV_MAX_OFFSET_COL, ovSpace.getMaxOffset());
|
||||
table.putRecord(rec);
|
||||
ovSpace.setDatabaseKey(rec.getKey());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the named space from the database
|
||||
* @param name the name of the overlay space to remove
|
||||
* @throws IOException
|
||||
*/
|
||||
void removeOverlaySpace(String name) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String spaceName = rec.getString(0);
|
||||
if (name.equals(spaceName)) {
|
||||
it.delete();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void updateOverlaySpaces(ProgramAddressFactory factory) throws IOException {
|
||||
Map<Long, OverlayAddressSpace> map = new HashMap<>();
|
||||
for (AddressSpace space : factory.getAllAddressSpaces()) {
|
||||
if (space instanceof OverlayAddressSpace) {
|
||||
OverlayAddressSpace os = (OverlayAddressSpace) space;
|
||||
map.put(os.getDatabaseKey(), os);
|
||||
}
|
||||
}
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
OverlayAddressSpace space = map.remove(rec.getKey());
|
||||
if (space != null) {
|
||||
//maxId = Math.max(maxId, space.getUnique());
|
||||
String spaceName = rec.getString(OV_SPACE_NAME_COL);
|
||||
if (!spaceName.equals(space.getName())) {
|
||||
factory.removeOverlaySpace(space.getName());
|
||||
space.setName(rec.getString(OV_SPACE_NAME_COL));
|
||||
try {
|
||||
factory.addOverlayAddressSpace(space);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected error updating overlay address spaces", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
String spaceName = rec.getString(OV_SPACE_NAME_COL);
|
||||
long minOffset = rec.getLongValue(OV_MIN_OFFSET_COL);
|
||||
long maxOffset = rec.getLongValue(OV_MAX_OFFSET_COL);
|
||||
AddressSpace origSpace =
|
||||
factory.getAddressSpace(rec.getString(OV_SPACE_BASE_COL));
|
||||
try {
|
||||
space = factory.addOverlayAddressSpace(spaceName, true, origSpace,
|
||||
minOffset,
|
||||
maxOffset);
|
||||
space.setDatabaseKey(rec.getKey());
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected error updating overlay address spaces", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (OverlayAddressSpace space : map.values()) {
|
||||
factory.removeOverlaySpace(space.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public void renameOverlaySpace(String oldName, String newName) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String spaceName = rec.getString(0);
|
||||
if (oldName.equals(spaceName)) {
|
||||
it.delete();
|
||||
rec.setString(0, newName);
|
||||
table.putRecord(rec);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Translate overlay address spaces for a new language provider
|
||||
* and initialize the new addrFactory with the translated overlay spaces.
|
||||
* All non-overlay address spaces within the address factory should already
|
||||
* have been mapped to the new language.
|
||||
* @param newLanguage new language to be used
|
||||
* @param addrFactory old address factory
|
||||
* @param translator language translator to assist with mapping of address spaces
|
||||
* @throws IOException
|
||||
*/
|
||||
void setLanguage(Language newLanguage, ProgramAddressFactory addrFactory,
|
||||
LanguageTranslator translator) throws IOException {
|
||||
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String oldUnderlyingSpaceName = rec.getString(OV_SPACE_BASE_COL);
|
||||
AddressSpace space = addrFactory.getAddressSpace(oldUnderlyingSpaceName);
|
||||
if (space != null && space.isNonLoadedMemorySpace()) {
|
||||
// skip overlays associated with non-loaded spaces such as OTHER space
|
||||
continue;
|
||||
}
|
||||
AddressSpace newSpace = translator.getNewAddressSpace(oldUnderlyingSpaceName);
|
||||
if (newSpace == null) {
|
||||
throw new IOException(
|
||||
"Failed to map old address space: " + oldUnderlyingSpaceName);
|
||||
}
|
||||
rec.setString(OV_SPACE_BASE_COL, newSpace.getName());
|
||||
table.putRecord(rec);
|
||||
}
|
||||
}
|
||||
initializeOverlaySpaces(addrFactory);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.util.LanguageTranslator;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.*;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
abstract class OverlaySpaceDBAdapter {
|
||||
|
||||
// TODO: Duplication of address space names must be avoided. There is the possibility of
|
||||
// of a language change triggering such duplication with an existing overlay space.
|
||||
// Such a condition is currently unsupported and may cause severe errors.
|
||||
|
||||
static String TABLE_NAME = "Overlay Spaces";
|
||||
static final Schema SCHEMA = OverlaySpaceDBAdapterV1.SCHEMA_V1;
|
||||
static final int OV_SPACE_NAME_COL = OverlaySpaceDBAdapterV1.OV_SPACE_NAME_COL_V1;
|
||||
static final int OV_SPACE_BASE_COL = OverlaySpaceDBAdapterV1.OV_SPACE_BASE_COL_V1;
|
||||
|
||||
final DBHandle db;
|
||||
|
||||
OverlaySpaceDBAdapter(DBHandle dbHandle) {
|
||||
this.db = dbHandle;
|
||||
}
|
||||
|
||||
static OverlaySpaceDBAdapter getOverlaySpaceAdapter(DBHandle dbHandle, int openMode,
|
||||
TaskMonitor monitor) throws IOException, VersionException, CancelledException {
|
||||
try {
|
||||
return new OverlaySpaceDBAdapterV1(dbHandle, openMode);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
if (openMode == DBConstants.UPGRADE) {
|
||||
return upgrade(dbHandle, findReadOnlyAdapter(dbHandle), monitor);
|
||||
}
|
||||
if (e.isUpgradable() && openMode == DBConstants.READ_ONLY) {
|
||||
return findReadOnlyAdapter(dbHandle);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private static OverlaySpaceDBAdapter findReadOnlyAdapter(DBHandle handle)
|
||||
throws VersionException {
|
||||
|
||||
try {
|
||||
return new OverlaySpaceDBAdapterV0(handle);
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
// failed - can't handle whatever version this is trying to open
|
||||
}
|
||||
|
||||
throw new VersionException(false);
|
||||
}
|
||||
|
||||
private static OverlaySpaceDBAdapter upgrade(DBHandle dbHandle,
|
||||
OverlaySpaceDBAdapter oldAdapter, TaskMonitor monitor)
|
||||
throws VersionException, IOException, CancelledException {
|
||||
|
||||
monitor.setMessage("Upgrading Overlay Table...");
|
||||
monitor.initialize(oldAdapter.getRecordCount() * 2);
|
||||
|
||||
DBHandle tmpHandle = dbHandle.getScratchPad();
|
||||
|
||||
try {
|
||||
OverlaySpaceDBAdapter tmpAdapter =
|
||||
new OverlaySpaceDBAdapterV1(tmpHandle, DBConstants.CREATE);
|
||||
copyRecords(oldAdapter, tmpAdapter, monitor);
|
||||
|
||||
dbHandle.deleteTable(TABLE_NAME);
|
||||
|
||||
OverlaySpaceDBAdapter newAdapter =
|
||||
new OverlaySpaceDBAdapterV1(dbHandle, DBConstants.CREATE);
|
||||
copyRecords(tmpAdapter, newAdapter, monitor);
|
||||
|
||||
tmpHandle.deleteTable(TABLE_NAME);
|
||||
|
||||
return newAdapter;
|
||||
}
|
||||
finally {
|
||||
tmpHandle.deleteTable(TABLE_NAME);
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyRecords(OverlaySpaceDBAdapter fromAdapter,
|
||||
OverlaySpaceDBAdapter toAdapter, TaskMonitor monitor)
|
||||
throws IOException, CancelledException {
|
||||
|
||||
RecordIterator iter = fromAdapter.getOverlayRecords();
|
||||
while (iter.hasNext()) {
|
||||
monitor.checkCancelled();
|
||||
DBRecord rec = iter.next();
|
||||
toAdapter.updateOverlayRecord(rec);
|
||||
monitor.incrementProgress(1);
|
||||
}
|
||||
}
|
||||
|
||||
final int getRecordCount() {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
return table != null ? table.getRecordCount() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds existing overlay spaces to the factory.
|
||||
* @param factory the program address factory to add overlay spaces to
|
||||
* @throws IOException if database error occurs
|
||||
* @throws RuntimeException for various unsupported address space naming conditions
|
||||
*/
|
||||
final void initializeOverlaySpaces(ProgramAddressFactory factory) throws IOException {
|
||||
|
||||
RecordIterator it = getOverlayRecords();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
try {
|
||||
String spaceName = rec.getString(OV_SPACE_NAME_COL);
|
||||
if (factory.getAddressSpace(spaceName) != null) {
|
||||
throw new DuplicateNameException("Overlay space '" + spaceName +
|
||||
"' duplicates name of another address space");
|
||||
}
|
||||
|
||||
String baseSpaceName = rec.getString(OV_SPACE_BASE_COL);
|
||||
AddressSpace space = factory.getAddressSpace(baseSpaceName);
|
||||
if (space == null) {
|
||||
throw new RuntimeException("Overlay base space '" + baseSpaceName +
|
||||
"' not found for overlay space '" + spaceName + "'");
|
||||
}
|
||||
factory.addOverlaySpace(rec.getKey(), spaceName, space);
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IOException("Unexpected error initializing overlay address spaces", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide overlay space record iterator. Older adapters will must translate records into
|
||||
* the latest schema format.
|
||||
* @return overlay space record iterator
|
||||
* @throws IOException if database error occurs
|
||||
*/
|
||||
abstract RecordIterator getOverlayRecords() throws IOException;
|
||||
|
||||
/**
|
||||
* Update the overlay database table with the specified record
|
||||
* @param rec overlay record in latest schema format
|
||||
* @throws IOException if database error occurs
|
||||
*/
|
||||
abstract void updateOverlayRecord(DBRecord rec) throws IOException;
|
||||
|
||||
/**
|
||||
* Create a new overlay address space and associated record
|
||||
* @param factory program address factory which retains address spaces
|
||||
* @param overlayName overlay space name (may not contain `:`, space or other non-printable
|
||||
* characters.
|
||||
* @param baseSpace underlying physical/base address space which is to be overlayed
|
||||
* (must not be an overlay space)
|
||||
* @return new overlay space (without regions defined)
|
||||
* @throws IOException if database error occurs
|
||||
* @throws DuplicateNameException if overlay name duplicates another address space name
|
||||
* @throws InvalidNameException if specified overlay name is invalid
|
||||
*/
|
||||
abstract ProgramOverlayAddressSpace createOverlaySpace(ProgramAddressFactory factory,
|
||||
String overlayName, AddressSpace baseSpace)
|
||||
throws IOException, DuplicateNameException, InvalidNameException;
|
||||
|
||||
/**
|
||||
* Removes the named space from the database. Caller is responsible for updating address
|
||||
* factory.
|
||||
* @param name the name of the overlay space to remove
|
||||
* @return true if overlay record updated, false if not found
|
||||
* @throws IOException if database error occurs
|
||||
*/
|
||||
abstract boolean removeOverlaySpace(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Rename the overlay space from oldName to newName. Caller is responsible for updating
|
||||
* address factory and ensuring that newName does not duplicate that of another address space.
|
||||
* @param oldName old overlay name
|
||||
* @param newName new overlay name
|
||||
* @return true if overlay record updated, false if not found
|
||||
* @throws IOException if database error occurs
|
||||
*/
|
||||
abstract boolean renameOverlaySpace(String oldName, String newName) throws IOException;
|
||||
|
||||
/**
|
||||
* Reconcile overlay spaces following cache invalidation (e.g., undo/redo)
|
||||
* @param factory program address factory which retains address spaces
|
||||
* @throws IOException if database error occurs
|
||||
*/
|
||||
abstract void updateOverlaySpaces(ProgramAddressFactory factory) throws IOException;
|
||||
|
||||
/**
|
||||
* Translate overlay address spaces for a new language provider
|
||||
* and initialize the new addrFactory with the translated overlay spaces.
|
||||
* All non-overlay address spaces within the address factory should already
|
||||
* have been mapped to the new language.
|
||||
* @param newLanguage new language to be used
|
||||
* @param addrFactory old address factory
|
||||
* @param translator language translator to assist with mapping of address spaces
|
||||
* @throws IOException if database error occurs
|
||||
*/
|
||||
abstract void setLanguage(Language newLanguage, ProgramAddressFactory addrFactory,
|
||||
LanguageTranslator translator) throws IOException;
|
||||
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.help.UnsupportedOperationException;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.util.LanguageTranslator;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
class OverlaySpaceDBAdapterV0 extends OverlaySpaceDBAdapter {
|
||||
|
||||
private static final int VERSION = 0;
|
||||
|
||||
/* Do not remove the following commented out schema! It shows the version 0 overlay table schema. */
|
||||
// private static final Schema SCHEMA_V0 = new Schema(VERSION, "ID",
|
||||
// new Field[] { StringField.INSTANCE, StringField.INSTANCE, LongField.INSTANCE, LongField.INSTANCE },
|
||||
// new String[] { "Overlay Space Name", "Base Space Name", "Minimum Offset", "Maximum Offset" });
|
||||
|
||||
private static final int OV_SPACE_NAME_COL_V0 = 0;
|
||||
private static final int OV_SPACE_BASE_COL_V0 = 1;
|
||||
//private static final int OV_MIN_OFFSET_COL_V0 = 2; // OBSOLETE - Ignored
|
||||
//private static final int OV_MAX_OFFSET_COL_V0 = 3; // OBSOLETE - Ignored
|
||||
|
||||
private Table table;
|
||||
|
||||
OverlaySpaceDBAdapterV0(DBHandle dbHandle) throws VersionException {
|
||||
super(dbHandle);
|
||||
table = dbHandle.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
// Missing table case is OK but should be handled by latest version
|
||||
throw new VersionException("Missing Table: " + TABLE_NAME);
|
||||
}
|
||||
if (table.getSchema().getVersion() != VERSION) {
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
ProgramOverlayAddressSpace createOverlaySpace(ProgramAddressFactory factory, String blockName,
|
||||
AddressSpace baseSpace) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean removeOverlaySpace(String name) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean renameOverlaySpace(String oldName, String newName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateOverlayRecord(DBRecord rec) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateOverlaySpaces(ProgramAddressFactory factory) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
void setLanguage(Language newLanguage, ProgramAddressFactory addrFactory,
|
||||
LanguageTranslator translator) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
RecordIterator getOverlayRecords() throws IOException {
|
||||
return new V0ConvertedRecordIterator(table.iterator());
|
||||
}
|
||||
|
||||
private DBRecord convertV0Record(DBRecord v0Rec) {
|
||||
String overlayName = v0Rec.getString(OV_SPACE_NAME_COL_V0);
|
||||
String baseSpaceName = v0Rec.getString(OV_SPACE_BASE_COL_V0);
|
||||
|
||||
DBRecord rec = SCHEMA.createRecord(v0Rec.getKey());
|
||||
rec.setString(OV_SPACE_NAME_COL, overlayName);
|
||||
rec.setString(OV_SPACE_BASE_COL, baseSpaceName);
|
||||
return rec;
|
||||
}
|
||||
|
||||
private class V0ConvertedRecordIterator extends ConvertedRecordIterator {
|
||||
|
||||
V0ConvertedRecordIterator(RecordIterator originalIterator) {
|
||||
super(originalIterator, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DBRecord convertRecord(DBRecord record) {
|
||||
return convertV0Record(record);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,249 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import db.*;
|
||||
import ghidra.program.database.util.EmptyRecordIterator;
|
||||
import ghidra.program.model.address.AddressSpace;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.program.util.LanguageTranslator;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.VersionException;
|
||||
|
||||
class OverlaySpaceDBAdapterV1 extends OverlaySpaceDBAdapter {
|
||||
|
||||
private static final int VERSION = 1;
|
||||
|
||||
static final Schema SCHEMA_V1 =
|
||||
new Schema(VERSION, "ID", new Field[] { StringField.INSTANCE, StringField.INSTANCE },
|
||||
new String[] { "Overlay Space Name", "Base Space Name" });
|
||||
|
||||
static final int OV_SPACE_NAME_COL_V1 = 0;
|
||||
static final int OV_SPACE_BASE_COL_V1 = 1;
|
||||
|
||||
OverlaySpaceDBAdapterV1(DBHandle dbHandle, int openMode) throws IOException, VersionException {
|
||||
super(dbHandle);
|
||||
|
||||
Table table = dbHandle.getTable(TABLE_NAME);
|
||||
if (openMode == DBConstants.CREATE) {
|
||||
if (table != null) {
|
||||
throw new IOException("Table already exists: " + TABLE_NAME);
|
||||
}
|
||||
return; // lazy table creation
|
||||
}
|
||||
|
||||
if (table != null && table.getSchema().getVersion() != VERSION) {
|
||||
int version = table.getSchema().getVersion();
|
||||
if (version < VERSION) {
|
||||
throw new VersionException(true);
|
||||
}
|
||||
throw new VersionException(VersionException.NEWER_VERSION, false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
ProgramOverlayAddressSpace createOverlaySpace(ProgramAddressFactory factory, String spaceName,
|
||||
AddressSpace baseSpace)
|
||||
throws IOException, DuplicateNameException, InvalidNameException {
|
||||
|
||||
if (!factory.isValidOverlayBaseSpace(baseSpace)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid address space for overlay: " + baseSpace.getName());
|
||||
}
|
||||
|
||||
factory.checkValidOverlaySpaceName(spaceName);
|
||||
|
||||
if (factory.getAddressSpace(spaceName) != null) {
|
||||
throw new DuplicateNameException(
|
||||
"Overlay space '" + spaceName + "' duplicates name of another address space");
|
||||
}
|
||||
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
table = db.createTable(TABLE_NAME, SCHEMA_V1);
|
||||
}
|
||||
DBRecord rec = SCHEMA_V1.createRecord(table.getKey());
|
||||
rec.setString(OV_SPACE_NAME_COL_V1, spaceName);
|
||||
rec.setString(OV_SPACE_BASE_COL_V1, baseSpace.getName());
|
||||
table.putRecord(rec);
|
||||
|
||||
return factory.addOverlaySpace(rec.getKey(), spaceName, baseSpace);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected RecordIterator getOverlayRecords() throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
return EmptyRecordIterator.INSTANCE;
|
||||
}
|
||||
return table.iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateOverlayRecord(DBRecord rec) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
table = db.createTable(TABLE_NAME, SCHEMA_V1);
|
||||
}
|
||||
table.putRecord(rec);
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean removeOverlaySpace(String name) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String overlayName = rec.getString(0);
|
||||
if (name.equals(overlayName)) {
|
||||
it.delete();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean renameOverlaySpace(String oldName, String newName) throws IOException {
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String spaceName = rec.getString(0);
|
||||
if (oldName.equals(spaceName)) {
|
||||
it.delete();
|
||||
rec.setString(0, newName);
|
||||
table.putRecord(rec);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
void updateOverlaySpaces(ProgramAddressFactory factory) throws IOException {
|
||||
|
||||
// Perform reconciliation of overlay address spaces while attempting to preserve
|
||||
// address space instances associated with a given key
|
||||
|
||||
// Put all overlay records into key-based map
|
||||
Map<Long, DBRecord> keyToRecordMap = new HashMap<>();
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
keyToRecordMap.put(rec.getKey(), rec);
|
||||
}
|
||||
}
|
||||
|
||||
// Examine existing overlay spaces for removals and renames
|
||||
List<ProgramOverlayAddressSpace> renameList = new ArrayList<>();
|
||||
for (AddressSpace space : factory.getAllAddressSpaces()) {
|
||||
if (space instanceof ProgramOverlayAddressSpace os) {
|
||||
String name = os.getName();
|
||||
DBRecord rec = keyToRecordMap.get(os.getKey());
|
||||
if (rec == null || !isCompatibleOverlay(os, rec, factory)) {
|
||||
// Remove overlay if record does not exist or base space differs
|
||||
factory.removeOverlaySpace(name);
|
||||
}
|
||||
else if (name.equals(rec.getString(OV_SPACE_NAME_COL_V1))) {
|
||||
keyToRecordMap.remove(os.getKey());
|
||||
continue; // no change to space
|
||||
}
|
||||
else {
|
||||
// Add space to map of those that need to be renamed
|
||||
renameList.add(os);
|
||||
factory.removeOverlaySpace(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Handle all renamed overlays which had been temporarily removed from factory
|
||||
for (ProgramOverlayAddressSpace existingSpace : renameList) {
|
||||
long key = existingSpace.getKey();
|
||||
DBRecord rec = keyToRecordMap.get(key);
|
||||
existingSpace.setName(rec.getString(OV_SPACE_NAME_COL_V1));
|
||||
factory.addOverlaySpace(existingSpace); // re-add renamed space
|
||||
keyToRecordMap.remove(key);
|
||||
}
|
||||
|
||||
// Add any remaing overlay which are missing from factory
|
||||
for (long key : keyToRecordMap.keySet()) {
|
||||
DBRecord rec = keyToRecordMap.get(key);
|
||||
String spaceName = rec.getString(OV_SPACE_NAME_COL_V1);
|
||||
AddressSpace baseSpace =
|
||||
factory.getAddressSpace(rec.getString(OV_SPACE_BASE_COL_V1));
|
||||
factory.addOverlaySpace(key, spaceName, baseSpace);
|
||||
}
|
||||
}
|
||||
catch (IllegalArgumentException | DuplicateNameException e) {
|
||||
throw new AssertionError("Unexpected error updating overlay address spaces", e);
|
||||
}
|
||||
|
||||
factory.refreshStaleOverlayStatus();
|
||||
}
|
||||
|
||||
private boolean isCompatibleOverlay(ProgramOverlayAddressSpace os, DBRecord rec,
|
||||
ProgramAddressFactory factory) throws IOException {
|
||||
String baseSpaceName = rec.getString(OV_SPACE_BASE_COL_V1);
|
||||
AddressSpace baseSpace = factory.getAddressSpace(baseSpaceName);
|
||||
if (baseSpace == null) {
|
||||
throw new IOException("Base space for overlay not found: " + baseSpaceName);
|
||||
}
|
||||
return baseSpace == os.getOverlayedSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
void setLanguage(Language newLanguage, ProgramAddressFactory addrFactory,
|
||||
LanguageTranslator translator) throws IOException {
|
||||
|
||||
Table table = db.getTable(TABLE_NAME);
|
||||
if (table != null) {
|
||||
RecordIterator it = table.iterator();
|
||||
while (it.hasNext()) {
|
||||
DBRecord rec = it.next();
|
||||
String oldUnderlyingSpaceName = rec.getString(OV_SPACE_BASE_COL_V1);
|
||||
AddressSpace space = addrFactory.getAddressSpace(oldUnderlyingSpaceName);
|
||||
if (space != null && space.isNonLoadedMemorySpace()) {
|
||||
// skip overlays associated with non-loaded spaces such as OTHER space
|
||||
continue;
|
||||
}
|
||||
AddressSpace newSpace = translator.getNewAddressSpace(oldUnderlyingSpaceName);
|
||||
if (newSpace == null) {
|
||||
throw new IOException(
|
||||
"Failed to map old address space: " + oldUnderlyingSpaceName);
|
||||
}
|
||||
rec.setString(OV_SPACE_BASE_COL_V1, newSpace.getName());
|
||||
table.putRecord(rec);
|
||||
}
|
||||
}
|
||||
initializeOverlaySpaces(addrFactory);
|
||||
}
|
||||
}
|
|
@ -18,18 +18,42 @@ package ghidra.program.database;
|
|||
import ghidra.program.model.address.*;
|
||||
import ghidra.program.model.lang.CompilerSpec;
|
||||
import ghidra.program.model.lang.Language;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class ProgramAddressFactory extends DefaultAddressFactory {
|
||||
|
||||
protected final OverlayRegionSupplier overlayRegionSupplier;
|
||||
|
||||
private AddressFactory originalFactory;
|
||||
private AddressSpace stackSpace;
|
||||
private boolean hasStaleOverlays = false;
|
||||
private long nextTmpId = 1; // used for overlay naming
|
||||
|
||||
public ProgramAddressFactory(Language language, CompilerSpec compilerSpec) {
|
||||
/**
|
||||
* Construct a Program address factory which augments the {@link DefaultAddressFactory}
|
||||
* supplied by a {@link Language}. The following additional address spaces are added:
|
||||
* <ul>
|
||||
* <li>{@link AddressSpace#OTHER_SPACE}</li>
|
||||
* <li>{@link AddressSpace#EXTERNAL_SPACE}</li>
|
||||
* <li>A stack space (see {@link AddressSpace#TYPE_STACK})</li>
|
||||
* <li>{@link AddressSpace#HASH_SPACE}</li>
|
||||
* <li>A join space (see {@link AddressSpace#TYPE_JOIN})</li>
|
||||
* </ol>
|
||||
* In addition, support is provided for {@link ProgramOverlayAddressSpace}.
|
||||
* @param language language specification
|
||||
* @param compilerSpec compiler specification
|
||||
* @param overlayRegionSupplier overlay space defined region supplier which will be invoked when
|
||||
* specific queries are performed on overlay address spaces. If memory is not yet available
|
||||
* a null AddressSet may be returned by the supplier.
|
||||
*/
|
||||
public ProgramAddressFactory(Language language, CompilerSpec compilerSpec,
|
||||
OverlayRegionSupplier overlayRegionSupplier) {
|
||||
super(language.getAddressFactory().getAllAddressSpaces(),
|
||||
language.getAddressFactory().getDefaultAddressSpace());
|
||||
this.originalFactory = language.getAddressFactory();
|
||||
this.overlayRegionSupplier = overlayRegionSupplier;
|
||||
initOtherSpace(language);
|
||||
initExternalSpace(language);
|
||||
initStackSpace(language, compilerSpec);
|
||||
|
@ -37,6 +61,14 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
|||
initJoinSpace(language);
|
||||
}
|
||||
|
||||
public void invalidateOverlayCache() {
|
||||
for (AddressSpace space : getAddressSpaces()) {
|
||||
if (space instanceof ProgramOverlayAddressSpace os) {
|
||||
os.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initOtherSpace(Language language) {
|
||||
try {
|
||||
addAddressSpace(AddressSpace.OTHER_SPACE);
|
||||
|
@ -97,145 +129,68 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
|||
return originalFactory;
|
||||
}
|
||||
|
||||
protected void addOverlayAddressSpace(OverlayAddressSpace ovSpace)
|
||||
throws DuplicateNameException {
|
||||
addAddressSpace(ovSpace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given space can have an overlay
|
||||
*
|
||||
* @param originalSpace the original space
|
||||
* @param baseSpace the overlay base address space
|
||||
* @return true to allow, false to prohibit
|
||||
*/
|
||||
protected boolean validateOriginalSpace(AddressSpace originalSpace) {
|
||||
return originalSpace.isMemorySpace() && !originalSpace.isOverlaySpace();
|
||||
protected boolean isValidOverlayBaseSpace(AddressSpace baseSpace) {
|
||||
if (baseSpace != getAddressSpace(baseSpace.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean assignUniqueID(AddressSpace originalSpace) {
|
||||
return originalSpace.getType() == AddressSpace.TYPE_RAM ||
|
||||
originalSpace.getType() == AddressSpace.TYPE_OTHER;
|
||||
return baseSpace.isMemorySpace() && !baseSpace.isOverlaySpace();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OverlayAddressSpace based upon the given overlay blockName and base AddressSpace
|
||||
*
|
||||
* @param name the preferred name of the overlay address space to be created. This name may be
|
||||
* modified if preserveName is false to produce a valid overlay space name and avoid
|
||||
* duplication.
|
||||
* @param preserveName if true specified name will be preserved, if false an unique acceptable
|
||||
* overlay space name will be generated from the specified name.
|
||||
* @param originalSpace the base AddressSpace to overlay
|
||||
* @param minOffset the min offset of the space
|
||||
* @param maxOffset the max offset of the space
|
||||
* @return the new overlay space
|
||||
* @throws IllegalArgumentException if originalSpace is not permitted or preserveName is true
|
||||
* and a space with specified name already exists.
|
||||
* Add an overlay address space to this factory
|
||||
* @param ovSpace overlay space
|
||||
* @throws DuplicateNameException if name of overlay space already exists in this factory
|
||||
*/
|
||||
protected OverlayAddressSpace addOverlayAddressSpace(String name, boolean preserveName,
|
||||
AddressSpace originalSpace, long minOffset, long maxOffset) {
|
||||
|
||||
if (!validateOriginalSpace(originalSpace)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid address space for overlay: " + originalSpace.getName());
|
||||
protected void addOverlaySpace(ProgramOverlayAddressSpace ovSpace)
|
||||
throws DuplicateNameException {
|
||||
if (!ovSpace.getOrderedKey().equals(ovSpace.getName())) {
|
||||
hasStaleOverlays = true;
|
||||
}
|
||||
AddressSpace space = getAddressSpace(originalSpace.getName());
|
||||
if (space != originalSpace) {
|
||||
throw new IllegalArgumentException("Unknown memory address space instance");
|
||||
}
|
||||
|
||||
String spaceName = name;
|
||||
if (!preserveName) {
|
||||
spaceName = fixupOverlaySpaceName(name);
|
||||
spaceName = getUniqueOverlayName(spaceName);
|
||||
}
|
||||
else if (getAddressSpace(name) != null) { // check before allocating unique ID
|
||||
throw new IllegalArgumentException("Space named " + name + " already exists!");
|
||||
}
|
||||
|
||||
int unique = 0;
|
||||
if (assignUniqueID(originalSpace)) {
|
||||
unique = getNextUniqueID();
|
||||
}
|
||||
|
||||
OverlayAddressSpace ovSpace =
|
||||
new OverlayAddressSpace(spaceName, originalSpace, unique, minOffset, maxOffset);
|
||||
try {
|
||||
addAddressSpace(ovSpace);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new RuntimeException(e); // unexpected
|
||||
}
|
||||
return ovSpace;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique address space name based on the specified baseOverlayName
|
||||
*
|
||||
* @param baseOverlayName base overlay address space name
|
||||
* @return unique overlay space name
|
||||
* Create a new ProgramOverlayAddressSpace based upon the given overlay blockName and base AddressSpace
|
||||
* @param key overlay record key
|
||||
* @param overlayName overlay name
|
||||
* @param baseSpace the base AddressSpace to overlay
|
||||
* @return the new overlay space
|
||||
* @throws DuplicateNameException if overlay name duplicates another address space name
|
||||
* @throws IllegalArgumentException if baseSpace is not permitted or not found.
|
||||
*/
|
||||
private String getUniqueOverlayName(String baseOverlayName) {
|
||||
if (getAddressSpace(baseOverlayName) == null) {
|
||||
return baseOverlayName;
|
||||
}
|
||||
int index = 1;
|
||||
while (true) {
|
||||
String revisedName = baseOverlayName + "." + index++;
|
||||
if (getAddressSpace(revisedName) == null) {
|
||||
return revisedName;
|
||||
}
|
||||
}
|
||||
protected ProgramOverlayAddressSpace addOverlaySpace(long key, String overlayName,
|
||||
AddressSpace baseSpace) throws DuplicateNameException {
|
||||
|
||||
if (!isValidOverlayBaseSpace(baseSpace)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid base space for overlay: " + baseSpace.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get base overlay name removing any numeric suffix which may have been added to avoid
|
||||
* duplication. This method is intended to be used during rename only.
|
||||
*
|
||||
* @param overlayName existing overlay space name
|
||||
* @return base overlay name with any trailing index removed which may have been added to avoid
|
||||
* duplication.
|
||||
*/
|
||||
private String getBaseOverlayName(String overlayName) {
|
||||
int index = overlayName.lastIndexOf('.');
|
||||
if (index < 1) {
|
||||
return overlayName;
|
||||
}
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt(overlayName.substring(index + 1));
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
return overlayName;
|
||||
}
|
||||
if (value < 1) {
|
||||
return overlayName;
|
||||
}
|
||||
String baseName = overlayName.substring(0, index);
|
||||
return overlayName.equals(baseName + '.' + value) ? baseName : overlayName;
|
||||
AddressSpace space = getAddressSpace(baseSpace.getName());
|
||||
if (space != baseSpace) {
|
||||
throw new IllegalArgumentException("Invalid memory address space instance");
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an allowed address space name from a block name. Use of unsupported characters will
|
||||
* be converted to underscore (includes colon and all whitespace chars). double-underscore to
|
||||
* ensure uniqueness.
|
||||
*
|
||||
* @param blockName corresponding memory block name
|
||||
* @return overlay space name
|
||||
*/
|
||||
private String fixupOverlaySpaceName(String blockName) {
|
||||
int len = blockName.length();
|
||||
StringBuffer buf = new StringBuffer(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = blockName.charAt(i);
|
||||
if (c == ':' || c <= 0x20) {
|
||||
buf.append('_');
|
||||
return new ProgramOverlayAddressSpace(key, overlayName, baseSpace, getNextUniqueID(),
|
||||
overlayRegionSupplier, this);
|
||||
}
|
||||
else {
|
||||
buf.append(c);
|
||||
|
||||
public void checkValidOverlaySpaceName(String name)
|
||||
throws InvalidNameException, DuplicateNameException {
|
||||
|
||||
if (!AddressSpace.isValidName(name)) {
|
||||
throw new InvalidNameException("Invalid overlay space name: " + name);
|
||||
}
|
||||
|
||||
if (getAddressSpace(name) != null) {
|
||||
throw new DuplicateNameException("Duplicate address space name: " + name);
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -266,31 +221,28 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
|||
return addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove an overlay space.
|
||||
* It may be neccessary to invoke {@link #refreshStaleOverlayStatus()} when an overlay is
|
||||
* removed.
|
||||
* @param name overlay space name
|
||||
*/
|
||||
protected void removeOverlaySpace(String name) {
|
||||
AddressSpace space = getAddressSpace(name);
|
||||
if (!(space instanceof ProgramOverlayAddressSpace)) {
|
||||
throw new IllegalArgumentException("Overlay " + name + " not found");
|
||||
}
|
||||
removeAddressSpace(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename overlay with preferred newName. Actual name used will be returned and may differ from
|
||||
* specified newName to ensure validity and avoid duplication.
|
||||
*
|
||||
* @param oldOverlaySpaceName the existing overlay address space name
|
||||
* @param newName the preferred new name of the overlay address space. This name may be modified
|
||||
* to produce a valid overlay space name to avoid duplication.
|
||||
* @return new name applied to existing overlay space
|
||||
*/
|
||||
@Override
|
||||
protected String renameOverlaySpace(String oldOverlaySpaceName, String newName) {
|
||||
try {
|
||||
String revisedName = fixupOverlaySpaceName(newName);
|
||||
if (revisedName.equals(getBaseOverlayName(oldOverlaySpaceName))) {
|
||||
return oldOverlaySpaceName;
|
||||
protected void overlaySpaceRenamed(String oldOverlaySpaceName, String newName,
|
||||
boolean refreshStatusIfNeeded) {
|
||||
OverlayAddressSpace os = super.overlaySpaceRenamed(oldOverlaySpaceName, newName);
|
||||
if (!newName.equals(os.getOrderedKey())) {
|
||||
hasStaleOverlays = true;
|
||||
}
|
||||
revisedName = getUniqueOverlayName(revisedName);
|
||||
return super.renameOverlaySpace(oldOverlaySpaceName, revisedName);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
throw new RuntimeException(e); // unexpected
|
||||
else if (hasStaleOverlays && refreshStatusIfNeeded) {
|
||||
refreshStaleOverlayStatus(); // must check all overlays to determine status
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -302,4 +254,43 @@ public class ProgramAddressFactory extends DefaultAddressFactory {
|
|||
}
|
||||
return maxID + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine all overlay spaces and update the stale status indicator
|
||||
* (see {@link #hasStaleOverlays}).
|
||||
*/
|
||||
protected void refreshStaleOverlayStatus() {
|
||||
hasStaleOverlays = false;
|
||||
for (AddressSpace space : getAddressSpaces()) {
|
||||
if (space instanceof ProgramOverlayAddressSpace os) {
|
||||
if (!os.getName().equals(os.getOrderedKey())) {
|
||||
hasStaleOverlays = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStaleOverlayCondition() {
|
||||
return hasStaleOverlays;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an ordered unique name-based key for use with overlay spaces.
|
||||
* This will generally be the overlay name unless that value has already been utilized by
|
||||
* another overlay.
|
||||
* @param overlayName overlay name
|
||||
* @return ordered key to be used
|
||||
*/
|
||||
synchronized String generateOrderedKey(String overlayName) {
|
||||
for (AddressSpace space : getAddressSpaces()) {
|
||||
if (space instanceof ProgramOverlayAddressSpace os) {
|
||||
if (overlayName.equals(os.getOrderedKey())) {
|
||||
return overlayName + Address.SEPARATOR + nextTmpId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return overlayName;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -51,7 +51,6 @@ import ghidra.program.model.data.CategoryPath;
|
|||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.*;
|
||||
import ghidra.program.model.mem.MemoryBlock;
|
||||
import ghidra.program.model.mem.MemoryConflictException;
|
||||
import ghidra.program.model.pcode.Varnode;
|
||||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
|
@ -109,10 +108,12 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
* property map (StringTranslations).
|
||||
* 19-Jan-2023 - version 26 Improved relocation data records to incorporate status and
|
||||
* byte-length when original FileBytes should be used.
|
||||
* 10-Jul-2023 - VERSION 27 Add support for Instruction length override which utilizes
|
||||
* 10-Jul-2023 - version 27 Add support for Instruction length override which utilizes
|
||||
* unused flag bits.
|
||||
* 19-Oct-2023 - version 28 Revised overlay address space table and eliminated min/max.
|
||||
* Multiple blocks are permitted within a single overlay space.
|
||||
*/
|
||||
static final int DB_VERSION = 27;
|
||||
static final int DB_VERSION = 28;
|
||||
|
||||
/**
|
||||
* UPGRADE_REQUIRED_BFORE_VERSION should be changed to DB_VERSION anytime the
|
||||
|
@ -211,7 +212,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
private Address effectiveImageBase = null;
|
||||
private boolean recordChanges;
|
||||
|
||||
private OverlaySpaceAdapterDB overlaySpaceAdapter;
|
||||
private OverlaySpaceDBAdapter overlaySpaceAdapter;
|
||||
|
||||
private Map<String, AddressSetPropertyMapDB> addrSetPropertyMap = new HashMap<>();
|
||||
private Map<String, IntRangeMapDB> intRangePropertyMap = new HashMap<>();
|
||||
|
@ -246,7 +247,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
languageVersion = language.getVersion();
|
||||
languageMinorVersion = language.getMinorVersion();
|
||||
|
||||
addressFactory = new ProgramAddressFactory(language, compilerSpec);
|
||||
addressFactory =
|
||||
new ProgramAddressFactory(language, compilerSpec, s -> getDefinedAddressSet(s));
|
||||
|
||||
recordChanges = false;
|
||||
boolean success = false;
|
||||
|
@ -339,7 +341,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
|
||||
initCompilerSpec();
|
||||
|
||||
addressFactory = new ProgramAddressFactory(language, compilerSpec);
|
||||
addressFactory =
|
||||
new ProgramAddressFactory(language, compilerSpec, s -> getDefinedAddressSet(s));
|
||||
|
||||
VersionException versionExc = createManagers(openMode, monitor);
|
||||
if (dbVersionExc != null) {
|
||||
|
@ -378,6 +381,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
}
|
||||
languageUpgradeRequired = false;
|
||||
}
|
||||
addressFactory.invalidateOverlayCache();
|
||||
postUpgrade(oldVersion, monitor);
|
||||
changed = true;
|
||||
}
|
||||
|
@ -404,6 +408,14 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
ProgramUtilities.addTrackedProgram(this);
|
||||
}
|
||||
|
||||
private AddressSetView getDefinedAddressSet(AddressSpace s) {
|
||||
MemoryMapDB memory = getMemory();
|
||||
if (memory != null) {
|
||||
return memory.intersectRange(s.getMinAddress(), s.getMaxAddress());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if program initialization requires a language upgrade
|
||||
* @return true if language upgrade is pending
|
||||
|
@ -741,7 +753,7 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
}
|
||||
|
||||
@Override
|
||||
public AddressFactory getAddressFactory() {
|
||||
public ProgramAddressFactory getAddressFactory() {
|
||||
return addressFactory;
|
||||
}
|
||||
|
||||
|
@ -1183,33 +1195,29 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new OverlayAddressSpace based upon the given overlay blockName and base AddressSpace
|
||||
* @param blockName the name of the overlay memory block which corresponds to the new overlay address
|
||||
* space to be created. This name may be modified to produce a valid overlay space name and avoid
|
||||
* duplication.
|
||||
* @param originalSpace the base AddressSpace to overlay
|
||||
* @param minOffset the min offset of the space
|
||||
* @param maxOffset the max offset of the space
|
||||
* @return the new space
|
||||
* @throws LockException if the program is shared and not checked out exclusively.
|
||||
* @throws MemoryConflictException if image base override is active
|
||||
*/
|
||||
public AddressSpace addOverlaySpace(String blockName, AddressSpace originalSpace,
|
||||
long minOffset, long maxOffset) throws LockException, MemoryConflictException {
|
||||
@Override
|
||||
public ProgramOverlayAddressSpace createOverlaySpace(String overlaySpaceName,
|
||||
AddressSpace baseSpace) throws IllegalStateException, DuplicateNameException,
|
||||
InvalidNameException, LockException {
|
||||
|
||||
checkExclusiveAccess();
|
||||
if (imageBaseOverride) {
|
||||
throw new MemoryConflictException(
|
||||
"Overlay spaces may not be created while an image-base override is active");
|
||||
|
||||
if (!addressFactory.isValidOverlayBaseSpace(baseSpace)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid address space for overlay: " + baseSpace.getName());
|
||||
}
|
||||
|
||||
OverlayAddressSpace ovSpace = null;
|
||||
ProgramOverlayAddressSpace ovSpace = null;
|
||||
lock.acquire();
|
||||
try {
|
||||
ovSpace = addressFactory.addOverlayAddressSpace(blockName, false, originalSpace,
|
||||
minOffset, maxOffset);
|
||||
overlaySpaceAdapter.addOverlaySpace(ovSpace);
|
||||
if (imageBaseOverride) {
|
||||
throw new IllegalStateException(
|
||||
"Overlay spaces may not be created while an image-base override is active");
|
||||
}
|
||||
ovSpace =
|
||||
overlaySpaceAdapter.createOverlaySpace(addressFactory, overlaySpaceName, baseSpace);
|
||||
|
||||
setChanged(ChangeManager.DOCR_OVERLAY_SPACE_ADDED, overlaySpaceName, null);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
|
@ -1220,35 +1228,61 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
return ovSpace;
|
||||
}
|
||||
|
||||
public void renameOverlaySpace(String oldOverlaySpaceName, String newName)
|
||||
throws LockException {
|
||||
checkExclusiveAccess();
|
||||
String revisedName = addressFactory.renameOverlaySpace(oldOverlaySpaceName, newName);
|
||||
if (!revisedName.equals(oldOverlaySpaceName)) {
|
||||
@Override
|
||||
public void renameOverlaySpace(String overlaySpaceName, String newName)
|
||||
throws NotFoundException, InvalidNameException, DuplicateNameException, LockException {
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
overlaySpaceAdapter.renameOverlaySpace(oldOverlaySpaceName, revisedName);
|
||||
addrMap.renameOverlaySpace(oldOverlaySpaceName, revisedName);
|
||||
checkExclusiveAccess();
|
||||
|
||||
AddressSpace space = addressFactory.getAddressSpace(overlaySpaceName);
|
||||
if (space == null || !(space instanceof ProgramOverlayAddressSpace os)) {
|
||||
throw new NotFoundException("Overlay " + overlaySpaceName + " not found");
|
||||
}
|
||||
|
||||
addressFactory.checkValidOverlaySpaceName(newName);
|
||||
|
||||
if (overlaySpaceAdapter.renameOverlaySpace(overlaySpaceName, newName)) {
|
||||
os.setName(newName);
|
||||
addressFactory.overlaySpaceRenamed(overlaySpaceName, newName, true);
|
||||
addrMap.renameOverlaySpace(overlaySpaceName, newName);
|
||||
clearCache(true);
|
||||
setChanged(ChangeManager.DOCR_OVERLAY_SPACE_RENAMED, overlaySpaceName, newName);
|
||||
fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
finally {
|
||||
lock.release();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean removeOverlaySpace(AddressSpace overlaySpace) throws LockException {
|
||||
@Override
|
||||
public boolean removeOverlaySpace(String overlaySpaceName)
|
||||
throws LockException, NotFoundException {
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
checkExclusiveAccess();
|
||||
MemoryBlock[] blocks = memoryManager.getBlocks();
|
||||
for (MemoryBlock block : blocks) {
|
||||
if (block.getStart().getAddressSpace().equals(overlaySpace)) {
|
||||
return false;
|
||||
|
||||
AddressSpace space = addressFactory.getAddressSpace(overlaySpaceName);
|
||||
if (space == null || !(space instanceof ProgramOverlayAddressSpace os)) {
|
||||
throw new NotFoundException("Overlay " + overlaySpaceName + " not found");
|
||||
}
|
||||
|
||||
if (!os.getOverlayAddressSet().isEmpty()) {
|
||||
return false; // memory blocks are still defined
|
||||
}
|
||||
addressFactory.removeOverlaySpace(overlaySpace.getName());
|
||||
overlaySpaceAdapter.removeOverlaySpace(overlaySpace.getName());
|
||||
addrMap.deleteOverlaySpace(overlaySpace.getName());
|
||||
|
||||
addressFactory.removeOverlaySpace(overlaySpaceName);
|
||||
overlaySpaceAdapter.removeOverlaySpace(overlaySpaceName);
|
||||
addrMap.deleteOverlaySpace(overlaySpaceName);
|
||||
clearCache(true);
|
||||
setChanged(ChangeManager.DOCR_OVERLAY_SPACE_REMOVED, overlaySpaceName, null);
|
||||
fireEvent(new DomainObjectChangeRecord(DomainObject.DO_OBJECT_RESTORED));
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
|
@ -1589,7 +1623,25 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
throws CancelledException, IOException {
|
||||
|
||||
VersionException versionExc = null;
|
||||
overlaySpaceAdapter = new OverlaySpaceAdapterDB(dbh);
|
||||
try {
|
||||
overlaySpaceAdapter =
|
||||
OverlaySpaceDBAdapter.getOverlaySpaceAdapter(dbh, openMode, monitor);
|
||||
}
|
||||
catch (VersionException e) {
|
||||
versionExc = e.combine(versionExc);
|
||||
try {
|
||||
overlaySpaceAdapter =
|
||||
OverlaySpaceDBAdapter.getOverlaySpaceAdapter(dbh, READ_ONLY, monitor);
|
||||
}
|
||||
catch (VersionException e1) {
|
||||
if (e1.isUpgradable()) {
|
||||
throw new RuntimeException(
|
||||
"OverlaySpaceDBAdapter is supported but failed to open as READ-ONLY!");
|
||||
}
|
||||
// Unable to proceed without overlay space adapter !
|
||||
return versionExc;
|
||||
}
|
||||
}
|
||||
overlaySpaceAdapter.initializeOverlaySpaces(addressFactory);
|
||||
monitor.checkCancelled();
|
||||
|
||||
|
@ -2047,7 +2099,8 @@ public class ProgramDB extends DomainObjectAdapterDB implements Program, ChangeM
|
|||
languageMinorVersion = language.getMinorVersion();
|
||||
|
||||
if (translator != null) {
|
||||
addressFactory = new ProgramAddressFactory(language, compilerSpec);
|
||||
addressFactory = new ProgramAddressFactory(language, compilerSpec,
|
||||
s -> getDefinedAddressSet(s));
|
||||
|
||||
addrMap.setLanguage(language, addressFactory, translator);
|
||||
overlaySpaceAdapter.setLanguage(language, addressFactory, translator);
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
/* ###
|
||||
* 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.program.database;
|
||||
|
||||
import ghidra.program.model.address.*;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
|
||||
public class ProgramOverlayAddressSpace extends OverlayAddressSpace {
|
||||
|
||||
private final long key;
|
||||
private final OverlayRegionSupplier overlayRegionSupplier;
|
||||
|
||||
private String overlayName;
|
||||
|
||||
private AddressSetView overlaySet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param key DB record key
|
||||
* @param overlayName current overlay name
|
||||
* @param baseSpace base address space (type should be restricted as neccessary by caller)
|
||||
* @param unique assigned unique ID
|
||||
* @param overlayRegionSupplier callback handler which supplies the defined address set
|
||||
* for a specified overlay address space.
|
||||
* @param factory used to determine a suitable ordered overlay ordered-key used for
|
||||
* {@link #equals(Object)} and {@link #compareTo(AddressSpace)}.
|
||||
* @throws DuplicateNameException if specified name duplicates an existing address space name
|
||||
*/
|
||||
public ProgramOverlayAddressSpace(long key, String overlayName, AddressSpace baseSpace,
|
||||
int unique, OverlayRegionSupplier overlayRegionSupplier, ProgramAddressFactory factory)
|
||||
throws DuplicateNameException {
|
||||
super(baseSpace, unique, factory.generateOrderedKey(overlayName));
|
||||
this.key = key;
|
||||
this.overlayName = overlayName;
|
||||
this.overlayRegionSupplier = overlayRegionSupplier;
|
||||
factory.addOverlaySpace(this);
|
||||
}
|
||||
|
||||
protected synchronized void invalidate() {
|
||||
overlaySet = null;
|
||||
}
|
||||
|
||||
private void validate() {
|
||||
if (overlaySet == null) {
|
||||
overlaySet =
|
||||
overlayRegionSupplier != null ? overlayRegionSupplier.getOverlayAddressSet(this)
|
||||
: new AddressSet();
|
||||
if (overlaySet == null) {
|
||||
overlaySet = new AddressSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DB record key used to store this overlay specification.
|
||||
* This is intended to be used internally to reconcile address spaces only.
|
||||
* @return DB record key
|
||||
*/
|
||||
public long getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return overlayName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to support renaming an overlay address space instance. Intended for internal use only.
|
||||
* @param name new overlay space name
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.overlayName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean contains(long offset) {
|
||||
try {
|
||||
Address addr = getAddressInThisSpaceOnly(makeValidOffset(offset));
|
||||
return getOverlayAddressSet().contains(addr);
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized AddressSetView getOverlayAddressSet() {
|
||||
validate();
|
||||
return overlaySet;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,7 +24,6 @@ import ghidra.framework.store.FileSystem;
|
|||
import ghidra.program.database.map.AddressMapDB;
|
||||
import ghidra.program.database.properties.*;
|
||||
import ghidra.program.model.address.Address;
|
||||
import ghidra.program.model.address.AddressFactory;
|
||||
import ghidra.program.model.lang.*;
|
||||
import ghidra.program.model.listing.ProgramUserData;
|
||||
import ghidra.program.model.util.*;
|
||||
|
@ -102,7 +101,7 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
private int languageVersion;
|
||||
private Language language;
|
||||
private LanguageTranslator languageUpgradeTranslator;
|
||||
private AddressFactory addressFactory;
|
||||
private ProgramAddressFactory addressFactory;
|
||||
private HashMap<Long, PropertyMap<?>> propertyMaps = new HashMap<Long, PropertyMap<?>>();
|
||||
private HashSet<String> propertyMapOwners = null;
|
||||
|
||||
|
@ -126,7 +125,7 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
languageID = language.getLanguageID();
|
||||
languageVersion = language.getVersion();
|
||||
|
||||
addressFactory = language.getAddressFactory();
|
||||
addressFactory = program.getAddressFactory();
|
||||
|
||||
setEventsEnabled(false); // events not support
|
||||
|
||||
|
@ -184,7 +183,7 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
languageVersionExc = checkForLanguageChange(e);
|
||||
}
|
||||
|
||||
addressFactory = language.getAddressFactory();
|
||||
addressFactory = program.getAddressFactory();
|
||||
|
||||
VersionException versionExc = createManagers(UPGRADE, program, monitor);
|
||||
if (dbVersionExc != null) {
|
||||
|
@ -238,8 +237,7 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
Language newLanguage = language;
|
||||
|
||||
Language oldLanguage = OldLanguageFactory.getOldLanguageFactory()
|
||||
.getOldLanguage(
|
||||
languageID, languageVersion);
|
||||
.getOldLanguage(languageID, languageVersion);
|
||||
if (oldLanguage == null) {
|
||||
// Assume minor version behavior - old language does not exist for current major version
|
||||
Msg.error(this, "Old language specification not found: " + languageID +
|
||||
|
@ -248,10 +246,8 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
}
|
||||
|
||||
// Ensure that we can upgrade the language
|
||||
languageUpgradeTranslator =
|
||||
LanguageTranslatorFactory.getLanguageTranslatorFactory()
|
||||
.getLanguageTranslator(
|
||||
oldLanguage, newLanguage);
|
||||
languageUpgradeTranslator = LanguageTranslatorFactory.getLanguageTranslatorFactory()
|
||||
.getLanguageTranslator(oldLanguage, newLanguage);
|
||||
if (languageUpgradeTranslator == null) {
|
||||
throw new LanguageNotFoundException(language.getLanguageID(),
|
||||
"(Ver " + languageVersion + ".x" + " -> " + newLanguage.getVersion() + "." +
|
||||
|
@ -278,10 +274,8 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
private VersionException checkForLanguageChange(LanguageNotFoundException e)
|
||||
throws LanguageNotFoundException {
|
||||
|
||||
languageUpgradeTranslator =
|
||||
LanguageTranslatorFactory.getLanguageTranslatorFactory()
|
||||
.getLanguageTranslator(
|
||||
languageID, languageVersion);
|
||||
languageUpgradeTranslator = LanguageTranslatorFactory.getLanguageTranslatorFactory()
|
||||
.getLanguageTranslator(languageID, languageVersion);
|
||||
if (languageUpgradeTranslator == null) {
|
||||
throw e;
|
||||
}
|
||||
|
@ -428,7 +422,8 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
languageID = language.getLanguageID();
|
||||
languageVersion = language.getVersion();
|
||||
|
||||
addressFactory = language.getAddressFactory();
|
||||
// AddressFactory need not change since we are using the instance from the
|
||||
// Program which would have already been subject to an upgrade
|
||||
addressMap.setLanguage(language, addressFactory, translator);
|
||||
|
||||
clearCache(true);
|
||||
|
@ -528,31 +523,26 @@ class ProgramUserDataDB extends DomainObjectAdapterDB implements ProgramUserData
|
|||
switch (type) {
|
||||
case PROPERTY_TYPE_STRING:
|
||||
map = new StringPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr,
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL),
|
||||
TaskMonitor.DUMMY);
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
break;
|
||||
case PROPERTY_TYPE_LONG:
|
||||
map =
|
||||
new LongPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr, addressMap,
|
||||
rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
map = new LongPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr,
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
break;
|
||||
case PROPERTY_TYPE_INT:
|
||||
map =
|
||||
new IntPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr, addressMap,
|
||||
rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
map = new IntPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr,
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
break;
|
||||
case PROPERTY_TYPE_BOOLEAN:
|
||||
map =
|
||||
new VoidPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr, addressMap,
|
||||
rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
map = new VoidPropertyMapDB(dbh, DBConstants.UPGRADE, this, changeMgr,
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL), TaskMonitor.DUMMY);
|
||||
break;
|
||||
case PROPERTY_TYPE_SAVEABLE:
|
||||
String className = rec.getString(PROPERTY_CLASS_COL);
|
||||
Class<? extends Saveable> c =
|
||||
ObjectPropertyMapDB.getSaveableClassForName(className);
|
||||
return new ObjectPropertyMapDB<>(dbh, DBConstants.UPGRADE, this, changeMgr,
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL), c,
|
||||
TaskMonitor.DUMMY, true);
|
||||
addressMap, rec.getString(PROPERTY_NAME_COL), c, TaskMonitor.DUMMY, true);
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported property type: " + type);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import java.util.*;
|
|||
|
||||
import db.DBConstants;
|
||||
import db.DBHandle;
|
||||
import ghidra.program.database.ProgramAddressFactory;
|
||||
import ghidra.program.database.map.AddressMapDBAdapter.AddressMapEntry;
|
||||
import ghidra.program.database.mem.MemoryMapDB;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -219,7 +220,6 @@ public class AddressMapDB implements AddressMap {
|
|||
for (int i = 0; i < sortedBaseStartAddrs.length; i++) {
|
||||
long max = sortedBaseStartAddrs[i].getAddressSpace().getMaxAddress().getOffset();
|
||||
max = max < 0 ? MAX_OFFSET : Math.min(max, MAX_OFFSET);
|
||||
// Avoid use of add which fails for overlay addresses which have restricted min/max offsets
|
||||
long off = sortedBaseStartAddrs[i].getOffset() | max;
|
||||
sortedBaseEndAddrs[i] =
|
||||
sortedBaseStartAddrs[i].getAddressSpace().getAddressInThisSpaceOnly(off);
|
||||
|
@ -912,8 +912,8 @@ public class AddressMapDB implements AddressMap {
|
|||
@Override
|
||||
public Address getImageBase() {
|
||||
if (defaultAddrSpace instanceof SegmentedAddressSpace) {
|
||||
return ((SegmentedAddressSpace) defaultAddrSpace).getAddress(
|
||||
(int) (baseImageOffset >> 4), 0);
|
||||
return ((SegmentedAddressSpace) defaultAddrSpace)
|
||||
.getAddress((int) (baseImageOffset >> 4), 0);
|
||||
}
|
||||
return defaultAddrSpace.getAddress(baseImageOffset);
|
||||
}
|
||||
|
@ -925,7 +925,7 @@ public class AddressMapDB implements AddressMap {
|
|||
* @param translator translates address spaces from the old language to the new language.
|
||||
* @throws IOException if IO error occurs
|
||||
*/
|
||||
public synchronized void setLanguage(Language newLanguage, AddressFactory addrFactory,
|
||||
public synchronized void setLanguage(Language newLanguage, ProgramAddressFactory addrFactory,
|
||||
LanguageTranslator translator) throws IOException {
|
||||
|
||||
List<AddressMapEntry> entries = adapter.getEntries();
|
||||
|
|
|
@ -185,9 +185,6 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
}
|
||||
memMap.checkBlockName(name);
|
||||
try {
|
||||
if (isOverlay()) {
|
||||
memMap.overlayBlockRenamed(startAddress.getAddressSpace().getName(), name);
|
||||
}
|
||||
record.setString(MemoryMapDBAdapter.NAME_COL, name);
|
||||
adapter.updateBlockRecord(record);
|
||||
}
|
||||
|
@ -752,4 +749,22 @@ public class MemoryBlockDB implements MemoryBlock {
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append(getName());
|
||||
buf.append("(");
|
||||
Address start = getStart();
|
||||
buf.append(start.toString());
|
||||
buf.append(" - ");
|
||||
buf.append(getEnd().toString());
|
||||
AddressSpace space = start.getAddressSpace();
|
||||
if (space instanceof OverlayAddressSpace os) {
|
||||
buf.append(", overlays: ");
|
||||
buf.append(os.getOverlayedSpace().getName());
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,8 +24,7 @@ import db.DBHandle;
|
|||
import ghidra.framework.model.DomainObject;
|
||||
import ghidra.framework.model.DomainObjectChangeRecord;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.ManagerDB;
|
||||
import ghidra.program.database.ProgramDB;
|
||||
import ghidra.program.database.*;
|
||||
import ghidra.program.database.code.CodeManager;
|
||||
import ghidra.program.database.map.AddressMapDB;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -201,7 +200,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
AddressSet mappedSet = getMappedIntersection(block, addrSetView.initialized);
|
||||
addrSetView.initialized.add(mappedSet);
|
||||
addrSetView.initializedAndLoaded.add(getMappedIntersection(block, addrSetView.initializedAndLoaded));
|
||||
addrSetView.initializedAndLoaded
|
||||
.add(getMappedIntersection(block, addrSetView.initializedAndLoaded));
|
||||
}
|
||||
else if (block.isInitialized()) {
|
||||
addrSetView.initialized.add(block.getStart(), block.getEnd());
|
||||
|
@ -231,6 +231,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
nameBlockMap = new HashMap<>();
|
||||
addrSetView = null; // signal stale view
|
||||
addrMap.memoryMapChanged(this);
|
||||
if (program != null) {
|
||||
program.getAddressFactory().invalidateOverlayCache();
|
||||
}
|
||||
}
|
||||
|
||||
void blockExecuteChanged(MemoryBlockDB block) {
|
||||
|
@ -370,8 +373,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
private void checkMemoryWriteMappedBlock(MemoryBlockDB mappedBlock, Address start,
|
||||
Address endAddr)
|
||||
throws AddressOverflowException, MemoryAccessException {
|
||||
Address endAddr) throws AddressOverflowException, MemoryAccessException {
|
||||
long startOffset = start.subtract(mappedBlock.getStart());
|
||||
long endOffset = endAddr.subtract(mappedBlock.getStart());
|
||||
|
||||
|
@ -401,8 +403,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
private void checkMemoryWriteNonMappedBlock(MemoryBlockDB nonMappedBlock, Address start,
|
||||
Address endAddr)
|
||||
throws MemoryAccessException {
|
||||
Address endAddr) throws MemoryAccessException {
|
||||
// TODO: could contain uninitialized region which is illegal to write to although block.isInitialized
|
||||
// may not be of much help since it reflects the first sub-block only - seems like mixing is a bad idea
|
||||
|
||||
|
@ -576,9 +577,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
@Override
|
||||
public MemoryBlock createInitializedBlock(String name, Address start, long size,
|
||||
byte initialValue, TaskMonitor monitor, boolean overlay)
|
||||
throws LockException, MemoryConflictException, AddressOverflowException,
|
||||
CancelledException {
|
||||
byte initialValue, TaskMonitor monitor, boolean overlay) throws LockException,
|
||||
MemoryConflictException, AddressOverflowException, CancelledException {
|
||||
|
||||
InputStream fillStream = null;
|
||||
if (initialValue != 0) {
|
||||
|
@ -594,17 +594,67 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
private Address createOverlaySpace(String name, Address start, long dataLength)
|
||||
throws MemoryConflictException, AddressOverflowException, LockException {
|
||||
throws IllegalStateException, AddressOverflowException, LockException {
|
||||
|
||||
start.addNoWrap(dataLength - 1);// just tests the AddressOverflow condition.
|
||||
|
||||
AddressSpace ovSpace = program.addOverlaySpace(name, start.getAddressSpace(),
|
||||
start.getOffset(), start.getOffset() + (dataLength - 1));
|
||||
ProgramOverlayAddressSpace ovSpace =
|
||||
createUniqueOverlaySpace(name, start.getAddressSpace());
|
||||
|
||||
Address ovAddr = ovSpace.getAddress(start.getOffset());
|
||||
Address ovAddr = ovSpace.getAddressInThisSpaceOnly(start.getOffset());
|
||||
return ovAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new overlay space based upon the given base AddressSpace.
|
||||
* The specified overlaySpaceName may be modified to ensure name validity and uniqueness.
|
||||
* @param overlaySpaceName the name of the new overlay space.
|
||||
* @param baseSpace the base AddressSpace to overlay (i.e., overlayed-space)
|
||||
* @return the new overlay space
|
||||
* @throws LockException if the program is shared and not checked out exclusively.
|
||||
* @throws IllegalStateException if image base override is active
|
||||
*/
|
||||
private ProgramOverlayAddressSpace createUniqueOverlaySpace(String overlaySpaceName,
|
||||
AddressSpace baseSpace) throws IllegalStateException, LockException {
|
||||
|
||||
ProgramAddressFactory addressFactory = program.getAddressFactory();
|
||||
overlaySpaceName = fixupOverlaySpaceName(overlaySpaceName);
|
||||
String spaceName = overlaySpaceName;
|
||||
int index = 1;
|
||||
while (addressFactory.getAddressSpace(spaceName) != null) {
|
||||
spaceName = overlaySpaceName + "." + index++;
|
||||
}
|
||||
try {
|
||||
return program.createOverlaySpace(spaceName, baseSpace);
|
||||
}
|
||||
catch (DuplicateNameException | InvalidNameException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate an allowed address space name from a block name. Use of unsupported characters will
|
||||
* be converted to underscore (includes colon and all whitespace chars). double-underscore to
|
||||
* ensure uniqueness.
|
||||
*
|
||||
* @param blockName corresponding memory block name
|
||||
* @return overlay space name
|
||||
*/
|
||||
private String fixupOverlaySpaceName(String blockName) {
|
||||
int len = blockName.length();
|
||||
StringBuffer buf = new StringBuffer(len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = blockName.charAt(i);
|
||||
if (c == ':' || c <= 0x20) {
|
||||
buf.append('_');
|
||||
}
|
||||
else {
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryBlock createInitializedBlock(String name, Address start, InputStream is,
|
||||
long length, TaskMonitor monitor, boolean overlay) throws MemoryConflictException,
|
||||
|
@ -618,8 +668,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
if (monitor != null && is != null) {
|
||||
is = new MonitoredInputStream(is, monitor);
|
||||
}
|
||||
if (overlay) {
|
||||
boolean createdOverlaySpace = false;
|
||||
if (overlay && !start.getAddressSpace().isOverlaySpace()) {
|
||||
start = createOverlaySpace(name, start, length);
|
||||
createdOverlaySpace = true;
|
||||
}
|
||||
else {
|
||||
checkRange(start, length);
|
||||
|
@ -634,8 +686,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
catch (IOCancelledException e) {
|
||||
// this assumes the adapter has already cleaned up any partially created buffers.
|
||||
if (overlay) {
|
||||
checkRemoveAddressSpace(start.getAddressSpace());
|
||||
if (createdOverlaySpace) {
|
||||
attemptOverlaySpaceRemoval((OverlayAddressSpace) start.getAddressSpace());
|
||||
}
|
||||
throw new CancelledException();
|
||||
}
|
||||
|
@ -662,7 +714,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
program.checkExclusiveAccess();
|
||||
checkFileBytesRange(fileBytes, offset, length);
|
||||
|
||||
if (overlay) {
|
||||
if (overlay && !start.getAddressSpace().isOverlaySpace()) {
|
||||
start = createOverlaySpace(name, start, length);
|
||||
}
|
||||
else {
|
||||
|
@ -705,8 +757,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
@Override
|
||||
public MemoryBlock createUninitializedBlock(String name, Address start, long size,
|
||||
boolean overlay) throws MemoryConflictException, AddressOverflowException,
|
||||
LockException {
|
||||
boolean overlay)
|
||||
throws MemoryConflictException, AddressOverflowException, LockException {
|
||||
|
||||
checkBlockName(name);
|
||||
lock.acquire();
|
||||
|
@ -715,7 +767,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
program.checkExclusiveAccess();
|
||||
|
||||
if (overlay) {
|
||||
if (overlay && !start.getAddressSpace().isOverlaySpace()) {
|
||||
start = createOverlaySpace(name, start, size);
|
||||
}
|
||||
else {
|
||||
|
@ -750,7 +802,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
checkBlockSize(length, false);
|
||||
program.checkExclusiveAccess();
|
||||
mappedAddress.addNoWrap((length - 1) / 8);// just to check if length fits in address space
|
||||
if (overlay) {
|
||||
if (overlay && !start.getAddressSpace().isOverlaySpace()) {
|
||||
start = createOverlaySpace(name, start, length);
|
||||
}
|
||||
else {
|
||||
|
@ -794,7 +846,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
checkBlockSize(length, false);
|
||||
program.checkExclusiveAccess();
|
||||
byteMappingScheme.getMappedSourceAddress(mappedAddress, length - 1); // source fit check
|
||||
if (overlay) {
|
||||
if (overlay && !start.getAddressSpace().isOverlaySpace()) {
|
||||
start = createOverlaySpace(name, start, length);
|
||||
}
|
||||
else {
|
||||
|
@ -904,13 +956,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
MemoryBlockDB memBlock = (MemoryBlockDB) block;
|
||||
|
||||
Address oldStartAddr = block.getStart();
|
||||
if (block.isOverlay()) {
|
||||
throw new IllegalArgumentException("Overlay blocks cannot be moved");
|
||||
if (block.isOverlay() && block.getStart().isNonLoadedMemoryAddress()) {
|
||||
// impose convention-based restriction
|
||||
throw new IllegalArgumentException("OTHER overlay blocks cannot be moved");
|
||||
}
|
||||
if (newStartAddr.getAddressSpace().isOverlaySpace()) {
|
||||
throw new IllegalArgumentException("Can not move a block into an overlay space.");
|
||||
}
|
||||
|
||||
program.setEventsEnabled(false);// ensure that no domain object change
|
||||
// events go out that would cause screen updates;
|
||||
// the code manager will be locked until the remove is done
|
||||
|
@ -920,7 +969,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
set.delete(block.getStart(), block.getEnd());
|
||||
if (set.intersects(newStartAddr, newEndAddr)) {
|
||||
throw new MemoryConflictException(
|
||||
"Block move conflicts with other existing memory block");
|
||||
"Block move conflicts with another existing memory block");
|
||||
}
|
||||
try {
|
||||
memBlock.setStartAddress(newStartAddr);
|
||||
|
@ -961,8 +1010,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
if (addr.equals(memBlock.getStart())) {
|
||||
throw new IllegalArgumentException("Split cannot be done on block start address");
|
||||
}
|
||||
if (memBlock.isOverlay()) {
|
||||
throw new IllegalArgumentException("Split cannot be done on an overlay block");
|
||||
if (memBlock.isOverlay() && memBlock.getStart().isNonLoadedMemoryAddress()) {
|
||||
// impose convention-based restriction
|
||||
throw new IllegalArgumentException(
|
||||
"Split cannot be done on an OTHER overlay block");
|
||||
}
|
||||
if (memBlock.isMapped()) {
|
||||
if (memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
|
||||
|
@ -1057,9 +1108,6 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
|
||||
private void checkBlockForJoining(MemoryBlock block) {
|
||||
checkBlock(block);
|
||||
if (block.isOverlay()) {
|
||||
throw new IllegalArgumentException("Cannot join overlay blocks");
|
||||
}
|
||||
if (block.isMapped()) {
|
||||
throw new IllegalArgumentException("Cannot join mapped blocks");
|
||||
}
|
||||
|
@ -1909,8 +1957,8 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
fireBlockRemoved(startAddress);
|
||||
if (startAddress.getAddressSpace().isOverlaySpace()) {
|
||||
checkRemoveAddressSpace(startAddress.getAddressSpace());
|
||||
if (startAddress.getAddressSpace() instanceof OverlayAddressSpace os) {
|
||||
attemptOverlaySpaceRemoval(os);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
|
@ -1919,17 +1967,17 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
|
||||
/**
|
||||
* Tests if the given addressSpace (overlay space) is used by any blocks. If not, it removes the
|
||||
* space.
|
||||
* Attempts to remove the the given overlay address space. Removal will only succeed if no
|
||||
* memory blocks currently reside within the space.
|
||||
*
|
||||
* @param addressSpace overlay address space to be removed
|
||||
*/
|
||||
private void checkRemoveAddressSpace(AddressSpace addressSpace) {
|
||||
private void attemptOverlaySpaceRemoval(OverlayAddressSpace addressSpace) {
|
||||
lock.acquire();
|
||||
try {
|
||||
program.removeOverlaySpace(addressSpace);
|
||||
program.removeOverlaySpace(addressSpace.getName());
|
||||
}
|
||||
catch (LockException e) {
|
||||
catch (LockException | NotFoundException e) {
|
||||
throw new AssertException();
|
||||
}
|
||||
finally {
|
||||
|
@ -1950,9 +1998,6 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
throw new IllegalArgumentException(
|
||||
"Block may not be created with unrecognized address space");
|
||||
}
|
||||
if (space.isOverlaySpace()) {
|
||||
throw new IllegalArgumentException("Block may not be created with an Overlay space");
|
||||
}
|
||||
if (size == 0) {
|
||||
throw new IllegalArgumentException("Block must have a non-zero length");
|
||||
}
|
||||
|
@ -2027,8 +2072,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
else { // Byte mapped
|
||||
ByteMappingScheme byteMappingScheme = info.getByteMappingScheme().get();
|
||||
start =
|
||||
byteMappingScheme.getMappedAddress(mappedBlock, startOffset, false);
|
||||
start = byteMappingScheme.getMappedAddress(mappedBlock, startOffset, false);
|
||||
long endOffset = startOffset + sourceRangeLength - 1;
|
||||
end = byteMappingScheme.getMappedAddress(mappedBlock, endOffset, true);
|
||||
if (start == null || start.compareTo(end) > 0) {
|
||||
|
@ -2076,11 +2120,6 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
|||
}
|
||||
}
|
||||
|
||||
public void overlayBlockRenamed(String oldOverlaySpaceName, String name)
|
||||
throws LockException {
|
||||
program.renameOverlaySpace(oldOverlaySpaceName, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
lock.acquire();
|
||||
|
|
|
@ -17,50 +17,52 @@ package ghidra.program.model.address;
|
|||
|
||||
import java.math.BigInteger;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.util.MathUtilities;
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.*;
|
||||
import ghidra.util.exception.AssertException;
|
||||
|
||||
abstract class AbstractAddressSpace implements AddressSpace {
|
||||
|
||||
protected String name;
|
||||
protected int size; // number of address bits
|
||||
protected int unitSize = 1; // number of data bytes at each location
|
||||
protected int type;
|
||||
protected long spaceSize = 0; // number of address locations (2^size * unitSize) - is always even number (spaceSize=0 when all 64-bits of address offset are used)
|
||||
protected boolean signed;
|
||||
protected long minOffset;
|
||||
private final int size; // number of address bits
|
||||
private final int unitSize; // number of data bytes at each location
|
||||
private final int type;
|
||||
private final boolean signed;
|
||||
|
||||
protected final long minOffset;
|
||||
protected long maxOffset;
|
||||
protected Address minAddress;
|
||||
protected final Address minAddress;
|
||||
protected Address maxAddress;
|
||||
private int hashcode;
|
||||
protected int spaceID;
|
||||
private final long wordAddressMask;
|
||||
protected long spaceSize; // number of address locations (2^size * unitSize) - is always even number (spaceSize=0 when all 64-bits of address offset are used)
|
||||
protected final int spaceID;
|
||||
|
||||
private Integer hashcode;
|
||||
private boolean showSpaceName; // show space name when displaying an address
|
||||
private boolean hasMemoryMappedRegisters = false;
|
||||
|
||||
private long wordAddressMask = -1;
|
||||
|
||||
/**
|
||||
* Constructs a new address space with the given name, bit size, type and unique value.
|
||||
* @param name the name of the space.
|
||||
* @param size the number of bits required to represent the largest address
|
||||
* the space.
|
||||
* @param unitSize number of bytes contained at each addressable location (i.e., word-size in bytes)
|
||||
* @param type the type of the space
|
||||
* @param unique the unique id for this space.
|
||||
*/
|
||||
protected AbstractAddressSpace(String name, int size, int unitSize, int type, int unique) {
|
||||
protected AbstractAddressSpace(int size, int unitSize, int type, int unique) {
|
||||
|
||||
this.size = size;
|
||||
this.unitSize = unitSize;
|
||||
this.type = type;
|
||||
|
||||
showSpaceName = (type != TYPE_RAM) || isOverlaySpace();
|
||||
|
||||
if (type == TYPE_NONE) {
|
||||
this.name = name;
|
||||
this.type = TYPE_NONE;
|
||||
// Intended for special purpose non-physical address space and single address
|
||||
minOffset = maxOffset = 0; // single address at offset-0
|
||||
minAddress = maxAddress = getUncheckedAddress(0);
|
||||
signed = false;
|
||||
spaceSize = 0; // (spaceSize=0 for 64-bit space)
|
||||
wordAddressMask = -1;
|
||||
spaceID = -1;
|
||||
hashcode = name.hashCode() + type;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -68,17 +70,17 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
throw new IllegalArgumentException(
|
||||
"Unique space id must be between 0 and " + Short.MAX_VALUE + " inclusive");
|
||||
}
|
||||
this.name = name;
|
||||
this.size = size;
|
||||
this.unitSize = unitSize;
|
||||
this.type = type;
|
||||
|
||||
if ((bitsConsumedByUnitSize(unitSize) + size) > 64) {
|
||||
if ((bitsConsumedByUnitSize() + size) > 64) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupport address space size (2^size * wordsize > 2^64)");
|
||||
}
|
||||
if (size != 64) {
|
||||
spaceSize = ((long) unitSize) << size; // (spaceSize=0 for 64-bit space)
|
||||
if (size == 64) {
|
||||
spaceSize = 0; // (spaceSize=0 for 64-bit space)
|
||||
wordAddressMask = -1;
|
||||
}
|
||||
else {
|
||||
spaceSize = ((long) unitSize) << size;
|
||||
wordAddressMask = (1L << size) - 1;
|
||||
}
|
||||
signed = (type == AddressSpace.TYPE_CONSTANT || type == AddressSpace.TYPE_STACK);
|
||||
|
@ -113,11 +115,9 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
|
||||
// space id includes space and size info.
|
||||
this.spaceID = (unique << ID_UNIQUE_SHIFT) | (logsize << ID_SIZE_SHIFT) | type;
|
||||
|
||||
hashcode = name.hashCode() + type;
|
||||
}
|
||||
|
||||
private int bitsConsumedByUnitSize(int unitSize) {
|
||||
private int bitsConsumedByUnitSize() {
|
||||
if (unitSize < 1 || unitSize > 8) {
|
||||
throw new IllegalArgumentException("Unsupported unit size: " + unitSize);
|
||||
}
|
||||
|
@ -133,11 +133,6 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
return signed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSize() {
|
||||
return size;
|
||||
|
@ -200,7 +195,7 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress(String addrString) throws AddressFormatException {
|
||||
public final Address getAddress(String addrString) throws AddressFormatException {
|
||||
return getAddress(addrString, true);
|
||||
}
|
||||
|
||||
|
@ -209,11 +204,10 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
throws AddressFormatException {
|
||||
String offStr = addrString;
|
||||
|
||||
int colonPos = addrString.lastIndexOf(':');
|
||||
|
||||
int colonPos = addrString.lastIndexOf(Address.SEPARATOR);
|
||||
if (colonPos >= 0) {
|
||||
String addrSpaceStr = addrString.substring(0, colonPos);
|
||||
if (!StringUtils.equals(name, addrSpaceStr)) {
|
||||
if (!StringUtilities.equals(getName(), addrSpaceStr, caseSensitive)) {
|
||||
return null;
|
||||
}
|
||||
offStr = addrString.substring(colonPos + 1);
|
||||
|
@ -221,11 +215,10 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
|
||||
try {
|
||||
long off = parseString(offStr);
|
||||
return getAddress(off);
|
||||
return getAddressInThisSpaceOnly(off);
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new AddressFormatException(
|
||||
addrString + " contains invalid address hex offset");
|
||||
throw new AddressFormatException(addrString + " contains invalid address hex offset");
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
throw new AddressFormatException(e.getMessage());
|
||||
|
@ -475,48 +468,37 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
return minAddress;
|
||||
}
|
||||
|
||||
private int compareAsOverlaySpace(AddressSpace overlaySpace) {
|
||||
int baseCompare = ((OverlayAddressSpace) this).getBaseSpaceID() -
|
||||
((OverlayAddressSpace) overlaySpace).getBaseSpaceID();
|
||||
if (baseCompare == 0) {
|
||||
long otherMinOffset = overlaySpace.getMinAddress().getOffset();
|
||||
if (minOffset == otherMinOffset) {
|
||||
return name.compareTo(overlaySpace.getName());
|
||||
}
|
||||
return (minOffset < otherMinOffset) ? -1 : 1;
|
||||
}
|
||||
return baseCompare;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(AddressSpace space) {
|
||||
if (space == this) {
|
||||
return 0;
|
||||
}
|
||||
if (isOverlaySpace()) {
|
||||
if (space.isOverlaySpace()) {
|
||||
|
||||
if (this instanceof OverlayAddressSpace thisOverlaySpace) {
|
||||
if (space instanceof OverlayAddressSpace otherOverlaySpace) {
|
||||
// Both spaces are overlay spaces
|
||||
return compareAsOverlaySpace(space);
|
||||
return thisOverlaySpace.compareOverlay(otherOverlaySpace);
|
||||
}
|
||||
// I'm an overlay, other space is NOT an overlay
|
||||
return 1;
|
||||
}
|
||||
else if (space.isOverlaySpace()) {
|
||||
|
||||
if (space instanceof OverlayAddressSpace) {
|
||||
// I'm NOT an overlay, other space is an overlay
|
||||
return -1;
|
||||
}
|
||||
if (hashcode == space.hashCode() &&
|
||||
|
||||
if (hashCode() == space.hashCode() &&
|
||||
// hashcode factors name and type
|
||||
type == space.getType() && name.equals(space.getName()) &&
|
||||
type == space.getType() && getName().equals(space.getName()) &&
|
||||
getClass().equals(space.getClass())) {
|
||||
// TODO: This could be bad - should really only be 0 if same instance - although this could have other implications
|
||||
// Does not seem to be good way of factoring ID-based ordering with equality
|
||||
// This is not intended to handle complete mixing of address spaces
|
||||
// from multiple sources (i.e., language provider / address factory).
|
||||
// It is intended to handle searching for a single address from one
|
||||
// source within a list/set of addresses from a second source.
|
||||
return 0;
|
||||
}
|
||||
|
||||
int c = getSpaceID() - space.getSpaceID();
|
||||
if (c == 0) {
|
||||
c = getClass().getName().compareTo(space.getClass().getName());
|
||||
|
@ -535,22 +517,29 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (hashcode != obj.hashCode()) {
|
||||
if (hashCode() != obj.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AddressSpace s = (AddressSpace) obj;
|
||||
|
||||
// return spaceID == s.getUniqueSpaceID() &&
|
||||
// type == s.getType() &&
|
||||
//// name.equals(s.getName) && // does the name really matter?
|
||||
// size == s.getSize();
|
||||
|
||||
return type == s.getType() && name.equals(s.getName()) && size == s.getSize();
|
||||
if (type != s.getType() || size != s.getSize() || !getName().equals(s.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the fixed hashcode for this address space.
|
||||
* @return computed hash code
|
||||
*/
|
||||
abstract int computeHashCode();
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
public final int hashCode() {
|
||||
if (hashcode == null) {
|
||||
hashcode = computeHashCode();
|
||||
}
|
||||
return hashcode;
|
||||
}
|
||||
|
||||
|
@ -562,13 +551,13 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
protected void testAddressSpace(Address addr) {
|
||||
if (!this.equals(addr.getAddressSpace())) {
|
||||
throw new IllegalArgumentException("Address space for " + addr + " (" +
|
||||
addr.getAddressSpace().getName() + ") does not match " + name);
|
||||
addr.getAddressSpace().getName() + ") does not match " + getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + ":";
|
||||
return getName() + Address.SEPARATOR;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -579,7 +568,8 @@ abstract class AbstractAddressSpace implements AddressSpace {
|
|||
/**
|
||||
* Instantiates an address within this space.
|
||||
* No offset validation should be performed.
|
||||
* @param offset
|
||||
* @param offset address offset
|
||||
* @return requested unchecked address
|
||||
*/
|
||||
protected abstract Address getUncheckedAddress(long offset);
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ public interface Address extends Comparable<Address> {
|
|||
* Character used to separate space names from offsets.
|
||||
*/
|
||||
public final char SEPARATOR_CHAR = ':';
|
||||
public final String SEPARATOR = ":";
|
||||
|
||||
/**
|
||||
* Creates a new Address by parsing a String representation of an address. The string may be
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* ###
|
||||
* IP: GHIDRA
|
||||
* REVIEWED: YES
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -173,4 +172,16 @@ public interface AddressFactory {
|
|||
*/
|
||||
public boolean hasMultipleMemorySpaces();
|
||||
|
||||
/**
|
||||
* Determine if this address factory contains a stale overlay address space
|
||||
* whose name was recently changed. When this condition occurs, issues may arise when
|
||||
* comparing {@link Address} and {@link AddressSpace}-related objects when overlay
|
||||
* address spaces are involved. A common case for this is a Diff type operation.
|
||||
*
|
||||
* @return true if this factory contains one or more stale overlay address space instances.
|
||||
*/
|
||||
public default boolean hasStaleOverlayCondition() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,4 +67,9 @@ public interface AddressIterator extends Iterator<Address>, Iterable<Address> {
|
|||
@Override
|
||||
public boolean hasNext();
|
||||
|
||||
@Override
|
||||
default Iterator<Address> iterator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@ package ghidra.program.model.address;
|
|||
|
||||
import java.util.*;
|
||||
|
||||
import ghidra.util.UniversalIdGenerator;
|
||||
|
||||
/**
|
||||
* <code>AddressMapImpl</code> provides a stand-alone AddressMap.
|
||||
* An AddressMapImpl instance should only be used to decode keys which it has generated.
|
||||
|
@ -77,7 +75,6 @@ public class AddressMapImpl {
|
|||
for (int i = 0; i < sortedBaseStartAddrs.length; i++) {
|
||||
long max = sortedBaseStartAddrs[i].getAddressSpace().getMaxAddress().getOffset();
|
||||
max = max < 0 ? MAX_OFFSET : Math.min(max, MAX_OFFSET);
|
||||
// Avoid use of add which fails for overlay addresses which have restricted min/max offsets
|
||||
long off = sortedBaseStartAddrs[i].getOffset() | max;
|
||||
sortedBaseEndAddrs[i] =
|
||||
sortedBaseStartAddrs[i].getAddressSpace().getAddressInThisSpaceOnly(off);
|
||||
|
@ -332,15 +329,16 @@ public class AddressMapImpl {
|
|||
private static class ObsoleteOverlaySpace extends OverlayAddressSpace {
|
||||
|
||||
private final OverlayAddressSpace originalSpace;
|
||||
private String name;
|
||||
|
||||
ObsoleteOverlaySpace(OverlayAddressSpace ovSpace) {
|
||||
super(makeName(), ovSpace.getOverlayedSpace(), ovSpace.getUnique(),
|
||||
ovSpace.getMinOffset(), ovSpace.getMaxOffset());
|
||||
super(ovSpace.getOverlayedSpace(), ovSpace.getUnique(), createName(ovSpace));
|
||||
this.originalSpace = ovSpace;
|
||||
this.name = createName(ovSpace);
|
||||
}
|
||||
|
||||
private static String makeName() {
|
||||
return "DELETED_" + Long.toHexString(UniversalIdGenerator.nextID().getValue());
|
||||
private static String createName(OverlayAddressSpace ovSpace) {
|
||||
return "DELETED_" + ovSpace.getName() + "_" + ovSpace.getSpaceID();
|
||||
}
|
||||
|
||||
OverlayAddressSpace getOriginalSpace() {
|
||||
|
@ -348,20 +346,20 @@ public class AddressMapImpl {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof ObsoleteOverlaySpace)) {
|
||||
return false;
|
||||
}
|
||||
ObsoleteOverlaySpace s = (ObsoleteOverlaySpace) obj;
|
||||
|
||||
return originalSpace.equals(s.originalSpace) && name.equals(s.name) &&
|
||||
getMinOffset() == s.getMinOffset() && getMaxOffset() == s.getMaxOffset();
|
||||
@Override
|
||||
public boolean contains(long offset) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSetView getOverlayAddressSet() {
|
||||
return new AddressSet();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import java.util.Iterator;
|
|||
|
||||
import util.CollectionUtils;
|
||||
|
||||
|
||||
/**
|
||||
* AddressRangeIterator is used to iterate over some set of addresses.
|
||||
*
|
||||
|
@ -27,4 +26,10 @@ import util.CollectionUtils;
|
|||
* @see CollectionUtils#asIterable
|
||||
*/
|
||||
|
||||
public interface AddressRangeIterator extends Iterator<AddressRange>, Iterable<AddressRange> {}
|
||||
public interface AddressRangeIterator extends Iterator<AddressRange>, Iterable<AddressRange> {
|
||||
|
||||
@Override
|
||||
default Iterator<AddressRange> iterator() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -724,9 +724,7 @@ public class AddressSet implements AddressSetView {
|
|||
entry = rbTree.getFirst();
|
||||
}
|
||||
|
||||
Iterator<AddressRange> iterator = addrSet.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AddressRange range = iterator.next();
|
||||
for (AddressRange range : addrSet) {
|
||||
while (range.compareTo(entry.getValue()) > 0) {
|
||||
entry = entry.getSuccessor();
|
||||
if (entry == null) {
|
||||
|
@ -746,9 +744,7 @@ public class AddressSet implements AddressSetView {
|
|||
if (entry == null) {
|
||||
return false;
|
||||
}
|
||||
Iterator<AddressRange> iterator = addrSet.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
AddressRange range = iterator.next();
|
||||
for (AddressRange range : addrSet) {
|
||||
while (range.compareTo(entry.getValue()) > 0) {
|
||||
entry = entry.getSuccessor();
|
||||
if (entry == null) {
|
||||
|
|
|
@ -103,6 +103,7 @@ public interface AddressSpace extends Comparable<AddressSpace> {
|
|||
|
||||
/**
|
||||
* Returns the name of this address space.
|
||||
* With the exception of {@link OverlayAddressSpace}, the name of an address space may not change.
|
||||
*/
|
||||
String getName();
|
||||
|
||||
|
@ -159,7 +160,7 @@ public interface AddressSpace extends Comparable<AddressSpace> {
|
|||
int getUnique();
|
||||
|
||||
/**
|
||||
* Parses the String into an address.
|
||||
* Parses the String into an address within this address space.
|
||||
* @param addrString the string to parse as an address.
|
||||
* @return an address if the string parsed successfully or null if the
|
||||
* AddressSpace specified in the addrString is not this space.
|
||||
|
@ -169,7 +170,7 @@ public interface AddressSpace extends Comparable<AddressSpace> {
|
|||
Address getAddress(String addrString) throws AddressFormatException;
|
||||
|
||||
/**
|
||||
* Parses the String into an address.
|
||||
* Parses the String into an address within this address space.
|
||||
* @param addrString the string to parse as an address.
|
||||
* @param caseSensitive specifies if addressSpace names must match case.
|
||||
* @return an address if the string parsed successfully or null if the
|
||||
|
@ -385,12 +386,25 @@ public interface AddressSpace extends Comparable<AddressSpace> {
|
|||
public boolean isSuccessor(Address addr1, Address addr2);
|
||||
|
||||
/**
|
||||
* Get the max address allowed for this AddressSpace.
|
||||
* Get the maximum address allowed for this AddressSpace.
|
||||
*
|
||||
* NOTE: Use of this method to identify the region associated with an overlay memory block
|
||||
* within its overlay address space is no longer supported. Defined regions of an overlay space
|
||||
* may now be determined using {@link OverlayAddressSpace#getOverlayAddressSet()}.
|
||||
*
|
||||
* @return maximum address of this address space.
|
||||
*/
|
||||
public Address getMaxAddress();
|
||||
|
||||
/**
|
||||
* Get the min address allowed for this AddressSpace
|
||||
* Get the minimum address allowed for this AddressSpace.
|
||||
* For a memory space the returned address will have an offset of 0 within this address space.
|
||||
*
|
||||
* NOTE: Use of this method to identify the region associated with an overlay memory block
|
||||
* within its overlay address space is no longer supported. Defined regions of an overlay space
|
||||
* may now be determined using {@link OverlayAddressSpace#getOverlayAddressSet()}.
|
||||
*
|
||||
* @return minimum address of this address space.
|
||||
*/
|
||||
public Address getMinAddress();
|
||||
|
||||
|
@ -493,4 +507,24 @@ public interface AddressSpace extends Comparable<AddressSpace> {
|
|||
*/
|
||||
boolean hasSignedOffset();
|
||||
|
||||
/**
|
||||
* Determine if the specific name is a valid address space name (e.g., allowed
|
||||
* overlay space name). NOTE: This does not perform any duplicate name checks.
|
||||
* @param name name
|
||||
* @return true if name is a valid space name.
|
||||
*/
|
||||
public static boolean isValidName(String name) {
|
||||
int len = name.length();
|
||||
if (len == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = name.charAt(i);
|
||||
if (c == ':' || c <= 0x20) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -198,9 +198,6 @@ public class DefaultAddressFactory implements AddressFactory {
|
|||
if (addr == null) {
|
||||
continue;
|
||||
}
|
||||
if (space.isOverlaySpace() && addr.getAddressSpace() != space) {
|
||||
continue;
|
||||
}
|
||||
if (space.isNonLoadedMemorySpace()) {
|
||||
otherList.add(addr);
|
||||
}
|
||||
|
@ -412,27 +409,28 @@ public class DefaultAddressFactory implements AddressFactory {
|
|||
}
|
||||
|
||||
/**
|
||||
* Rename overlay with newName.
|
||||
* @param oldOverlaySpaceName the existing overlay address space name
|
||||
* @param newName the new name of the overlay address space.
|
||||
* @return new name applied to existing overlay space
|
||||
* @throws DuplicateNameException if space with newName already exists
|
||||
* @throws IllegalArgumentException if specified oldOverlaySpaceName was not found as
|
||||
* an existing overlay space
|
||||
* Update address factory map <b>following</b> the rename of an overlay address space instance.
|
||||
* The caller is reponsible for the actual renaming of the existing overlay space instance and
|
||||
* must ensure the newName is not already assigned to another space.
|
||||
* @param oldOverlaySpaceName previous name of existing overlay space
|
||||
* @param newName new name for existing overlay space
|
||||
* @return overlay space instance which was renamed
|
||||
*/
|
||||
protected String renameOverlaySpace(String oldOverlaySpaceName, String newName)
|
||||
throws DuplicateNameException {
|
||||
if (getAddressSpace(newName) != null) {
|
||||
throw new DuplicateNameException("AddressSpace named " + newName + " already exists!");
|
||||
protected OverlayAddressSpace overlaySpaceRenamed(String oldOverlaySpaceName, String newName) {
|
||||
if (spaceNameTable.get(newName) != null) {
|
||||
throw new AssertionError("Address space named " + newName + " already exists!");
|
||||
}
|
||||
AddressSpace space = spaceNameTable.get(oldOverlaySpaceName);
|
||||
if (space instanceof OverlayAddressSpace os) {
|
||||
if (!newName.equals(os.getName())) {
|
||||
throw new AssertionError(
|
||||
"Overlay space " + oldOverlaySpaceName + " was not renamed");
|
||||
}
|
||||
AddressSpace space = getAddressSpace(oldOverlaySpaceName);
|
||||
if (space != null && space.isOverlaySpace()) {
|
||||
((OverlayAddressSpace) space).setName(newName);
|
||||
spaceNameTable.remove(oldOverlaySpaceName);
|
||||
spaceNameTable.put(space.getName(), space);
|
||||
return newName;
|
||||
spaceNameTable.put(newName, os);
|
||||
return os;
|
||||
}
|
||||
throw new IllegalArgumentException("No such overlay space: " + oldOverlaySpaceName);
|
||||
throw new AssertionError("Overlay space not found: " + oldOverlaySpaceName);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,10 +439,9 @@ public class DefaultAddressFactory implements AddressFactory {
|
|||
* @param spaceName the name of the space to remove.
|
||||
*/
|
||||
protected void removeAddressSpace(String spaceName) {
|
||||
AddressSpace deletedSpace = spaceNameTable.get(spaceName);
|
||||
AddressSpace deletedSpace = spaceNameTable.remove(spaceName);
|
||||
if (deletedSpace != null) {
|
||||
spaces.remove(deletedSpace);
|
||||
spaceNameTable.remove(deletedSpace.getName());
|
||||
spaceLookup.remove(deletedSpace.getSpaceID());
|
||||
if (deletedSpace.getType() == AddressSpace.TYPE_RAM ||
|
||||
deletedSpace.getType() == AddressSpace.TYPE_CODE) {
|
||||
|
|
|
@ -20,6 +20,8 @@ package ghidra.program.model.address;
|
|||
*/
|
||||
public class GenericAddressSpace extends AbstractAddressSpace {
|
||||
|
||||
private final String name;
|
||||
|
||||
/**
|
||||
* Constructs a new GenericAddress space with the given name, bit size, type
|
||||
* and unique value.
|
||||
|
@ -77,7 +79,18 @@ public class GenericAddressSpace extends AbstractAddressSpace {
|
|||
* the unique id for this space.
|
||||
*/
|
||||
public GenericAddressSpace(String name, int size, int unitSize, int type, int unique) {
|
||||
super(name, size, unitSize, type, unique);
|
||||
super(size, unitSize, type, unique);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
int computeHashCode() {
|
||||
return name.hashCode() ^ getType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,93 +15,65 @@
|
|||
*/
|
||||
package ghidra.program.model.address;
|
||||
|
||||
public class OverlayAddressSpace extends AbstractAddressSpace {
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class OverlayAddressSpace extends AbstractAddressSpace {
|
||||
public static final String OV_SEPARATER = ":";
|
||||
|
||||
private AddressSpace originalSpace;
|
||||
private final AddressSpace baseSpace;
|
||||
|
||||
private long databaseKey;
|
||||
private final String orderedKey;
|
||||
|
||||
public OverlayAddressSpace(String name, AddressSpace originalSpace, int unique,
|
||||
long minOffset, long maxOffset) {
|
||||
super(name, originalSpace.getSize(), originalSpace.getAddressableUnitSize(),
|
||||
originalSpace.getType(), unique);
|
||||
|
||||
this.originalSpace = originalSpace;
|
||||
/**
|
||||
* Construction an overlay address space instance.
|
||||
* @param baseSpace base overlayed address space
|
||||
* @param unique unique index/sequence number
|
||||
* @param orderedKey unique ordered key which should generally match overlay name unless
|
||||
* already used (e.g., on a renamed overlay space). This associated value should not be
|
||||
* changed for a given address factory instance.
|
||||
*/
|
||||
public OverlayAddressSpace(AddressSpace baseSpace, int unique, String orderedKey) {
|
||||
super(baseSpace.getSize(), baseSpace.getAddressableUnitSize(), baseSpace.getType(), unique);
|
||||
this.orderedKey = orderedKey;
|
||||
this.baseSpace = baseSpace;
|
||||
this.setShowSpaceName(true);
|
||||
|
||||
//KEEP THIS CODE
|
||||
//it also validates the min and max offset
|
||||
this.minOffset = minOffset;
|
||||
this.maxOffset = maxOffset;
|
||||
minAddress = new GenericAddress(this, minOffset);
|
||||
maxAddress = new GenericAddress(this, maxOffset);
|
||||
}
|
||||
|
||||
// public Address addNoWrap(Address addr, long displacement) throws AddressOverflowException {
|
||||
// addr = super.addNoWrap(addr, displacement);
|
||||
//
|
||||
// return translateAddress(addr);
|
||||
// }
|
||||
//
|
||||
// public Address addWrap(Address addr, long displacement) {
|
||||
// addr = super.addWrap(addr, displacement);
|
||||
//
|
||||
// return translateAddress(addr);
|
||||
// }
|
||||
//
|
||||
// public Address getAddress(long offset, long namespaceID) {
|
||||
// return translateAddress(super.getAddress(offset, namespaceID));
|
||||
// }
|
||||
//
|
||||
// public Address getAddress(long offset) {
|
||||
// return translateAddress(super.getAddress(offset));
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* Get the ordered key assigned to this overlay address space instance This value is used
|
||||
* when performing {@link #equals(Object)} and {@link AddressSpace#compareTo(AddressSpace)}
|
||||
* operations.
|
||||
* <p>
|
||||
* If this value does not have its optimal value (i.e., same as address space name), the
|
||||
* associated {@link AddressFactory} should report a
|
||||
* {@link AddressFactory#hasStaleOverlayCondition() stale overlay condition}.
|
||||
* @return instance ordered key
|
||||
*/
|
||||
public String getOrderedKey() {
|
||||
return orderedKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress(String addrString) throws AddressFormatException {
|
||||
addrString = addrString.replaceAll("::", ":");
|
||||
|
||||
int firstColonPos = addrString.indexOf(":");
|
||||
int lastColonPos = addrString.lastIndexOf(":");
|
||||
|
||||
if (firstColonPos != lastColonPos) {
|
||||
String middleName = addrString.substring(firstColonPos + 1, lastColonPos);
|
||||
if (middleName.equals(originalSpace.getName())) {
|
||||
addrString =
|
||||
addrString.substring(0, firstColonPos) + addrString.substring(lastColonPos);
|
||||
}
|
||||
}
|
||||
return super.getAddress(addrString);
|
||||
// return translateAddress(super.getAddress(addrString));
|
||||
|
||||
int computeHashCode() {
|
||||
return Objects.hash(orderedKey, baseSpace);
|
||||
}
|
||||
|
||||
// public Address next(Address addr) {
|
||||
// addr = super.next(addr);
|
||||
// if (addr != null && contains(addr.getOffset())) {
|
||||
// return addr;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
//
|
||||
// public Address previous(Address addr) {
|
||||
// addr = super.previous(addr);
|
||||
// if (addr != null && contains(addr.getOffset())) {
|
||||
// return addr;
|
||||
// }
|
||||
// return null;
|
||||
// }
|
||||
@Override
|
||||
public Address getAddress(String addrString, boolean caseSensitive)
|
||||
throws AddressFormatException {
|
||||
addrString = addrString.replaceAll("::", Address.SEPARATOR);
|
||||
return super.getAddress(addrString, caseSensitive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long subtract(Address addr1, Address addr2) {
|
||||
AddressSpace space1 = addr1.getAddressSpace();
|
||||
AddressSpace space2 = addr2.getAddressSpace();
|
||||
if (space1.equals(this)) {
|
||||
space1 = originalSpace;
|
||||
space1 = baseSpace;
|
||||
}
|
||||
if (space2.equals(this)) {
|
||||
space2 = originalSpace;
|
||||
space2 = baseSpace;
|
||||
}
|
||||
if (!space1.equals(space2)) {
|
||||
throw new IllegalArgumentException("Address are in different spaces " +
|
||||
|
@ -110,45 +82,42 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
|||
return addr1.getOffset() - addr2.getOffset();
|
||||
}
|
||||
|
||||
// public Address subtractNoWrap(Address addr, long displacement) throws AddressOverflowException {
|
||||
// return translateAddress(super.subtractNoWrap(addr, displacement));
|
||||
// }
|
||||
//
|
||||
// public Address subtractWrap(Address addr, long displacement) {
|
||||
// return translateAddress(super.subtractWrap(addr, displacement));
|
||||
// }
|
||||
|
||||
@Override
|
||||
public boolean isOverlaySpace() {
|
||||
return originalSpace != null;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the overlayed (i.e., underlying) base space associated with this overlay space.
|
||||
* @return overlayed base space.
|
||||
*/
|
||||
public AddressSpace getOverlayedSpace() {
|
||||
return originalSpace;
|
||||
return baseSpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSpace getPhysicalSpace() {
|
||||
return originalSpace.getPhysicalSpace();
|
||||
return baseSpace.getPhysicalSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMappedRegisters() {
|
||||
return originalSpace.hasMappedRegisters();
|
||||
return baseSpace.hasMappedRegisters();
|
||||
}
|
||||
|
||||
public long getMinOffset() {
|
||||
return minOffset;
|
||||
}
|
||||
/**
|
||||
* Determine if the specified offset is contained within a defined region of this overlay space.
|
||||
* @param offset unsigned address offset
|
||||
* @return true if contained within defined region otherwise false
|
||||
*/
|
||||
public abstract boolean contains(long offset);
|
||||
|
||||
public long getMaxOffset() {
|
||||
return maxOffset;
|
||||
}
|
||||
|
||||
public boolean contains(long offset) {
|
||||
return Long.compareUnsigned(minOffset, offset) <= 0 &&
|
||||
Long.compareUnsigned(offset, maxOffset) <= 0;
|
||||
}
|
||||
/**
|
||||
* Get the {@link AddressSet} which corresponds to overlayed physical region which
|
||||
* corresponds to the defined overlay regions within the overlay (i.e., overlay blocks).
|
||||
* @return defined regions within the overlay. All addresses are overlay addresses.
|
||||
*/
|
||||
public abstract AddressSetView getOverlayAddressSet();
|
||||
|
||||
@Override
|
||||
public Address getAddressInThisSpaceOnly(long offset) {
|
||||
|
@ -160,7 +129,7 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
|||
if (contains(offset)) {
|
||||
return new GenericAddress(this, offset);
|
||||
}
|
||||
return originalSpace.getAddress(offset);
|
||||
return baseSpace.getAddress(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -209,14 +178,14 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
|||
if (!forceTranslation && contains(addr.getOffset())) {
|
||||
return addr;
|
||||
}
|
||||
return new GenericAddress(originalSpace, addr.getOffset());
|
||||
return new GenericAddress(baseSpace, addr.getOffset());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the ID of the address space underlying this space
|
||||
*/
|
||||
public int getBaseSpaceID() {
|
||||
return originalSpace.getSpaceID();
|
||||
return baseSpace.getSpaceID();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -224,34 +193,51 @@ public class OverlayAddressSpace extends AbstractAddressSpace {
|
|||
return super.toString() + OV_SEPARATER;
|
||||
}
|
||||
|
||||
public void setName(String newName) {
|
||||
name = newName;
|
||||
}
|
||||
|
||||
public void setDatabaseKey(long key) {
|
||||
databaseKey = key;
|
||||
}
|
||||
|
||||
public long getDatabaseKey() {
|
||||
return databaseKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
public final boolean equals(Object obj) {
|
||||
if (obj == this) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null) {
|
||||
return false;
|
||||
}
|
||||
if (!(obj instanceof OverlayAddressSpace)) {
|
||||
if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
OverlayAddressSpace s = (OverlayAddressSpace) obj;
|
||||
|
||||
return originalSpace.equals(s.originalSpace) &&
|
||||
name.equals(s.name) &&
|
||||
minOffset == s.minOffset &&
|
||||
maxOffset == s.maxOffset;
|
||||
if (hashCode() != obj.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OverlayAddressSpace s = (OverlayAddressSpace) obj;
|
||||
if (!s.orderedKey.equals(orderedKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (getType() != s.getType() || getSize() != s.getSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return s.getOverlayedSpace().equals(baseSpace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare this overlay to the spacified overlay.
|
||||
* @param overlay other overlay to be checked for eqauality
|
||||
* @return see {@link Comparable#compareTo(Object)}
|
||||
*/
|
||||
int compareOverlay(OverlayAddressSpace overlay) {
|
||||
if (overlay == this) {
|
||||
return 0;
|
||||
}
|
||||
int rc = baseSpace.compareTo(overlay.baseSpace);
|
||||
if (rc != 0) {
|
||||
return rc;
|
||||
}
|
||||
int c = getType() - overlay.getType();
|
||||
if (c == 0) {
|
||||
c = orderedKey.compareTo(overlay.orderedKey);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
*/
|
||||
package ghidra.program.model.address;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ghidra.util.NumericUtilities;
|
||||
import ghidra.util.StringUtilities;
|
||||
|
||||
/**
|
||||
* Address Space for dealing with (intel) segmented address spaces.
|
||||
|
@ -134,26 +133,17 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @see ghidra.program.model.address.AddressSpace#getAddress(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public Address getAddress(String addrString) throws AddressFormatException {
|
||||
return getAddress(addrString, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address getAddress(String addrString, boolean caseSensitive)
|
||||
throws AddressFormatException {
|
||||
|
||||
int colonPos = addrString.indexOf(':');
|
||||
int colonPos = addrString.indexOf(Address.SEPARATOR);
|
||||
|
||||
if (colonPos >= 0) {
|
||||
String addrSpaceStr = addrString.substring(0, colonPos);
|
||||
String offStr = addrString.substring(colonPos + 1);
|
||||
if (StringUtils.equals(getName(), addrSpaceStr)) {
|
||||
colonPos = offStr.indexOf(':');
|
||||
if (StringUtilities.equals(getName(), addrSpaceStr, caseSensitive)) {
|
||||
colonPos = offStr.indexOf(Address.SEPARATOR);
|
||||
if (colonPos >= 0) {
|
||||
String segString = offStr.substring(0, colonPos);
|
||||
offStr = offStr.substring(colonPos + 1);
|
||||
|
@ -161,11 +151,11 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
|||
}
|
||||
return parseNonSegmented(offStr);
|
||||
}
|
||||
// treat addrSpaceStr as segment
|
||||
return parseSegmented(addrSpaceStr, offStr);
|
||||
}
|
||||
|
||||
return parseNonSegmented(addrString);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -266,7 +256,7 @@ public class SegmentedAddressSpace extends GenericAddressSpace {
|
|||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new AddressFormatException(
|
||||
"Cannot parse (" + segStr + ':' + offStr + ") as a number.");
|
||||
"Cannot parse (" + segStr + Address.SEPARATOR + offStr + ") as a number.");
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
|
@ -259,11 +259,10 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
ProgramArchitecture arch = getProgramArchitecture();
|
||||
LanguageDescription languageDescription =
|
||||
arch.getLanguage().getLanguageDescription();
|
||||
msg += " '" + getName() +
|
||||
"'\n Language: " +
|
||||
msg += " '" + getName() + "'\n Language: " +
|
||||
languageDescription.getLanguageID() + " Version " +
|
||||
languageDescription.getVersion() + ".x" +
|
||||
", CompilerSpec: " + arch.getCompilerSpec().getCompilerSpecID();
|
||||
languageDescription.getVersion() + ".x" + ", CompilerSpec: " +
|
||||
arch.getCompilerSpec().getCompilerSpecID();
|
||||
}
|
||||
break;
|
||||
case DATA_ORG_CHANGED:
|
||||
|
@ -346,8 +345,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
LanguageVersionException languageVersionExc = null;
|
||||
try {
|
||||
language = DefaultLanguageService.getLanguageService().getLanguage(languageId);
|
||||
languageVersionExc =
|
||||
LanguageVersionException.check(language, languageVersion, -1); // don't care about minor version
|
||||
languageVersionExc = LanguageVersionException.check(language, languageVersion, -1); // don't care about minor version
|
||||
}
|
||||
catch (LanguageNotFoundException e) {
|
||||
warning = ArchiveWarning.LANGUAGE_NOT_FOUND;
|
||||
|
@ -417,7 +415,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
|
||||
final Language lang = language;
|
||||
final CompilerSpec cspec = compilerSpec;
|
||||
final AddressFactory addrFactory = new ProgramAddressFactory(lang, cspec);
|
||||
final AddressFactory addrFactory = new ProgramAddressFactory(lang, cspec, s -> null);
|
||||
|
||||
super.setProgramArchitecture(new ProgramArchitecture() {
|
||||
|
||||
|
@ -451,7 +449,6 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
super.handleDataOrganizationChange(openMode, monitor);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the program architecture information which has been associated with this
|
||||
* datatype manager. If {@link #getProgramArchitecture()} returns null this method
|
||||
|
@ -545,7 +542,6 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
warning == ArchiveWarning.COMPILER_SPEC_NOT_FOUND;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear the program architecture setting and all architecture-specific data from this archive.
|
||||
* Archive will revert to using the default {@link DataOrganization}.
|
||||
|
|
|
@ -19,6 +19,7 @@ import java.util.Date;
|
|||
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.IntRangeMap;
|
||||
import ghidra.program.database.ProgramOverlayAddressSpace;
|
||||
import ghidra.program.database.data.DataTypeUtilities;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -30,7 +31,9 @@ import ghidra.program.model.reloc.RelocationTable;
|
|||
import ghidra.program.model.symbol.*;
|
||||
import ghidra.program.model.util.AddressSetPropertyMap;
|
||||
import ghidra.program.model.util.PropertyMapManager;
|
||||
import ghidra.util.InvalidNameException;
|
||||
import ghidra.util.exception.DuplicateNameException;
|
||||
import ghidra.util.exception.NotFoundException;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
|
@ -117,7 +120,6 @@ public interface Program extends DataTypeManagerDomainObject, ProgramArchitectur
|
|||
public SymbolTable getSymbolTable();
|
||||
|
||||
/**
|
||||
|
||||
* Returns the external manager.
|
||||
* @return the external manager
|
||||
*/
|
||||
|
@ -270,12 +272,14 @@ public interface Program extends DataTypeManagerDomainObject, ProgramArchitectur
|
|||
* Returns the language used by this program.
|
||||
* @return the language used by this program.
|
||||
*/
|
||||
@Override
|
||||
public Language getLanguage();
|
||||
|
||||
/**
|
||||
* Returns the CompilerSpec currently used by this program.
|
||||
* @return the compilerSpec currently used by this program.
|
||||
*/
|
||||
@Override
|
||||
public CompilerSpec getCompilerSpec();
|
||||
|
||||
/**
|
||||
|
@ -324,6 +328,7 @@ public interface Program extends DataTypeManagerDomainObject, ProgramArchitectur
|
|||
* Returns the AddressFactory for this program.
|
||||
* @return the program address factory
|
||||
*/
|
||||
@Override
|
||||
public AddressFactory getAddressFactory();
|
||||
|
||||
/**
|
||||
|
@ -351,6 +356,45 @@ public interface Program extends DataTypeManagerDomainObject, ProgramArchitectur
|
|||
*/
|
||||
public void invalidate();
|
||||
|
||||
/**
|
||||
* Create a new overlay space based upon the given base AddressSpace
|
||||
* @param overlaySpaceName the name of the new overlay space.
|
||||
* @param baseSpace the base AddressSpace to overlay (i.e., overlayed-space)
|
||||
* @return the new overlay space
|
||||
* @throws DuplicateNameException if an address space already exists with specified overlaySpaceName.
|
||||
* @throws LockException if the program is shared and not checked out exclusively.
|
||||
* @throws IllegalStateException if image base override is active
|
||||
* @throws InvalidNameException if overlaySpaceName contains invalid characters
|
||||
*/
|
||||
public ProgramOverlayAddressSpace createOverlaySpace(String overlaySpaceName,
|
||||
AddressSpace baseSpace) throws IllegalStateException, DuplicateNameException,
|
||||
InvalidNameException, LockException;
|
||||
|
||||
/**
|
||||
* Rename an existing overlay address space.
|
||||
* NOTE: This experimental method has known limitations with existing {@link Address} and
|
||||
* {@link AddressSpace} objects following an undo/redo which may continue to refer to the old
|
||||
* overlay name which may lead to unxpected errors.
|
||||
* @param overlaySpaceName overlay address space name
|
||||
* @param newName new name for overlay
|
||||
* @throws NotFoundException if the specified overlay space was not found
|
||||
* @throws InvalidNameException if new name is invalid
|
||||
* @throws DuplicateNameException if new name already used by another address space
|
||||
* @throws LockException if program does not has exclusive access
|
||||
*/
|
||||
public void renameOverlaySpace(String overlaySpaceName, String newName)
|
||||
throws NotFoundException, InvalidNameException, DuplicateNameException, LockException;
|
||||
|
||||
/**
|
||||
* Remove the specified overlay address space from this program.
|
||||
* @param overlaySpaceName overlay address space name
|
||||
* @return true if successfully removed, else false if blocks still make use of overlay space.
|
||||
* @throws LockException if program does not has exclusive access
|
||||
* @throws NotFoundException if specified overlay space not found in program
|
||||
*/
|
||||
public boolean removeOverlaySpace(String overlaySpaceName)
|
||||
throws LockException, NotFoundException;
|
||||
|
||||
/**
|
||||
* Returns the register with the given name;
|
||||
* @param name the name of the register to retrieve
|
||||
|
|
|
@ -29,7 +29,54 @@ import ghidra.util.exception.NotFoundException;
|
|||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
/**
|
||||
* Interface for Memory.
|
||||
* {@link Memory} provides the ability to inspect and manage the memory model for a {@link Program}.
|
||||
* In addition to conventional {@link MemoryBlock}s defined within physical memory
|
||||
* {@link AddressSpace}s other special purpose memory block types may be defined (e.g.,
|
||||
* byte-mapped, bit-mapped, overlays, etc.).
|
||||
* <p>
|
||||
* All memory block manipulations require excusive access (see {@link Program#hasExclusiveAccess()})
|
||||
* and all memory changes should generally be completed prior to analysis. In particular, adding
|
||||
* additional overlay blocks to an existing overlay space that has already been analyzed should be
|
||||
* avoided. Code references discovered during analysis from an overlay block will give preference
|
||||
* to remaining within the corresponding overlay address space provided a block exists at the
|
||||
* referenced offset.
|
||||
* <p>
|
||||
* <u>Block Types</u>
|
||||
* <ul>
|
||||
* <li><b>Initialized</b> - a memory block which defines a memory region with specific data.
|
||||
* Data may be initialized from defined {@link FileBytes}, an {@link InputStream}, or set to all
|
||||
* zeros.</li>
|
||||
* <li><b>Uninitialized</b> - a memory block which defines a memory region whose data is unknown.</li>
|
||||
* <li><b>Byte-Mapped</b> - a memory block whose bytes are mapped to another memory region using
|
||||
* either a 1:1 byte-mapping or other specified mapping scheme (see {@link ByteMappingScheme}).
|
||||
* Byte read/write operations are passed-through the mapped region.
|
||||
* </li>
|
||||
* <li><b>Bit-Mapped</b> - a memory block whose bytes are mapped to a corresponding bit in another
|
||||
* memory region where a mapped byte has a value of 0 or 1 only. Byte read/write operations are
|
||||
* passed-through to the corresponding bit within the mapped region.</li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* <u>Overlay Blocks</u>
|
||||
* An overlay memory block provides the ability to define alternate content for a physical memory
|
||||
* region. Any of the Block Types above may be created as an overlay block. The use of an overlay
|
||||
* block and its corresponding overlay address space can be used to reflect a different execution
|
||||
* context. Use of overlays during analysis has limitations that must be considered.</p>
|
||||
* <p>
|
||||
* <u>Loaded vs. Non-Loaded</u>
|
||||
* A special purpose {@link AddressSpace#OTHER_SPACE} has been established for storing adhoc
|
||||
* non-loaded data as a memory block. This is frequently used for storing portions of a file
|
||||
* that never actually get loaded into memory. All blocks created using the
|
||||
* {@link AddressSpace#OTHER_SPACE} must be created as an overlay memory block. All other
|
||||
* blocks based upon a memory address space, including overlays, are treated as Loaded and
|
||||
* use offsets into a physical memory space.</p>
|
||||
* <p>
|
||||
* <u>Sub-Blocks</u>
|
||||
* When a memory block is first created it corresponds to a single sub-block. When
|
||||
* a block join operation is performed the resulting block will consist of multiple sub-blocks.
|
||||
* However, the join operation is restricted to default block types only and does not support
|
||||
* byte/bit-mapped types.
|
||||
* </p>
|
||||
*/
|
||||
public interface Memory extends AddressSetView {
|
||||
|
||||
|
@ -118,24 +165,28 @@ public interface Memory extends AddressSetView {
|
|||
public LiveMemoryHandler getLiveMemoryHandler();
|
||||
|
||||
/**
|
||||
* Returns true if exclusive lock exists and memory blocks may be
|
||||
* created, removed, split, joined or moved. If false is returned,
|
||||
* these types of methods will throw a LockException. The manner in which
|
||||
* a lock is acquired is application specific.
|
||||
*/
|
||||
// public boolean haveLock();
|
||||
|
||||
/**
|
||||
* Create an initialized memory block and add it to this Memory.
|
||||
* Create an initialized memory block based upon a data {@link InputStream} and add it to
|
||||
* this Memory.
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start start address of the block
|
||||
* @param is source of the data used to fill the block or null for zero initialization.
|
||||
* @param length the size of the block
|
||||
* @param monitor task monitor
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Initialized Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
|
@ -150,16 +201,29 @@ public interface Memory extends AddressSetView {
|
|||
CancelledException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Create an initialized memory block and add it to this Memory.
|
||||
* Create an initialized memory block initialized and add it to this Memory. All bytes
|
||||
* will be initialized to the specified value (NOTE: use of zero as the initial value
|
||||
* is encouraged for reduced storage).
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start start of the block
|
||||
* @param size block length (positive non-zero value required)
|
||||
* @param initialValue initialization value for every byte in the block.
|
||||
* @param monitor progress monitor, may be null.
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Initialized Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
|
@ -175,16 +239,26 @@ public interface Memory extends AddressSetView {
|
|||
|
||||
/**
|
||||
* Create an initialized memory block using bytes from a {@link FileBytes} object.
|
||||
*
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start starting address of the block
|
||||
* @param fileBytes the {@link FileBytes} object to use as the underlying source of bytes.
|
||||
* @param offset the offset into the FileBytes for the first byte of this memory block.
|
||||
* @param size block length (positive non-zero value required)
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Initialized Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
|
@ -200,13 +274,24 @@ public interface Memory extends AddressSetView {
|
|||
|
||||
/**
|
||||
* Create an uninitialized memory block and add it to this Memory.
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start start of the block
|
||||
* @param size block length
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Uninitialized Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
|
@ -219,16 +304,29 @@ public interface Memory extends AddressSetView {
|
|||
MemoryConflictException, AddressOverflowException;
|
||||
|
||||
/**
|
||||
* Create a bit overlay memory block and add it to this Memory.
|
||||
* Create a bit-mapped overlay memory block and add it to this Memory. Each byte address
|
||||
* within the resulting memory block will correspond to a single bit location within the mapped
|
||||
* region specified by {@code mappedAddress}.
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start start of the block
|
||||
* @param mappedAddress start address in the source block for the
|
||||
* beginning of this block
|
||||
* @param length block length
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Bit Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a
|
||||
|
@ -243,8 +341,19 @@ public interface Memory extends AddressSetView {
|
|||
AddressOverflowException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Create a memory block that uses the bytes located at a different location with a 1:1
|
||||
* byte mapping scheme.
|
||||
* Create a byte-mapped memory block and add it to this memory. Each byte address
|
||||
* within the resulting memory block will correspond to a byte within the mapped
|
||||
* region specified by {@code mappedAddress}. While a 1:1 byte-mapping is the default,
|
||||
* a specific byte-mapping ratio may be specified.
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start start of the block
|
||||
|
@ -252,9 +361,11 @@ public interface Memory extends AddressSetView {
|
|||
* beginning of this block
|
||||
* @param length block length
|
||||
* @param byteMappingScheme byte mapping scheme (may be null for 1:1 mapping)
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Bit Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a previous block
|
||||
|
@ -266,17 +377,29 @@ public interface Memory extends AddressSetView {
|
|||
MemoryConflictException, AddressOverflowException, IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Create a memory block that uses the bytes located at a different location with a 1:1
|
||||
* byte mapping scheme.
|
||||
* Create a byte-mapped memory block and add it to this memory. Each byte address
|
||||
* within the resulting memory block will correspond to a byte within the mapped
|
||||
* region specified by {@code mappedAddress} using a 1:1 byte-mapping.
|
||||
* <p>
|
||||
* Overlay Blocks: An overlay memory block may be created in two ways:
|
||||
* <ul>
|
||||
* <li>Specifying a {@code start} address within an existing overlay address space
|
||||
* ({@code overlay} parameter is ignored), or</li>
|
||||
* <li>Specifying a {@code start} address within a physical memory address space and passing
|
||||
* {@code overlay=true}. This use case will force the creation of a new unique overlay
|
||||
* address space.</li>
|
||||
* </ul>
|
||||
* @param name block name (See {@link Memory#isValidMemoryBlockName(String)} for
|
||||
* naming rules)
|
||||
* @param start start of the block
|
||||
* @param mappedAddress start address in the source block for the
|
||||
* beginning of this block
|
||||
* @param length block length
|
||||
* @param overlay if true, the block will be created as an OVERLAY which means that a new
|
||||
* overlay address space will be created and the block will have a starting address at the same
|
||||
* offset as the given start address parameter, but in the new address space.
|
||||
* @param overlay if true, the block will be created as an OVERLAY block. If the {@code start}
|
||||
* address is a non-overlay memory address a new overlay address space will be created and the
|
||||
* block will have a starting address at the same offset within the new overlay space. If the
|
||||
* specified {@code start} address is an overlay address an overlay block will be created at
|
||||
* that overlay address.
|
||||
* @return new Bit Memory Block
|
||||
* @throws LockException if exclusive lock not in place (see haveLock())
|
||||
* @throws MemoryConflictException if the new block overlaps with a previous block
|
||||
|
@ -871,7 +994,8 @@ public interface Memory extends AddressSetView {
|
|||
* @return a list of addresses that are associated with the given
|
||||
* FileBytes and offset
|
||||
*/
|
||||
public default List<Address> locateAddressesForFileBytesOffset(FileBytes fileBytes, long offset) {
|
||||
public default List<Address> locateAddressesForFileBytesOffset(FileBytes fileBytes,
|
||||
long offset) {
|
||||
List<Address> list = new ArrayList<>();
|
||||
for (MemoryBlock memBlock : getBlocks()) {
|
||||
for (MemoryBlockSourceInfo info : memBlock.getSourceInfos()) {
|
||||
|
|
|
@ -118,8 +118,7 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
|||
* @throws IllegalArgumentException if invalid name specified
|
||||
* @throws LockException renaming an Overlay block without exclusive access
|
||||
*/
|
||||
public void setName(String name)
|
||||
throws IllegalArgumentException, LockException;
|
||||
public void setName(String name) throws IllegalArgumentException, LockException;
|
||||
|
||||
/**
|
||||
* Get the comment associated with this block.
|
||||
|
@ -289,8 +288,11 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
|||
|
||||
/**
|
||||
* Return whether this block has been initialized.
|
||||
*
|
||||
* @return true if block is fully initialized else false
|
||||
* <p>
|
||||
* WARNING: A mapped memory block may have a mix of intialized, uninitialized, and undefined
|
||||
* regions. The value returned by this method for a mapped memory block is always false
|
||||
* even if some regions are initialized.
|
||||
* @return true if block is fully initialized and not a memory-mapped-block, else false
|
||||
*/
|
||||
public boolean isInitialized();
|
||||
|
||||
|
|
|
@ -505,6 +505,21 @@ public interface ChangeManager {
|
|||
*/
|
||||
public static final int DOCR_OBJECT_CREATED = 132;
|
||||
|
||||
/**
|
||||
* An overlay address space was added.
|
||||
*/
|
||||
public static final int DOCR_OVERLAY_SPACE_ADDED = 133;
|
||||
|
||||
/**
|
||||
* An overlay address space was removed.
|
||||
*/
|
||||
public static final int DOCR_OVERLAY_SPACE_REMOVED = 134;
|
||||
|
||||
/**
|
||||
* An overlay address space was renamed.
|
||||
*/
|
||||
public static final int DOCR_OVERLAY_SPACE_RENAMED = 135;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Trees
|
||||
|
@ -840,8 +855,8 @@ public interface ChangeManager {
|
|||
* @param newValue new value or an Object that is related to the
|
||||
* the event
|
||||
*/
|
||||
public void setObjChanged(int type, AddressSetView addrSet, Object affectedObj,
|
||||
Object oldValue, Object newValue);
|
||||
public void setObjChanged(int type, AddressSetView addrSet, Object affectedObj, Object oldValue,
|
||||
Object newValue);
|
||||
|
||||
/**
|
||||
* Mark the state of a Program as having changed and generate
|
||||
|
|
|
@ -38,7 +38,7 @@ import ghidra.util.Msg;
|
|||
* is the character position within the display item specified by the row and column. Simple fields
|
||||
* like the address field and Mnemonic field will always have a row and column of 0.
|
||||
*/
|
||||
public class ProgramLocation implements Comparable<ProgramLocation> {
|
||||
public class ProgramLocation implements Cloneable, Comparable<ProgramLocation> {
|
||||
|
||||
protected Program program;
|
||||
protected Address addr;
|
||||
|
@ -477,4 +477,31 @@ public class ProgramLocation implements Comparable<ProgramLocation> {
|
|||
public int getCharOffset() {
|
||||
return charOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected final Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new translated copy of the specified {@link ProgramLocation} using the specified
|
||||
* {@link Program program}
|
||||
* @param loc original program location
|
||||
* @param program updated program
|
||||
* @param translatedAddress original loc address translated for using within specified program
|
||||
* @return translated program location
|
||||
*/
|
||||
public static ProgramLocation getTranslatedCopy(ProgramLocation loc, Program program,
|
||||
Address translatedAddress) {
|
||||
try {
|
||||
ProgramLocation translatedLoc = (ProgramLocation) loc.clone();
|
||||
translatedLoc.program = program;
|
||||
translatedLoc.addr = translatedAddress;
|
||||
return translatedLoc;
|
||||
}
|
||||
catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError(e);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -228,8 +228,9 @@ public class SimpleDiffUtility {
|
|||
return otherProgram.getAddressFactory().getStackSpace().getAddress(addr.getOffset());
|
||||
}
|
||||
else if (addr.isRegisterAddress()) {
|
||||
if (program.getLanguage().getLanguageID().equals(
|
||||
otherProgram.getLanguage().getLanguageID())) {
|
||||
if (program.getLanguage()
|
||||
.getLanguageID()
|
||||
.equals(otherProgram.getLanguage().getLanguageID())) {
|
||||
return addr;
|
||||
}
|
||||
// TODO: should we handle small varnodes within big endian registers
|
||||
|
@ -281,17 +282,12 @@ public class SimpleDiffUtility {
|
|||
AddressSpace addrSpace = addr.getAddressSpace();
|
||||
AddressSpace otherSpace = getCompatibleAddressSpace(addrSpace, otherProgram);
|
||||
if (otherSpace != null) {
|
||||
if (addrSpace.isOverlaySpace()) {
|
||||
long offset = addr.getOffset();
|
||||
if (offset < otherSpace.getMinAddress().getOffset()) {
|
||||
return exactMatchOnly ? null : otherSpace.getMinAddress();
|
||||
try {
|
||||
return otherSpace.getAddressInThisSpaceOnly(addr.getOffset());
|
||||
}
|
||||
else if (offset > otherSpace.getMaxAddress().getOffset()) {
|
||||
return exactMatchOnly ? null : otherSpace.getMaxAddress();
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
return otherSpace.getAddress(offset);
|
||||
}
|
||||
return otherSpace.getAddress(addr.getOffset());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -300,20 +296,15 @@ public class SimpleDiffUtility {
|
|||
Program otherProgram) {
|
||||
AddressSpace otherSpace =
|
||||
otherProgram.getAddressFactory().getAddressSpace(addrSpace.getName());
|
||||
if (otherSpace != null && otherSpace.getType() == addrSpace.getType()) {
|
||||
if (otherSpace != null && otherSpace.getType() == addrSpace.getType() &&
|
||||
otherSpace.isOverlaySpace() == addrSpace.isOverlaySpace()) {
|
||||
int id = addrSpace.isOverlaySpace() ? ((OverlayAddressSpace) addrSpace).getBaseSpaceID()
|
||||
: addrSpace.getSpaceID();
|
||||
int otherid =
|
||||
otherSpace.isOverlaySpace() ? ((OverlayAddressSpace) otherSpace).getBaseSpaceID()
|
||||
: otherSpace.getSpaceID();
|
||||
// NOTE: This only works for the same language
|
||||
if (id == otherid) {
|
||||
if (otherSpace.isOverlaySpace()) {
|
||||
long addrOffset = addrSpace.getMinAddress().getOffset();
|
||||
long otherOffset = otherSpace.getMinAddress().getOffset();
|
||||
if (addrOffset != otherOffset) {
|
||||
return null; // Overlays didn't begin at same address.
|
||||
}
|
||||
}
|
||||
return otherSpace;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import ghidra.framework.model.*;
|
|||
import ghidra.framework.options.Options;
|
||||
import ghidra.framework.store.LockException;
|
||||
import ghidra.program.database.IntRangeMap;
|
||||
import ghidra.program.database.ProgramOverlayAddressSpace;
|
||||
import ghidra.program.database.data.ProgramDataTypeManager;
|
||||
import ghidra.program.database.map.AddressMap;
|
||||
import ghidra.program.model.address.*;
|
||||
|
@ -498,6 +499,22 @@ public class StubProgram implements Program {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProgramOverlayAddressSpace createOverlaySpace(String overlaySpaceName,
|
||||
AddressSpace baseSpace) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renameOverlaySpace(String oldOverlaySpaceName, String newName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeOverlaySpace(String overlaySpaceName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Address[] parseAddress(String addrStr) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -44,7 +44,7 @@ public class AddressMapImplTest extends AbstractGenericTest {
|
|||
sp32 = new GenericAddressSpace("THREE", 32, AddressSpace.TYPE_RAM, 2);
|
||||
sp64 = new GenericAddressSpace("FOUR", 64, AddressSpace.TYPE_RAM, 2);
|
||||
|
||||
ov64 = new OverlayAddressSpace("four", sp64, 100, 0x1000, 0x1fff);
|
||||
ov64 = new SingleRangeOverlayAddressSpace("four", sp64, 100, 0x1000, 0x1FFF, "four");
|
||||
|
||||
segSpace1 = new SegmentedAddressSpace("SegSpaceOne", 3);
|
||||
segSpace2 = new SegmentedAddressSpace("SegSpaceTwo", 4);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*/
|
||||
package ghidra.program.model.address;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
|
@ -26,13 +26,13 @@ import generic.test.AbstractGenericTest;
|
|||
public class AddressSpaceTest extends AbstractGenericTest {
|
||||
|
||||
AddressSpace space1;
|
||||
AddressSpace space1overlay1;
|
||||
AddressSpace space1overlay2;
|
||||
AddressSpace space1overlay3;
|
||||
SingleRangeOverlayAddressSpace space1overlay1;
|
||||
SingleRangeOverlayAddressSpace space1overlay2;
|
||||
SingleRangeOverlayAddressSpace space1overlay3;
|
||||
AddressSpace space2;
|
||||
AddressSpace space2overlay1;
|
||||
AddressSpace space2overlay2;
|
||||
AddressSpace space2overlay3;
|
||||
SingleRangeOverlayAddressSpace space2overlay1;
|
||||
SingleRangeOverlayAddressSpace space2overlay2;
|
||||
SingleRangeOverlayAddressSpace space2overlay3;
|
||||
AddressSpace space3;
|
||||
|
||||
public AddressSpaceTest() {
|
||||
|
@ -43,20 +43,33 @@ public class AddressSpaceTest extends AbstractGenericTest {
|
|||
public void setUp() {
|
||||
space1 = new GenericAddressSpace("Test1", 8, AddressSpace.TYPE_RAM, 0);
|
||||
space2 = new GenericAddressSpace("Test2", 8, AddressSpace.TYPE_RAM, 1);
|
||||
space1overlay1 = new OverlayAddressSpace("Test1overlay1", space1, 3, 0x20, 0x30);
|
||||
space1overlay2 = new OverlayAddressSpace("Test1overlay2", space1, 4, 0x10, 0x20);
|
||||
space1overlay3 = new OverlayAddressSpace("Test1overlay", space1, 7, 0x10, 0x50); // dup min offset
|
||||
space2overlay1 = new OverlayAddressSpace("Test2overlay1", space2, 5, 0x20, 0x30);
|
||||
space2overlay2 = new OverlayAddressSpace("Test2overlay2", space2, 2, 0x10, 0x20);
|
||||
space2overlay3 = new OverlayAddressSpace("Test2overlay", space2, 6, 0x10, 0x50); // dup min offset
|
||||
space1overlay1 = new SingleRangeOverlayAddressSpace("Test1overlay1", space1, 3, 0x20, 0x30,
|
||||
"Test1overlay1");
|
||||
space1overlay2 = new SingleRangeOverlayAddressSpace("Test1overlay2", space1, 4, 0x10, 0x20,
|
||||
"Test1overlay2");
|
||||
space1overlay3 = new SingleRangeOverlayAddressSpace("Test1overlay", space1, 7, 0x10, 0x50,
|
||||
"Test1overlay");
|
||||
space2overlay1 = new SingleRangeOverlayAddressSpace("Test2overlay1", space2, 5, 0x20, 0x30,
|
||||
"Test2overlay1");
|
||||
space2overlay2 = new SingleRangeOverlayAddressSpace("Test2overlay2", space2, 2, 0x10, 0x20,
|
||||
"Test2overlay2");
|
||||
space2overlay3 = new SingleRangeOverlayAddressSpace("Test2overlay", space2, 6, 0x10, 0x50,
|
||||
"Test2overlay");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompareTo() {
|
||||
// Primary sort for overlay space is based on underlying base space name, while
|
||||
// secondary order is based upon its assigned "orderedKey" which is unique within its
|
||||
// associated AddressFactory.
|
||||
AddressSpace[] spaces =
|
||||
new AddressSpace[] { space1, space2, space1overlay1, space2overlay1, space1overlay2,
|
||||
space2overlay2, space1overlay3, space2overlay3, space1, space2, space1overlay1,
|
||||
space2overlay1, space1overlay2, space2overlay2, space1overlay3, space2overlay3, };
|
||||
// Address factories do not permit multiple address spaces with the same name or orderedKey.
|
||||
// Those overlaying the same space which have the same orderedKey are considered the same
|
||||
// for comparison/equals even if the name differs. This has been implemented in this
|
||||
// manner so that AddressSets remain valid following the rename of an overlay space.
|
||||
Arrays.sort(spaces);
|
||||
Assert.assertEquals(space1, spaces[0]);
|
||||
Assert.assertEquals(space1, spaces[1]);
|
||||
|
@ -64,37 +77,38 @@ public class AddressSpaceTest extends AbstractGenericTest {
|
|||
Assert.assertEquals(space2, spaces[3]);
|
||||
Assert.assertEquals(space1overlay3, spaces[4]);
|
||||
Assert.assertEquals(space1overlay3, spaces[5]);
|
||||
Assert.assertEquals(space1overlay2, spaces[6]);
|
||||
Assert.assertEquals(space1overlay2, spaces[7]);
|
||||
Assert.assertEquals(space1overlay1, spaces[8]);
|
||||
Assert.assertEquals(space1overlay1, spaces[9]);
|
||||
Assert.assertEquals(space1overlay1, spaces[6]);
|
||||
Assert.assertEquals(space1overlay1, spaces[7]);
|
||||
Assert.assertEquals(space1overlay2, spaces[8]);
|
||||
Assert.assertEquals(space1overlay2, spaces[9]);
|
||||
Assert.assertEquals(space2overlay3, spaces[10]);
|
||||
Assert.assertEquals(space2overlay3, spaces[11]);
|
||||
Assert.assertEquals(space2overlay2, spaces[12]);
|
||||
Assert.assertEquals(space2overlay2, spaces[13]);
|
||||
Assert.assertEquals(space2overlay1, spaces[14]);
|
||||
Assert.assertEquals(space2overlay1, spaces[15]);
|
||||
Assert.assertEquals(space2overlay1, spaces[12]);
|
||||
Assert.assertEquals(space2overlay1, spaces[13]);
|
||||
Assert.assertEquals(space2overlay2, spaces[14]);
|
||||
Assert.assertEquals(space2overlay2, spaces[15]);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEquals() {
|
||||
AddressSpace space1a = new GenericAddressSpace("Test1", 8, AddressSpace.TYPE_RAM, 0);
|
||||
AddressSpace space2a = new GenericAddressSpace("Test2", 8, AddressSpace.TYPE_RAM, 1);
|
||||
AddressSpace space1overlay1a =
|
||||
new OverlayAddressSpace("Test1overlay1", space1, 13, 0x20, 0x30);
|
||||
AddressSpace space1overlay2a =
|
||||
new OverlayAddressSpace("Test1overlay2", space1, 14, 0x10, 0x20);
|
||||
AddressSpace space1overlay3a =
|
||||
new OverlayAddressSpace("Test1overlay", space1, 17, 0x10, 0x50); // dup min offset
|
||||
AddressSpace space2overlay1a =
|
||||
new OverlayAddressSpace("Test2overlay1", space2, 15, 0x20, 0x30);
|
||||
AddressSpace space2overlay2a =
|
||||
new OverlayAddressSpace("Test2overlay2", space2, 12, 0x10, 0x20);
|
||||
AddressSpace space2overlay3a =
|
||||
new OverlayAddressSpace("Test2overlay", space2, 16, 0x10, 0x50); // dup min offset
|
||||
AddressSpace space1overlay1a = new SingleRangeOverlayAddressSpace("Test1overlay1", space1,
|
||||
13, 0x20, 0x30, "Test1overlay1");
|
||||
AddressSpace space1overlay2a = new SingleRangeOverlayAddressSpace("Test1overlay2", space1,
|
||||
14, 0x10, 0x20, "Test1overlay2");
|
||||
AddressSpace space1overlay3a = new SingleRangeOverlayAddressSpace("Test1overlay", space1,
|
||||
17, 0x10, 0x50, "Test1overlay");
|
||||
AddressSpace space2overlay1a = new SingleRangeOverlayAddressSpace("Test2overlay1", space2,
|
||||
15, 0x20, 0x30, "Test2overlay1");
|
||||
AddressSpace space2overlay2a = new SingleRangeOverlayAddressSpace("Test2overlay2", space2,
|
||||
12, 0x10, 0x20, "Test2overlay2");
|
||||
AddressSpace space2overlay3a = new SingleRangeOverlayAddressSpace("Test2overlay", space2,
|
||||
16, 0x10, 0x50, "Test2overlay");
|
||||
|
||||
assertTrue(space1a.equals(space1));
|
||||
assertTrue(space2a.equals(space2));
|
||||
|
||||
assertTrue(space1overlay1a.equals(space1overlay1));
|
||||
assertTrue(space1overlay2a.equals(space1overlay2));
|
||||
assertTrue(space1overlay3a.equals(space1overlay3));
|
||||
|
@ -108,7 +122,6 @@ public class AddressSpaceTest extends AbstractGenericTest {
|
|||
assertTrue(!space1overlay1a.equals(space1overlay2));
|
||||
assertTrue(!space1overlay1a.equals(space1overlay3));
|
||||
assertTrue(!space1overlay1a.equals(space2overlay1));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/* ###
|
||||
* 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.program.model.address;
|
||||
|
||||
/**
|
||||
* {@link SingleRangeOverlayAddressSpace} provides a simple immutable overlay space
|
||||
* which consists of a single memory offset range.
|
||||
*/
|
||||
public class SingleRangeOverlayAddressSpace extends OverlayAddressSpace {
|
||||
|
||||
private String name;
|
||||
private long min;
|
||||
private long max;
|
||||
private AddressSetView overlaySet;
|
||||
|
||||
/**
|
||||
* Construct a single range overlay address space.
|
||||
* NOTE: The same name should not be used more than once within a given {@link AddressFactory}.
|
||||
* @param name overlay space name
|
||||
* @param baseSpace overlayed base space
|
||||
* @param unique unique index number
|
||||
* @param min min address offset
|
||||
* @param max max address offset
|
||||
* @param orderedKey ordered key which is used during comparison with other overlays. Within
|
||||
* program-based implementation (i.e., ProgramOverlayAddressSpace) this is auto-generated based
|
||||
* upon the initial name and must be unique within the associated AddressFactory which does not
|
||||
* exist for this test implementation.
|
||||
*/
|
||||
public SingleRangeOverlayAddressSpace(String name, AddressSpace baseSpace, int unique, long min,
|
||||
long max, String orderedKey) {
|
||||
super(baseSpace, unique, orderedKey);
|
||||
this.name = name;
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(long offset) {
|
||||
return Long.compareUnsigned(offset, min) >= 0 && Long.compareUnsigned(offset, max) <= 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AddressSetView getOverlayAddressSet() {
|
||||
if (overlaySet == null) {
|
||||
AddressSet set = new AddressSet();
|
||||
AddressRange range = new AddressRangeImpl(getAddressInThisSpaceOnly(min),
|
||||
getAddressInThisSpaceOnly(max));
|
||||
set.add(range);
|
||||
overlaySet = set;
|
||||
}
|
||||
return overlaySet;
|
||||
}
|
||||
}
|
|
@ -32,6 +32,7 @@ import generic.theme.GThemeDefaults.Colors;
|
|||
import generic.theme.GThemeDefaults.Colors.Palette;
|
||||
import ghidra.util.exception.AssertException;
|
||||
import ghidra.util.table.GhidraTable;
|
||||
import ghidra.util.task.TaskMonitor;
|
||||
|
||||
public class MemoryMapPluginScreenShots extends GhidraScreenShotGenerator {
|
||||
|
||||
|
@ -40,7 +41,13 @@ public class MemoryMapPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testMemoryMap() {
|
||||
public void testMemoryMap() throws Exception {
|
||||
|
||||
program.withTransaction("Add Blocks", () -> {
|
||||
program.getMemory()
|
||||
.createInitializedBlock("OV1", addr(0x1000), 0x100, (byte) 0, TaskMonitor.DUMMY,
|
||||
true);
|
||||
});
|
||||
|
||||
performAction("Memory Map", "DockingWindows", true);
|
||||
|
||||
|
@ -48,7 +55,7 @@ public class MemoryMapPluginScreenShots extends GhidraScreenShotGenerator {
|
|||
moveProviderToItsOwnWindow(provider);
|
||||
JComponent component = getDockableComponent(provider);
|
||||
|
||||
captureIsolatedComponent(component, 800, 225);
|
||||
captureIsolatedComponent(component, 1000, 250);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue