mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Added feature to show file offsets in address hover in listing
This commit is contained in:
parent
3eafdaae37
commit
57e2171dd4
24 changed files with 357 additions and 75 deletions
|
@ -465,7 +465,8 @@
|
||||||
relationship between the hovered address and the base of memory and the containing memory
|
relationship between the hovered address and the base of memory and the containing memory
|
||||||
block. For addresses in functions, the function offset is also shown; for addresses within
|
block. For addresses in functions, the function offset is also shown; for addresses within
|
||||||
a complex data (structure, array, etc.), the offset from the base of that data is
|
a complex data (structure, array, etc.), the offset from the base of that data is
|
||||||
shown.</P>
|
shown. Also, if the byte value for the address can be traced back to the original imported
|
||||||
|
file, then the filename and offset for that location is displayed</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE><!-- Function Name Hover Section-->
|
</BLOCKQUOTE><!-- Function Name Hover Section-->
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,7 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.plugin.core.codebrowser.hover;
|
package ghidra.app.plugin.core.codebrowser.hover;
|
||||||
|
|
||||||
import static ghidra.util.HTMLUtilities.bold;
|
import static ghidra.util.HTMLUtilities.*;
|
||||||
import static ghidra.util.HTMLUtilities.italic;
|
|
||||||
|
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
|
||||||
|
@ -26,6 +25,7 @@ import ghidra.GhidraOptions;
|
||||||
import ghidra.app.plugin.core.hover.AbstractConfigurableHover;
|
import ghidra.app.plugin.core.hover.AbstractConfigurableHover;
|
||||||
import ghidra.framework.options.Options;
|
import ghidra.framework.options.Options;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
|
import ghidra.program.database.mem.AddressSourceInfo;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.data.Structure;
|
import ghidra.program.model.data.Structure;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
|
@ -33,6 +33,7 @@ import ghidra.program.model.mem.MemoryBlock;
|
||||||
import ghidra.program.util.AddressFieldLocation;
|
import ghidra.program.util.AddressFieldLocation;
|
||||||
import ghidra.program.util.ProgramLocation;
|
import ghidra.program.util.ProgramLocation;
|
||||||
import ghidra.util.HTMLUtilities;
|
import ghidra.util.HTMLUtilities;
|
||||||
|
import ghidra.util.StringUtilities;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hover service to show tool tip text for hovering over a program address in the listing.
|
* A hover service to show tool tip text for hovering over a program address in the listing.
|
||||||
|
@ -44,6 +45,7 @@ import ghidra.util.HTMLUtilities;
|
||||||
public class ProgramAddressRelationshipListingHover extends AbstractConfigurableHover
|
public class ProgramAddressRelationshipListingHover extends AbstractConfigurableHover
|
||||||
implements ListingHoverService {
|
implements ListingHoverService {
|
||||||
|
|
||||||
|
private static final int MAX_FILENAME_SIZE = 40;
|
||||||
private static final String NAME = "Address Display";
|
private static final String NAME = "Address Display";
|
||||||
private static final String DESCRIPTION =
|
private static final String DESCRIPTION =
|
||||||
"Shows the relationship between the hovered address and the base of memory " +
|
"Shows the relationship between the hovered address and the base of memory " +
|
||||||
|
@ -98,6 +100,7 @@ public class ProgramAddressRelationshipListingHover extends AbstractConfigurable
|
||||||
|
|
||||||
addFunctionInfo(program, loc, sb);
|
addFunctionInfo(program, loc, sb);
|
||||||
addDataInfo(program, loc, sb);
|
addDataInfo(program, loc, sb);
|
||||||
|
addByteSourceInfo(program, loc, sb);
|
||||||
|
|
||||||
return createTooltipComponent(sb.toString());
|
return createTooltipComponent(sb.toString());
|
||||||
}
|
}
|
||||||
|
@ -139,6 +142,21 @@ public class ProgramAddressRelationshipListingHover extends AbstractConfigurable
|
||||||
appendTableRow(sb, dataDescr, name, dataOffset);
|
appendTableRow(sb, dataDescr, name, dataOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addByteSourceInfo(Program program, Address loc, StringBuilder sb) {
|
||||||
|
|
||||||
|
AddressSourceInfo addressSourceInfo = program.getMemory().getAddressSourceInfo(loc);
|
||||||
|
if (addressSourceInfo == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (addressSourceInfo.getFileName() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String filename = StringUtilities.trim(addressSourceInfo.getFileName(), MAX_FILENAME_SIZE);
|
||||||
|
long fileOffset = addressSourceInfo.getFileOffset();
|
||||||
|
String dataDescr = "Byte Source Offset";
|
||||||
|
appendTableRow(sb, dataDescr, "File: " + filename, fileOffset);
|
||||||
|
}
|
||||||
|
|
||||||
private void addFunctionInfo(Program program, Address loc, StringBuilder sb) {
|
private void addFunctionInfo(Program program, Address loc, StringBuilder sb) {
|
||||||
Function function = program.getFunctionManager().getFunctionContaining(loc);
|
Function function = program.getFunctionManager().getFunctionContaining(loc);
|
||||||
if (function != null) {
|
if (function != null) {
|
||||||
|
|
|
@ -33,7 +33,7 @@ import docking.widgets.table.AbstractSortedTableModel;
|
||||||
|
|
||||||
import ghidra.framework.model.DomainFile;
|
import ghidra.framework.model.DomainFile;
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
@ -504,7 +504,7 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
||||||
case SOURCE:
|
case SOURCE:
|
||||||
if ((block.getType() == MemoryBlockType.BIT_MAPPED) ||
|
if ((block.getType() == MemoryBlockType.BIT_MAPPED) ||
|
||||||
(block.getType() == MemoryBlockType.BYTE_MAPPED)) {
|
(block.getType() == MemoryBlockType.BYTE_MAPPED)) {
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
return info.getMappedRange().get().getMinAddress().toString();
|
return info.getMappedRange().get().getMinAddress().toString();
|
||||||
}
|
}
|
||||||
return block.getSourceName();
|
return block.getSourceName();
|
||||||
|
@ -522,8 +522,8 @@ class MemoryMapModel extends AbstractSortedTableModel<MemoryBlock> {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getByteSourceDescription(List<SourceInfo> sourceInfos) {
|
private String getByteSourceDescription(List<MemoryBlockSourceInfo> sourceInfos) {
|
||||||
List<SourceInfo> limited = sourceInfos.size() < 5 ? sourceInfos : sourceInfos.subList(0, 4);
|
List<MemoryBlockSourceInfo> limited = sourceInfos.size() < 5 ? sourceInfos : sourceInfos.subList(0, 4);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
String description = limited
|
String description = limited
|
||||||
|
|
|
@ -23,7 +23,7 @@ import org.xml.sax.SAXParseException;
|
||||||
|
|
||||||
import ghidra.app.util.MemoryBlockUtil;
|
import ghidra.app.util.MemoryBlockUtil;
|
||||||
import ghidra.app.util.importer.MessageLog;
|
import ghidra.app.util.importer.MessageLog;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
@ -295,7 +295,7 @@ class MemoryMapXmlMgr {
|
||||||
|
|
||||||
if (block.getType() == MemoryBlockType.BIT_MAPPED) {
|
if (block.getType() == MemoryBlockType.BIT_MAPPED) {
|
||||||
// bit mapped blocks can only have one sub-block
|
// bit mapped blocks can only have one sub-block
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
attrs.addAttribute("SOURCE_ADDRESS",
|
attrs.addAttribute("SOURCE_ADDRESS",
|
||||||
info.getMappedRange().get().getMinAddress().toString());
|
info.getMappedRange().get().getMinAddress().toString());
|
||||||
writer.startElement("BIT_MAPPED", attrs);
|
writer.startElement("BIT_MAPPED", attrs);
|
||||||
|
@ -303,7 +303,7 @@ class MemoryMapXmlMgr {
|
||||||
}
|
}
|
||||||
else if (block.getType() == MemoryBlockType.BYTE_MAPPED) {
|
else if (block.getType() == MemoryBlockType.BYTE_MAPPED) {
|
||||||
// byte mapped blocks can only have one sub-block
|
// byte mapped blocks can only have one sub-block
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
attrs.addAttribute("SOURCE_ADDRESS",
|
attrs.addAttribute("SOURCE_ADDRESS",
|
||||||
info.getMappedRange().get().getMinAddress().toString());
|
info.getMappedRange().get().getMinAddress().toString());
|
||||||
writer.startElement("BYTE_MAPPED", attrs);
|
writer.startElement("BYTE_MAPPED", attrs);
|
||||||
|
|
|
@ -35,7 +35,7 @@ import ghidra.app.plugin.core.gotoquery.GoToServicePlugin;
|
||||||
import ghidra.app.plugin.core.navigation.NavigationHistoryPlugin;
|
import ghidra.app.plugin.core.navigation.NavigationHistoryPlugin;
|
||||||
import ghidra.framework.plugintool.PluginTool;
|
import ghidra.framework.plugintool.PluginTool;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.CodeUnit;
|
import ghidra.program.model.listing.CodeUnit;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
@ -560,7 +560,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
||||||
for (MemoryBlock memBlock : blocks) {
|
for (MemoryBlock memBlock : blocks) {
|
||||||
if (memBlock.getSourceName().equals(sources[i]) &&
|
if (memBlock.getSourceName().equals(sources[i]) &&
|
||||||
memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
|
memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
|
||||||
SourceInfo info = memBlock.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = memBlock.getSourceInfos().get(0);
|
||||||
Address addr = info.getMappedRange().get().getMinAddress();
|
Address addr = info.getMappedRange().get().getMinAddress();
|
||||||
|
|
||||||
assertEquals(addr.toString(), model.getValueAt(i, MemoryMapModel.SOURCE));
|
assertEquals(addr.toString(), model.getValueAt(i, MemoryMapModel.SOURCE));
|
||||||
|
@ -605,7 +605,7 @@ public class MemoryMapProvider1Test extends AbstractGhidraHeadedIntegrationTest
|
||||||
for (MemoryBlock memBlock : blocks) {
|
for (MemoryBlock memBlock : blocks) {
|
||||||
if (memBlock.getSourceName().equals(sources[idx]) &&
|
if (memBlock.getSourceName().equals(sources[idx]) &&
|
||||||
memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
|
memBlock.getType() == MemoryBlockType.BIT_MAPPED) {
|
||||||
SourceInfo info = memBlock.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = memBlock.getSourceInfos().get(0);
|
||||||
Address addr = info.getMappedRange().get().getMinAddress();
|
Address addr = info.getMappedRange().get().getMinAddress();
|
||||||
assertEquals(addr.toString(), model.getValueAt(i, MemoryMapModel.SOURCE));
|
assertEquals(addr.toString(), model.getValueAt(i, MemoryMapModel.SOURCE));
|
||||||
doAssert = false;
|
doAssert = false;
|
||||||
|
|
|
@ -879,7 +879,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
assertEquals(MemoryBlockType.BIT_MAPPED, bitBlock.getType());
|
assertEquals(MemoryBlockType.BIT_MAPPED, bitBlock.getType());
|
||||||
|
|
||||||
SourceInfo info = bitBlock.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = bitBlock.getSourceInfos().get(0);
|
||||||
assertEquals(new AddressRangeImpl(addr(0xf00), addr(0x10ff)), info.getMappedRange().get());
|
assertEquals(new AddressRangeImpl(addr(0xf00), addr(0x10ff)), info.getMappedRange().get());
|
||||||
AddressSet expectedInitializedSet = new AddressSet();
|
AddressSet expectedInitializedSet = new AddressSet();
|
||||||
expectedInitializedSet.add(addr(0), addr(0xfff));
|
expectedInitializedSet.add(addr(0), addr(0xfff));
|
||||||
|
@ -895,7 +895,7 @@ public class MemoryManagerTest extends AbstractGhidraHeadedIntegrationTest {
|
||||||
|
|
||||||
assertEquals(MemoryBlockType.BYTE_MAPPED, byteBlock.getType());
|
assertEquals(MemoryBlockType.BYTE_MAPPED, byteBlock.getType());
|
||||||
|
|
||||||
SourceInfo info = byteBlock.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = byteBlock.getSourceInfos().get(0);
|
||||||
assertEquals(new AddressRangeImpl(addr(0xf00), addr(0x10ff)), info.getMappedRange().get());
|
assertEquals(new AddressRangeImpl(addr(0xf00), addr(0x10ff)), info.getMappedRange().get());
|
||||||
AddressSet expectedInitializedSet = new AddressSet();
|
AddressSet expectedInitializedSet = new AddressSet();
|
||||||
expectedInitializedSet.add(addr(0), addr(0xfff));
|
expectedInitializedSet.add(addr(0), addr(0xfff));
|
||||||
|
|
|
@ -22,7 +22,7 @@ import org.junit.*;
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
import ghidra.framework.cmd.Command;
|
import ghidra.framework.cmd.Command;
|
||||||
import ghidra.program.database.ProgramBuilder;
|
import ghidra.program.database.ProgramBuilder;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.*;
|
import ghidra.program.model.listing.*;
|
||||||
import ghidra.program.model.mem.MemoryBlock;
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
@ -110,7 +110,7 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
||||||
|
|
||||||
MemoryBlock block = x08.getMemory().getBlock(addr);
|
MemoryBlock block = x08.getMemory().getBlock(addr);
|
||||||
assertNotNull(block);
|
assertNotNull(block);
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress());
|
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress());
|
||||||
assertEquals(MemoryBlockType.BIT_MAPPED, block.getType());
|
assertEquals(MemoryBlockType.BIT_MAPPED, block.getType());
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ public class AddMemoryBlockCmdTest extends AbstractGenericTest {
|
||||||
|
|
||||||
MemoryBlock block = x08.getMemory().getBlock(addr);
|
MemoryBlock block = x08.getMemory().getBlock(addr);
|
||||||
assertNotNull(block);
|
assertNotNull(block);
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress());
|
assertEquals(getX08Addr(0), info.getMappedRange().get().getMinAddress());
|
||||||
assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType());
|
assertEquals(MemoryBlockType.BYTE_MAPPED, block.getType());
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
|
import ghidra.program.database.mem.AddressSourceInfo;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
@ -56,6 +57,11 @@ class MyTestMemory extends AddressSet implements Memory {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressSourceInfo getAddressSourceInfo(Address address) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isBigEndian() {
|
public boolean isBigEndian() {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -18,7 +18,7 @@ package ghidra.app.plugin.core.checksums;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ class MyTestMemoryBlock implements MemoryBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SourceInfo> getSourceInfos() {
|
public List<MemoryBlockSourceInfo> getSourceInfos() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
|
import ghidra.program.database.mem.AddressSourceInfo;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
@ -348,4 +349,9 @@ public class MemoryTestDummy extends AddressSet implements Memory {
|
||||||
MemoryConflictException, AddressOverflowException {
|
MemoryConflictException, AddressOverflowException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressSourceInfo getAddressSourceInfo(Address address) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Arrays;
|
||||||
import ghidra.pcode.error.LowlevelError;
|
import ghidra.pcode.error.LowlevelError;
|
||||||
import ghidra.pcode.memstate.MemoryFaultHandler;
|
import ghidra.pcode.memstate.MemoryFaultHandler;
|
||||||
import ghidra.pcode.memstate.MemoryPage;
|
import ghidra.pcode.memstate.MemoryPage;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
@ -48,7 +48,7 @@ public class ProgramLoadImage {
|
||||||
}
|
}
|
||||||
|
|
||||||
private AddressSetView addMappedInitializedMemory(MemoryBlock mappedBlock) {
|
private AddressSetView addMappedInitializedMemory(MemoryBlock mappedBlock) {
|
||||||
SourceInfo sourceInfo = mappedBlock.getSourceInfos().get(0); // mapped block has exactly 1 mapped source
|
MemoryBlockSourceInfo sourceInfo = mappedBlock.getSourceInfos().get(0); // mapped block has exactly 1 mapped source
|
||||||
if (!sourceInfo.getMappedRange().isPresent()) {
|
if (!sourceInfo.getMappedRange().isPresent()) {
|
||||||
throw new AssertException("Mapped block did not have mapped range!");
|
throw new AssertException("Mapped block did not have mapped range!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Arrays;
|
||||||
import ghidra.pcode.error.LowlevelError;
|
import ghidra.pcode.error.LowlevelError;
|
||||||
import ghidra.pcode.memstate.MemoryFaultHandler;
|
import ghidra.pcode.memstate.MemoryFaultHandler;
|
||||||
import ghidra.pcode.memstate.MemoryPage;
|
import ghidra.pcode.memstate.MemoryPage;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.program.model.mem.*;
|
import ghidra.program.model.mem.*;
|
||||||
|
@ -52,7 +52,7 @@ public class ProgramMappedMemory {
|
||||||
|
|
||||||
private AddressSetView addMappedInitializedMemory(MemoryBlock mappedBlock) {
|
private AddressSetView addMappedInitializedMemory(MemoryBlock mappedBlock) {
|
||||||
AddressSet modifiedSet = new AddressSet(initializedAddressSet);
|
AddressSet modifiedSet = new AddressSet(initializedAddressSet);
|
||||||
SourceInfo sourceInfo = mappedBlock.getSourceInfos().get(0); // mapped block has exactly 1 mapped source
|
MemoryBlockSourceInfo sourceInfo = mappedBlock.getSourceInfos().get(0); // mapped block has exactly 1 mapped source
|
||||||
if (!sourceInfo.getMappedRange().isPresent()) {
|
if (!sourceInfo.getMappedRange().isPresent()) {
|
||||||
throw new AssertException("Mapped block did not have mapped range!");
|
throw new AssertException("Mapped block did not have mapped range!");
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
/* ###
|
||||||
|
* 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.mem;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import ghidra.program.model.address.Address;
|
||||||
|
import ghidra.program.model.address.AddressRange;
|
||||||
|
import ghidra.program.model.mem.Memory;
|
||||||
|
import ghidra.program.model.mem.MemoryBlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides information about the source of a byte value at an address including the file it
|
||||||
|
* came from, the offset into that file, and the original value of that byte.
|
||||||
|
*/
|
||||||
|
public class AddressSourceInfo {
|
||||||
|
|
||||||
|
private Address address;
|
||||||
|
private MemoryBlock block;
|
||||||
|
private FileBytes fileBytes;
|
||||||
|
private MemoryBlockSourceInfo sourceInfo;
|
||||||
|
private AddressSourceInfo mappedInfo;
|
||||||
|
private Memory memory;
|
||||||
|
|
||||||
|
public AddressSourceInfo(Memory memory, Address address, MemoryBlock block) {
|
||||||
|
this.memory = memory;
|
||||||
|
this.address = address;
|
||||||
|
this.block = block;
|
||||||
|
sourceInfo = getContainingInfo();
|
||||||
|
fileBytes = sourceInfo.getFileBytes().orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the address for which this object provides byte source information.
|
||||||
|
* @return the address for which this object provides byte source information.
|
||||||
|
*/
|
||||||
|
public Address getAddress() {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the offset into the originally imported file that provided the byte value for the
|
||||||
|
* associated address or -1 if there is no source information for this location.
|
||||||
|
* @return the offset into the originally imported file that provided the byte value for the
|
||||||
|
* associated address.
|
||||||
|
*/
|
||||||
|
public long getFileOffset() {
|
||||||
|
if (mappedInfo != null) {
|
||||||
|
return mappedInfo.getFileOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fileBytes != null) {
|
||||||
|
return sourceInfo.getFileBytesOffset(address) + fileBytes.getFileOffset();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the filename of the originally imported file that provided the byte value for the
|
||||||
|
* associated address or null if there is no source information for this location.
|
||||||
|
* @return the filename of the originally imported file that provided the byte value for the
|
||||||
|
* associated address or null if there is no source information for this location.
|
||||||
|
*/
|
||||||
|
public String getFileName() {
|
||||||
|
if (mappedInfo != null) {
|
||||||
|
return mappedInfo.getFileName();
|
||||||
|
}
|
||||||
|
if (fileBytes != null) {
|
||||||
|
return fileBytes.getFilename();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the original byte value from the imported file that provided the byte value for the
|
||||||
|
* associated address or 0 if there is no source information for this location.
|
||||||
|
* @return the original byte value from the imported file that provided the byte value for the
|
||||||
|
* associated address or 0 if there is no source information for this location.
|
||||||
|
* @throws IOException if an io error occurs reading the program database.
|
||||||
|
*/
|
||||||
|
public byte getOriginalValue() throws IOException {
|
||||||
|
if (mappedInfo != null) {
|
||||||
|
return mappedInfo.getOriginalValue();
|
||||||
|
}
|
||||||
|
if (fileBytes != null) {
|
||||||
|
return fileBytes.getOriginalByte(getFileOffset());
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link MemoryBlockSourceInfo} for the region surround this info's location.
|
||||||
|
* @return the {@link MemoryBlockSourceInfo} for the region surround this info's location.
|
||||||
|
*/
|
||||||
|
public MemoryBlockSourceInfo getMemoryBlockSourceInfo() {
|
||||||
|
return sourceInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryBlockSourceInfo getContainingInfo() {
|
||||||
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
|
for (MemoryBlockSourceInfo info : sourceInfos) {
|
||||||
|
if (info.contains(address)) {
|
||||||
|
Optional<AddressRange> mappedRangeOptional = info.getMappedRange();
|
||||||
|
if (mappedRangeOptional.isPresent()) {
|
||||||
|
mappedInfo = getMappedSourceInfo(info, mappedRangeOptional.get());
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AddressSourceInfo getMappedSourceInfo(MemoryBlockSourceInfo info, AddressRange addressRange) {
|
||||||
|
Address mappedAddress =
|
||||||
|
addressRange.getMinAddress().add(address.subtract(info.getMinAddress()));
|
||||||
|
MemoryBlock mappedBlock = memory.getBlock(mappedAddress);
|
||||||
|
if (mappedBlock == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return new AddressSourceInfo(memory, mappedAddress, mappedBlock);
|
||||||
|
}
|
||||||
|
}
|
|
@ -113,11 +113,7 @@ class FileBytesSubMemoryBlock extends SubMemoryBlock {
|
||||||
protected String getDescription() {
|
protected String getDescription() {
|
||||||
String fileName = fileBytes.getFilename();
|
String fileName = fileBytes.getFilename();
|
||||||
|
|
||||||
if (fileBytes.getFileOffset()> 0) {
|
String hexString = Long.toHexString(fileBytesOffset + fileBytes.getFileOffset());
|
||||||
fileName = "[" + fileName + " + 0x" + Long.toHexString(fileBytes.getFileOffset()) + "]";
|
|
||||||
}
|
|
||||||
|
|
||||||
String hexString = Long.toHexString(fileBytesOffset);
|
|
||||||
return "File: " + fileName + ": 0x" + hexString;
|
return "File: " + fileName + ": 0x" + hexString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -665,8 +665,8 @@ public class MemoryBlockDB implements MemoryBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SourceInfo> getSourceInfos() {
|
public List<MemoryBlockSourceInfo> getSourceInfos() {
|
||||||
List<SourceInfo> infos = new ArrayList<>(subBlocks.size());
|
List<MemoryBlockSourceInfo> infos = new ArrayList<>(subBlocks.size());
|
||||||
for (SubMemoryBlock subBlock : subBlocks) {
|
for (SubMemoryBlock subBlock : subBlocks) {
|
||||||
infos.add(subBlock.getSourceInfo(this));
|
infos.add(subBlock.getSourceInfo(this));
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,12 @@ import ghidra.program.model.mem.MemoryBlock;
|
||||||
/**
|
/**
|
||||||
* Class for describing the source of bytes for a memory block.
|
* Class for describing the source of bytes for a memory block.
|
||||||
*/
|
*/
|
||||||
public class SourceInfo {
|
public class MemoryBlockSourceInfo {
|
||||||
|
|
||||||
final MemoryBlock block;
|
private final MemoryBlock block;
|
||||||
final SubMemoryBlock subBlock;
|
private final SubMemoryBlock subBlock;
|
||||||
|
|
||||||
SourceInfo(MemoryBlock block, SubMemoryBlock subBlock) {
|
MemoryBlockSourceInfo(MemoryBlock block, SubMemoryBlock subBlock) {
|
||||||
this.block = block;
|
this.block = block;
|
||||||
this.subBlock = subBlock;
|
this.subBlock = subBlock;
|
||||||
}
|
}
|
||||||
|
@ -97,6 +97,26 @@ public class SourceInfo {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the offset into the {@link FileBytes} object for the given address or
|
||||||
|
* -1 if this SourceInfo does not have an associated {@link FileBytes} or the address doesn't
|
||||||
|
* belong to this SourceInfo.
|
||||||
|
*
|
||||||
|
* @param address the address for which to get an offset into the {@link FileBytes} object.
|
||||||
|
* @return the offset into the {@link FileBytes} object for the given address.
|
||||||
|
*/
|
||||||
|
public long getFileBytesOffset(Address address) {
|
||||||
|
if (!contains(address)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (subBlock instanceof FileBytesSubMemoryBlock) {
|
||||||
|
long blockOffset = address.subtract(getMinAddress());
|
||||||
|
long subBlockOffset = blockOffset - subBlock.startingOffset;
|
||||||
|
return ((FileBytesSubMemoryBlock) subBlock).getFileBytesOffset() + subBlockOffset;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an {@link Optional} {@link AddressRange} for the mapped addresses if this is mapped
|
* Returns an {@link Optional} {@link AddressRange} for the mapped addresses if this is mapped
|
||||||
* memory block (bit mapped or byte mapped). Otherwise, the Optional is empty.
|
* memory block (bit mapped or byte mapped). Otherwise, the Optional is empty.
|
||||||
|
@ -114,4 +134,21 @@ public class SourceInfo {
|
||||||
}
|
}
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the containing Memory Block
|
||||||
|
* @return the containing Memory Block
|
||||||
|
*/
|
||||||
|
public MemoryBlock getMemoryBlock() {
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this SourceInfo object applies to the given address;
|
||||||
|
* @param address the address to test if this is its SourceInfo
|
||||||
|
* @return true if this SourceInfo object applies to the given address;
|
||||||
|
*/
|
||||||
|
public boolean contains(Address address) {
|
||||||
|
return address.compareTo(getMinAddress()) >= 0 && address.compareTo(getMaxAddress()) <= 0;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -662,7 +662,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
try {
|
try {
|
||||||
Address overlayAddr = null;
|
Address overlayAddr = null;
|
||||||
if (block.isMapped()) {
|
if (block.isMapped()) {
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
overlayAddr = info.getMappedRange().get().getMinAddress();
|
overlayAddr = info.getMappedRange().get().getMinAddress();
|
||||||
}
|
}
|
||||||
MemoryBlockDB newBlock =
|
MemoryBlockDB newBlock =
|
||||||
|
@ -1838,9 +1838,9 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
*/
|
*/
|
||||||
private AddressSet getMappedIntersection(MemoryBlock block, AddressSet set) {
|
private AddressSet getMappedIntersection(MemoryBlock block, AddressSet set) {
|
||||||
AddressSet mappedIntersection = new AddressSet();
|
AddressSet mappedIntersection = new AddressSet();
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
// mapped blocks can only ever have one sourceInfo
|
// mapped blocks can only ever have one sourceInfo
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
AddressRange range = info.getMappedRange().get();
|
AddressRange range = info.getMappedRange().get();
|
||||||
AddressSet resolvedIntersection = set.intersect(new AddressSet(range));
|
AddressSet resolvedIntersection = set.intersect(new AddressSet(range));
|
||||||
for (AddressRange resolvedRange : resolvedIntersection) {
|
for (AddressRange resolvedRange : resolvedIntersection) {
|
||||||
|
@ -1855,7 +1855,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
private AddressRange getMappedRange(MemoryBlock mappedBlock, AddressRange resolvedRange) {
|
private AddressRange getMappedRange(MemoryBlock mappedBlock, AddressRange resolvedRange) {
|
||||||
Address start, end;
|
Address start, end;
|
||||||
|
|
||||||
SourceInfo info = mappedBlock.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = mappedBlock.getSourceInfos().get(0);
|
||||||
long startOffset =
|
long startOffset =
|
||||||
resolvedRange.getMinAddress().subtract(info.getMappedRange().get().getMinAddress());
|
resolvedRange.getMinAddress().subtract(info.getMappedRange().get().getMinAddress());
|
||||||
boolean isBitMapped = mappedBlock.getType() == MemoryBlockType.BIT_MAPPED;
|
boolean isBitMapped = mappedBlock.getType() == MemoryBlockType.BIT_MAPPED;
|
||||||
|
@ -1989,6 +1989,14 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
return addrSet.findFirstAddressInCommon(set);
|
return addrSet.findFirstAddressInCommon(set);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressSourceInfo getAddressSourceInfo(Address address) {
|
||||||
|
MemoryBlock block = getBlock(address);
|
||||||
|
if (block != null) {
|
||||||
|
return new AddressSourceInfo(this, address, block);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
private void checkBlockSize(long newBlockLength, boolean initialized) {
|
private void checkBlockSize(long newBlockLength, boolean initialized) {
|
||||||
if (newBlockLength > MAX_BLOCK_SIZE) {
|
if (newBlockLength > MAX_BLOCK_SIZE) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
@ -2109,4 +2117,5 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,7 @@ abstract class MemoryMapDBAdapter {
|
||||||
Address mappedAddress = null;
|
Address mappedAddress = null;
|
||||||
|
|
||||||
if (block.isMapped()) {
|
if (block.isMapped()) {
|
||||||
SourceInfo info = block.getSourceInfos().get(0);
|
MemoryBlockSourceInfo info = block.getSourceInfos().get(0);
|
||||||
mappedAddress = info.getMappedRange().get().getMinAddress();
|
mappedAddress = info.getMappedRange().get().getMinAddress();
|
||||||
}
|
}
|
||||||
newBlock =
|
newBlock =
|
||||||
|
|
|
@ -189,12 +189,12 @@ abstract class SubMemoryBlock {
|
||||||
protected abstract MemoryBlockType getType();
|
protected abstract MemoryBlockType getType();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the {@link SourceInfo} object for this SubMemoryBlock
|
* Returns the {@link MemoryBlockSourceInfo} object for this SubMemoryBlock
|
||||||
* @param block the {@link MemoryBlock} that this block belongs to.
|
* @param block the {@link MemoryBlock} that this block belongs to.
|
||||||
* @return the {@link SourceInfo} object for this SubMemoryBlock
|
* @return the {@link MemoryBlockSourceInfo} object for this SubMemoryBlock
|
||||||
*/
|
*/
|
||||||
protected final SourceInfo getSourceInfo(MemoryBlock block) {
|
protected final MemoryBlockSourceInfo getSourceInfo(MemoryBlock block) {
|
||||||
return new SourceInfo(block, this);
|
return new MemoryBlockSourceInfo(block, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@ import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
|
import ghidra.program.database.mem.AddressSourceInfo;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
@ -748,4 +749,11 @@ public interface Memory extends AddressSetView {
|
||||||
* @throws IOException if there was an error updating the database.
|
* @throws IOException if there was an error updating the database.
|
||||||
*/
|
*/
|
||||||
public boolean deleteFileBytes(FileBytes fileBytes) throws IOException;
|
public boolean deleteFileBytes(FileBytes fileBytes) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns information ({@link AddressSourceInfo}) about the byte source at the given address.
|
||||||
|
* @param address the address to query.
|
||||||
|
* @return information ({@link AddressSourceInfo}) about the byte source at the given address.
|
||||||
|
*/
|
||||||
|
public AddressSourceInfo getAddressSourceInfo(Address address);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ import java.io.Serializable;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
@ -264,13 +264,13 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
|
||||||
public boolean isLoaded();
|
public boolean isLoaded();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of {@link SourceInfo} objects for this block. A block may consist of
|
* Returns a list of {@link MemoryBlockSourceInfo} objects for this block. A block may consist of
|
||||||
* multiple sequences of bytes from different sources. Each such source of bytes is described
|
* multiple sequences of bytes from different sources. Each such source of bytes is described
|
||||||
* by its respective SourceInfo object. Blocks may have multiple sources after two or more
|
* by its respective SourceInfo object. Blocks may have multiple sources after two or more
|
||||||
* memory blocks have been joined together and the underlying byte sources can't be joined.
|
* memory blocks have been joined together and the underlying byte sources can't be joined.
|
||||||
* @return a list of SourceInfo objects, one for each different source of bytes in this block.
|
* @return a list of SourceInfo objects, one for each different source of bytes in this block.
|
||||||
*/
|
*/
|
||||||
public List<SourceInfo> getSourceInfos();
|
public List<MemoryBlockSourceInfo> getSourceInfos();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the specified address is contained within the reserved EXTERNAL block.
|
* Determine if the specified address is contained within the reserved EXTERNAL block.
|
||||||
|
|
|
@ -19,7 +19,7 @@ import java.io.InputStream;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
import ghidra.program.database.mem.SourceInfo;
|
import ghidra.program.database.mem.MemoryBlockSourceInfo;
|
||||||
import ghidra.program.model.address.Address;
|
import ghidra.program.model.address.Address;
|
||||||
import ghidra.util.exception.DuplicateNameException;
|
import ghidra.util.exception.DuplicateNameException;
|
||||||
|
|
||||||
|
@ -191,7 +191,7 @@ public class MemoryBlockStub implements MemoryBlock {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<SourceInfo> getSourceInfos() {
|
public List<MemoryBlockSourceInfo> getSourceInfos() {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import ghidra.framework.store.LockException;
|
import ghidra.framework.store.LockException;
|
||||||
|
import ghidra.program.database.mem.AddressSourceInfo;
|
||||||
import ghidra.program.database.mem.FileBytes;
|
import ghidra.program.database.mem.FileBytes;
|
||||||
import ghidra.program.model.address.*;
|
import ghidra.program.model.address.*;
|
||||||
import ghidra.program.model.listing.Program;
|
import ghidra.program.model.listing.Program;
|
||||||
|
@ -489,4 +490,9 @@ public class MemoryStub implements Memory {
|
||||||
MemoryConflictException, AddressOverflowException {
|
MemoryConflictException, AddressOverflowException {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AddressSourceInfo getAddressSourceInfo(Address address) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,10 +96,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertNull(block.getSourceName());
|
assertNull(block.getSourceName());
|
||||||
assertEquals(MemoryBlock.READ, block.getPermissions());
|
assertEquals(MemoryBlock.READ, block.getPermissions());
|
||||||
|
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
|
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(10, info.getLength());
|
assertEquals(10, info.getLength());
|
||||||
assertEquals(addr(0), info.getMinAddress());
|
assertEquals(addr(0), info.getMinAddress());
|
||||||
assertEquals(addr(9), info.getMaxAddress());
|
assertEquals(addr(9), info.getMaxAddress());
|
||||||
|
@ -117,9 +117,9 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(addr(0), block.getStart());
|
assertEquals(addr(0), block.getStart());
|
||||||
assertEquals(addr(9), block.getEnd());
|
assertEquals(addr(9), block.getEnd());
|
||||||
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
assertEquals(MemoryBlockType.DEFAULT, block.getType());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(10, info.getLength());
|
assertEquals(10, info.getLength());
|
||||||
assertEquals(addr(0), info.getMinAddress());
|
assertEquals(addr(0), info.getMinAddress());
|
||||||
assertEquals(addr(9), info.getMaxAddress());
|
assertEquals(addr(9), info.getMaxAddress());
|
||||||
|
@ -143,9 +143,9 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(9, block.getEnd().getOffset());
|
assertEquals(9, block.getEnd().getOffset());
|
||||||
assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
|
assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
|
||||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(10, info.getLength());
|
assertEquals(10, info.getLength());
|
||||||
try {
|
try {
|
||||||
block.getByte(block.getStart());
|
block.getByte(block.getStart());
|
||||||
|
@ -168,9 +168,9 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(9, block.getEnd().getOffset());
|
assertEquals(9, block.getEnd().getOffset());
|
||||||
assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
|
assertTrue(block.getStart().getAddressSpace().isOverlaySpace());
|
||||||
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
assertEquals(MemoryBlockType.OVERLAY, block.getType());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(10, info.getLength());
|
assertEquals(10, info.getLength());
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
assertEquals(1, block.getByte(block.getStart().add(i)));
|
assertEquals(1, block.getByte(block.getStart().add(i)));
|
||||||
|
@ -194,10 +194,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertNull(block.getSourceName());
|
assertNull(block.getSourceName());
|
||||||
assertEquals(MemoryBlock.READ, block.getPermissions());
|
assertEquals(MemoryBlock.READ, block.getPermissions());
|
||||||
|
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
|
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(20, info.getLength());
|
assertEquals(20, info.getLength());
|
||||||
assertEquals(new AddressRangeImpl(addr(40), addr(59)), info.getMappedRange().get());
|
assertEquals(new AddressRangeImpl(addr(40), addr(59)), info.getMappedRange().get());
|
||||||
|
|
||||||
|
@ -230,10 +230,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertNull(block.getSourceName());
|
assertNull(block.getSourceName());
|
||||||
assertEquals(MemoryBlock.READ, block.getPermissions());
|
assertEquals(MemoryBlock.READ, block.getPermissions());
|
||||||
|
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
|
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(16, info.getLength());
|
assertEquals(16, info.getLength());
|
||||||
assertEquals(new AddressRangeImpl(addr(49), addr(50)), info.getMappedRange().get());
|
assertEquals(new AddressRangeImpl(addr(49), addr(50)), info.getMappedRange().get());
|
||||||
|
|
||||||
|
@ -266,10 +266,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertNull(block.getSourceName());
|
assertNull(block.getSourceName());
|
||||||
assertEquals(MemoryBlock.READ, block.getPermissions());
|
assertEquals(MemoryBlock.READ, block.getPermissions());
|
||||||
|
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
|
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo info = sourceInfos.get(0);
|
MemoryBlockSourceInfo info = sourceInfos.get(0);
|
||||||
assertEquals(50, info.getLength());
|
assertEquals(50, info.getLength());
|
||||||
assertEquals(addr(100), info.getMinAddress());
|
assertEquals(addr(100), info.getMinAddress());
|
||||||
assertEquals(addr(149), info.getMaxAddress());
|
assertEquals(addr(149), info.getMaxAddress());
|
||||||
|
@ -324,9 +324,9 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(1, mem.getBlocks().length);
|
assertEquals(1, mem.getBlocks().length);
|
||||||
assertEquals(20, block.getSize());
|
assertEquals(20, block.getSize());
|
||||||
assertEquals(addr(10), block.getStart());
|
assertEquals(addr(10), block.getStart());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo sourceInfo = sourceInfos.get(0);
|
MemoryBlockSourceInfo sourceInfo = sourceInfos.get(0);
|
||||||
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
||||||
assertEquals(25, sourceInfo.getFileBytesOffset());
|
assertEquals(25, sourceInfo.getFileBytesOffset());
|
||||||
byte[] bytes = new byte[30];
|
byte[] bytes = new byte[30];
|
||||||
|
@ -346,9 +346,9 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(1, mem.getBlocks().length);
|
assertEquals(1, mem.getBlocks().length);
|
||||||
assertEquals(20, block.getSize());
|
assertEquals(20, block.getSize());
|
||||||
assertEquals(addr(10), block.getStart());
|
assertEquals(addr(10), block.getStart());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(2, sourceInfos.size());
|
assertEquals(2, sourceInfos.size());
|
||||||
SourceInfo sourceInfo = sourceInfos.get(0);
|
MemoryBlockSourceInfo sourceInfo = sourceInfos.get(0);
|
||||||
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
||||||
assertEquals(25, sourceInfo.getFileBytesOffset());
|
assertEquals(25, sourceInfo.getFileBytesOffset());
|
||||||
assertEquals(10, sourceInfo.getLength());
|
assertEquals(10, sourceInfo.getLength());
|
||||||
|
@ -370,14 +370,14 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(1, mem.getBlocks().length);
|
assertEquals(1, mem.getBlocks().length);
|
||||||
assertEquals(20, block.getSize());
|
assertEquals(20, block.getSize());
|
||||||
assertEquals(addr(10), block.getStart());
|
assertEquals(addr(10), block.getStart());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(2, sourceInfos.size());
|
assertEquals(2, sourceInfos.size());
|
||||||
SourceInfo sourceInfo = sourceInfos.get(0);
|
MemoryBlockSourceInfo sourceInfo = sourceInfos.get(0);
|
||||||
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
||||||
assertEquals(25, sourceInfo.getFileBytesOffset());
|
assertEquals(25, sourceInfo.getFileBytesOffset());
|
||||||
assertEquals(10, sourceInfo.getLength());
|
assertEquals(10, sourceInfo.getLength());
|
||||||
|
|
||||||
SourceInfo sourceInfo2 = sourceInfos.get(1);
|
MemoryBlockSourceInfo sourceInfo2 = sourceInfos.get(1);
|
||||||
assertEquals(10, sourceInfo2.getLength());
|
assertEquals(10, sourceInfo2.getLength());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,10 +392,10 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(1, mem.getBlocks().length);
|
assertEquals(1, mem.getBlocks().length);
|
||||||
assertEquals(20, block.getSize());
|
assertEquals(20, block.getSize());
|
||||||
assertEquals(addr(10), block.getStart());
|
assertEquals(addr(10), block.getStart());
|
||||||
List<SourceInfo> sourceInfos = block.getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = block.getSourceInfos();
|
||||||
assertEquals(2, sourceInfos.size());
|
assertEquals(2, sourceInfos.size());
|
||||||
|
|
||||||
SourceInfo sourceInfo = sourceInfos.get(0);
|
MemoryBlockSourceInfo sourceInfo = sourceInfos.get(0);
|
||||||
assertEquals(fileBytes1, sourceInfo.getFileBytes().get());
|
assertEquals(fileBytes1, sourceInfo.getFileBytes().get());
|
||||||
assertEquals(25, sourceInfo.getFileBytesOffset());
|
assertEquals(25, sourceInfo.getFileBytesOffset());
|
||||||
assertEquals(10, sourceInfo.getLength());
|
assertEquals(10, sourceInfo.getLength());
|
||||||
|
@ -421,9 +421,9 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(addr(10), blocks[0].getStart());
|
assertEquals(addr(10), blocks[0].getStart());
|
||||||
assertEquals(addr(30), blocks[1].getStart());
|
assertEquals(addr(30), blocks[1].getStart());
|
||||||
|
|
||||||
List<SourceInfo> sourceInfos = blocks[0].getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = blocks[0].getSourceInfos();
|
||||||
assertEquals(1, sourceInfos.size());
|
assertEquals(1, sourceInfos.size());
|
||||||
SourceInfo sourceInfo = sourceInfos.get(0);
|
MemoryBlockSourceInfo sourceInfo = sourceInfos.get(0);
|
||||||
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
assertEquals(fileBytes, sourceInfo.getFileBytes().get());
|
||||||
assertEquals(25, sourceInfo.getFileBytesOffset());
|
assertEquals(25, sourceInfo.getFileBytesOffset());
|
||||||
|
|
||||||
|
@ -479,7 +479,7 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(1, blocks.length);
|
assertEquals(1, blocks.length);
|
||||||
assertEquals(addr(0), blocks[0].getStart());
|
assertEquals(addr(0), blocks[0].getStart());
|
||||||
assertEquals(40, blocks[0].getSize());
|
assertEquals(40, blocks[0].getSize());
|
||||||
List<SourceInfo> sourceInfos = blocks[0].getSourceInfos();
|
List<MemoryBlockSourceInfo> sourceInfos = blocks[0].getSourceInfos();
|
||||||
assertEquals(1, sourceInfos.size()); // make sure the sub blocks were merged
|
assertEquals(1, sourceInfos.size()); // make sure the sub blocks were merged
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -825,6 +825,63 @@ public class MemBlockDBTest extends AbstractGenericTest {
|
||||||
assertEquals(2, range.getSize());
|
assertEquals(2, range.getSize());
|
||||||
assertEquals(0, range.getOffset());
|
assertEquals(0, range.getOffset());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressSourceInfoForFileBytesBlock() throws Exception {
|
||||||
|
FileBytes fileBytes = createFileBytes();
|
||||||
|
mem.createInitializedBlock("block", addr(100), fileBytes, 10, 50, false);
|
||||||
|
|
||||||
|
AddressSourceInfo info = mem.getAddressSourceInfo(addr(100));
|
||||||
|
assertEquals(addr(100), info.getAddress());
|
||||||
|
assertEquals("test", info.getFileName());
|
||||||
|
assertEquals(10, info.getFileOffset());
|
||||||
|
assertEquals(10, info.getOriginalValue());
|
||||||
|
|
||||||
|
info = mem.getAddressSourceInfo(addr(110));
|
||||||
|
assertEquals(addr(110), info.getAddress());
|
||||||
|
assertEquals("test", info.getFileName());
|
||||||
|
assertEquals(20, info.getFileOffset());
|
||||||
|
assertEquals(20, info.getOriginalValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressSourceInfoForBufferBlock() throws Exception {
|
||||||
|
mem.createInitializedBlock("test", addr(0), 10, (byte) 1, TaskMonitor.DUMMY, false);
|
||||||
|
|
||||||
|
AddressSourceInfo info = mem.getAddressSourceInfo(addr(0));
|
||||||
|
assertEquals(addr(0), info.getAddress());
|
||||||
|
assertNull(info.getFileName());
|
||||||
|
assertEquals(-1, info.getFileOffset());
|
||||||
|
assertEquals(0, info.getOriginalValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressSourceInfoForUnitialized() throws Exception {
|
||||||
|
mem.createUninitializedBlock("test", addr(0), 10, false);
|
||||||
|
|
||||||
|
AddressSourceInfo info = mem.getAddressSourceInfo(addr(0));
|
||||||
|
assertEquals(addr(0), info.getAddress());
|
||||||
|
assertNull(info.getFileName());
|
||||||
|
assertEquals(-1, info.getFileOffset());
|
||||||
|
assertEquals(0, info.getOriginalValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressSourceInfoForMappedBlock() throws Exception {
|
||||||
|
FileBytes fileBytes = createFileBytes();
|
||||||
|
mem.createInitializedBlock("block", addr(0), fileBytes, 10, 50, false);
|
||||||
|
mem.createByteMappedBlock("mapped", addr(1000), addr(0), 20);
|
||||||
|
|
||||||
|
AddressSourceInfo info = mem.getAddressSourceInfo(addr(1000));
|
||||||
|
assertEquals(addr(1000), info.getAddress());
|
||||||
|
assertEquals("test", info.getFileName());
|
||||||
|
assertEquals(10, info.getFileOffset());
|
||||||
|
assertEquals(10, info.getOriginalValue());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
private MemoryBlock createFileBytesBlock(FileBytes fileBytes, Address addr, int offset,
|
private MemoryBlock createFileBytesBlock(FileBytes fileBytes, Address addr, int offset,
|
||||||
int length) throws Exception {
|
int length) throws Exception {
|
||||||
return mem.createInitializedBlock("test" + addr.toString(), addr, fileBytes, offset, length,
|
return mem.createInitializedBlock("test" + addr.toString(), addr, fileBytes, offset, length,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue