mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +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
|
@ -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)
|
||||
/**
|
||||
* Determine whether the given space can have an overlay
|
||||
*
|
||||
* @param baseSpace the overlay base address space
|
||||
* @return true to allow, false to prohibit
|
||||
*/
|
||||
protected boolean isValidOverlayBaseSpace(AddressSpace baseSpace) {
|
||||
if (baseSpace != getAddressSpace(baseSpace.getName())) {
|
||||
return false;
|
||||
}
|
||||
return baseSpace.isMemorySpace() && !baseSpace.isOverlaySpace();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 void addOverlaySpace(ProgramOverlayAddressSpace ovSpace)
|
||||
throws DuplicateNameException {
|
||||
if (!ovSpace.getOrderedKey().equals(ovSpace.getName())) {
|
||||
hasStaleOverlays = true;
|
||||
}
|
||||
addAddressSpace(ovSpace);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether the given space can have an overlay
|
||||
*
|
||||
* @param originalSpace the original space
|
||||
* @return true to allow, false to prohibit
|
||||
*/
|
||||
protected boolean validateOriginalSpace(AddressSpace originalSpace) {
|
||||
return originalSpace.isMemorySpace() && !originalSpace.isOverlaySpace();
|
||||
}
|
||||
|
||||
protected boolean assignUniqueID(AddressSpace originalSpace) {
|
||||
return originalSpace.getType() == AddressSpace.TYPE_RAM ||
|
||||
originalSpace.getType() == AddressSpace.TYPE_OTHER;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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 IllegalArgumentException if originalSpace is not permitted or preserveName is true
|
||||
* and a space with specified name already exists.
|
||||
* @throws DuplicateNameException if overlay name duplicates another address space name
|
||||
* @throws IllegalArgumentException if baseSpace is not permitted or not found.
|
||||
*/
|
||||
protected OverlayAddressSpace addOverlayAddressSpace(String name, boolean preserveName,
|
||||
AddressSpace originalSpace, long minOffset, long maxOffset) {
|
||||
protected ProgramOverlayAddressSpace addOverlaySpace(long key, String overlayName,
|
||||
AddressSpace baseSpace) throws DuplicateNameException {
|
||||
|
||||
if (!validateOriginalSpace(originalSpace)) {
|
||||
if (!isValidOverlayBaseSpace(baseSpace)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid address space for overlay: " + originalSpace.getName());
|
||||
}
|
||||
AddressSpace space = getAddressSpace(originalSpace.getName());
|
||||
if (space != originalSpace) {
|
||||
throw new IllegalArgumentException("Unknown memory address space instance");
|
||||
"Invalid base space for overlay: " + baseSpace.getName());
|
||||
}
|
||||
|
||||
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!");
|
||||
AddressSpace space = getAddressSpace(baseSpace.getName());
|
||||
if (space != baseSpace) {
|
||||
throw new IllegalArgumentException("Invalid memory address space instance");
|
||||
}
|
||||
|
||||
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;
|
||||
return new ProgramOverlayAddressSpace(key, overlayName, baseSpace, getNextUniqueID(),
|
||||
overlayRegionSupplier, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a unique address space name based on the specified baseOverlayName
|
||||
*
|
||||
* @param baseOverlayName base overlay address space name
|
||||
* @return unique overlay space name
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void checkValidOverlaySpaceName(String name)
|
||||
throws InvalidNameException, DuplicateNameException {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
if (!AddressSpace.isValidName(name)) {
|
||||
throw new InvalidNameException("Invalid overlay space name: " + name);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
revisedName = getUniqueOverlayName(revisedName);
|
||||
return super.renameOverlaySpace(oldOverlaySpaceName, revisedName);
|
||||
protected void overlaySpaceRenamed(String oldOverlaySpaceName, String newName,
|
||||
boolean refreshStatusIfNeeded) {
|
||||
OverlayAddressSpace os = super.overlaySpaceRenamed(oldOverlaySpaceName, newName);
|
||||
if (!newName.equals(os.getOrderedKey())) {
|
||||
hasStaleOverlays = true;
|
||||
}
|
||||
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)) {
|
||||
try {
|
||||
overlaySpaceAdapter.renameOverlaySpace(oldOverlaySpaceName, revisedName);
|
||||
addrMap.renameOverlaySpace(oldOverlaySpaceName, revisedName);
|
||||
}
|
||||
catch (IOException e) {
|
||||
dbError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void renameOverlaySpace(String overlaySpaceName, String newName)
|
||||
throws NotFoundException, InvalidNameException, DuplicateNameException, LockException {
|
||||
|
||||
public boolean removeOverlaySpace(AddressSpace overlaySpace) throws LockException {
|
||||
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");
|
||||
}
|
||||
addressFactory.removeOverlaySpace(overlaySpace.getName());
|
||||
overlaySpaceAdapter.removeOverlaySpace(overlaySpace.getName());
|
||||
addrMap.deleteOverlaySpace(overlaySpace.getName());
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeOverlaySpace(String overlaySpaceName)
|
||||
throws LockException, NotFoundException {
|
||||
|
||||
lock.acquire();
|
||||
try {
|
||||
checkExclusiveAccess();
|
||||
|
||||
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(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;
|
||||
if (type != s.getType() || size != s.getSize() || !getName().equals(s.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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();
|
||||
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;
|
||||
}
|
||||
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();
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@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 = getAddressSpace(oldOverlaySpaceName);
|
||||
if (space != null && space.isOverlaySpace()) {
|
||||
((OverlayAddressSpace) space).setName(newName);
|
||||
AddressSpace space = spaceNameTable.get(oldOverlaySpaceName);
|
||||
if (space instanceof OverlayAddressSpace os) {
|
||||
if (!newName.equals(os.getName())) {
|
||||
throw new AssertionError(
|
||||
"Overlay space " + oldOverlaySpaceName + " was not renamed");
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (hashCode() != obj.hashCode()) {
|
||||
return false;
|
||||
}
|
||||
OverlayAddressSpace s = (OverlayAddressSpace) obj;
|
||||
|
||||
return originalSpace.equals(s.originalSpace) &&
|
||||
name.equals(s.name) &&
|
||||
minOffset == s.minOffset &&
|
||||
maxOffset == s.maxOffset;
|
||||
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 {
|
||||
|
|
|
@ -59,7 +59,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
private String programArchitectureSummary; // summary of expected program architecture
|
||||
|
||||
protected String name;
|
||||
|
||||
|
||||
public static enum ArchiveWarningLevel {
|
||||
INFO, WARN, ERROR;
|
||||
}
|
||||
|
@ -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}.
|
||||
|
@ -646,12 +642,12 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
|
||||
lock.acquire();
|
||||
try {
|
||||
|
||||
|
||||
if (!isArchitectureChangeAllowed()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Program-architecture change not permitted");
|
||||
}
|
||||
|
||||
|
||||
if (!dbHandle.canUpdate()) {
|
||||
throw new ReadOnlyException("Read-only Archive: " + getName());
|
||||
}
|
||||
|
@ -662,18 +658,18 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
", CompilerSpec: " + compilerSpecId);
|
||||
|
||||
CompilerSpec compilerSpec = language.getCompilerSpecByID(compilerSpecId);
|
||||
|
||||
|
||||
// This type of datatype manager only uses VariableStorageManagerDB
|
||||
VariableStorageManagerDB variableStorageMgr =
|
||||
(VariableStorageManagerDB) getVariableStorageManager();
|
||||
|
||||
|
||||
int txId = startTransaction("Set Program Architecture");
|
||||
try {
|
||||
ProgramArchitectureTranslator translator = null;
|
||||
|
||||
|
||||
ProgramArchitecture oldArch = getProgramArchitecture();
|
||||
if (oldArch != null || isProgramArchitectureMissing()) {
|
||||
|
||||
|
||||
if (updateOption == LanguageUpdateOption.CLEAR) {
|
||||
deleteAllProgramArchitectureData(monitor);
|
||||
variableStorageMgr = null;
|
||||
|
@ -709,12 +705,12 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
oldArch.getCompilerSpec().getCompilerSpecID(), language,
|
||||
compilerSpecId);
|
||||
}
|
||||
|
||||
|
||||
if (translator != null && variableStorageMgr != null) {
|
||||
variableStorageMgr.setLanguage(translator, monitor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ProgramArchitecture programArchitecture = new ProgramArchitecture() {
|
||||
|
||||
@Override
|
||||
|
@ -782,8 +778,8 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
|
||||
if (getProgramArchitecture() != null || isProgramArchitectureUpgradeRequired() ||
|
||||
isProgramArchitectureMissing()) {
|
||||
throw new UnsupportedOperationException(
|
||||
"Program-architecture change not permitted with this method");
|
||||
throw new UnsupportedOperationException(
|
||||
"Program-architecture change not permitted with this method");
|
||||
}
|
||||
|
||||
if (store) {
|
||||
|
@ -816,7 +812,7 @@ public class StandAloneDataTypeManager extends DataTypeManagerDB implements Clos
|
|||
|
||||
defaultListener.categoryRenamed(this, CategoryPath.ROOT, CategoryPath.ROOT);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Transaction openTransaction(String description) throws IllegalStateException {
|
||||
return new Transaction() {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
else if (offset > otherSpace.getMaxAddress().getOffset()) {
|
||||
return exactMatchOnly ? null : otherSpace.getMaxAddress();
|
||||
}
|
||||
return otherSpace.getAddress(offset);
|
||||
try {
|
||||
return otherSpace.getAddressInThisSpaceOnly(addr.getOffset());
|
||||
}
|
||||
catch (AddressOutOfBoundsException e) {
|
||||
return null;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue