GP-1036 EXTERNAL Block Offset-Reference refactor

This commit is contained in:
ghidra1 2022-03-08 05:08:02 -05:00
parent 332480a422
commit 2bced1cd43
43 changed files with 461 additions and 216 deletions

View file

@ -56,7 +56,7 @@ public class DefaultModuleMapProposal
// TODO: Determine how to handle these.
return false;
}
if (MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName())) {
if (block.isExternalBlock()) {
return false;
}
return true;

View file

@ -15,7 +15,7 @@
*/
package ghidra.trace.database.program;
import static ghidra.lifecycle.Unfinished.TODO;
import static ghidra.lifecycle.Unfinished.*;
import java.util.*;
import java.util.function.Function;
@ -108,11 +108,10 @@ public abstract class AbstractDBTraceProgramViewReferenceManager implements Refe
}
@Override
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, long offset,
RefType type, SourceType source, int opIndex) {
return refs(true).addOffsetReference(chooseLifespan(fromAddr), fromAddr, toAddr, offset,
type,
source, opIndex);
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, boolean toAddrIsBase,
long offset, RefType type, SourceType source, int opIndex) {
return refs(true).addOffsetReference(chooseLifespan(fromAddr), fromAddr, toAddr,
toAddrIsBase, offset, type, source, opIndex);
}
@Override

View file

@ -20,8 +20,12 @@ import ghidra.trace.database.symbol.DBTraceReferenceSpace.DBTraceReferenceEntry;
import ghidra.trace.model.symbol.TraceOffsetReference;
public class DBTraceOffsetReference extends DBTraceReference implements TraceOffsetReference {
public DBTraceOffsetReference(DBTraceReferenceEntry ent) {
private boolean isExternalBlockReference;
public DBTraceOffsetReference(DBTraceReferenceEntry ent, boolean isExternalBlockReference) {
super(ent);
this.isExternalBlockReference = isExternalBlockReference;
}
@Override
@ -31,6 +35,9 @@ public class DBTraceOffsetReference extends DBTraceReference implements TraceOff
@Override
public Address getBaseAddress() {
if (isExternalBlockReference) {
return ent.toAddress;
}
return ent.toAddress.subtractWrap(ent.ext);
}
}

View file

@ -179,9 +179,10 @@ public class DBTraceReferenceManager extends
@Override
public DBTraceOffsetReference addOffsetReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, long offset, RefType refType, SourceType source, int operandIndex) {
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex) {
return delegateWrite(fromAddress.getAddressSpace(), s -> s.addOffsetReference(lifespan,
fromAddress, toAddress, offset, refType, source, operandIndex));
fromAddress, toAddress, toAddrIsBase, offset, refType, source, operandIndex));
}
@Override

View file

@ -27,6 +27,7 @@ import db.DBRecord;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Language;
import ghidra.program.model.lang.Register;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.trace.database.DBTrace;
import ghidra.trace.database.DBTraceUtils;
@ -41,11 +42,13 @@ import ghidra.trace.database.space.AbstractDBTraceSpaceBasedManager.DBTraceSpace
import ghidra.trace.database.space.DBTraceSpaceBased;
import ghidra.trace.model.Trace.TraceReferenceChangeType;
import ghidra.trace.model.Trace.TraceSymbolChangeType;
import ghidra.trace.model.memory.TraceMemoryRegion;
import ghidra.trace.model.symbol.TraceReference;
import ghidra.trace.model.symbol.TraceReferenceSpace;
import ghidra.trace.model.thread.TraceThread;
import ghidra.trace.util.TraceChangeRecord;
import ghidra.util.LockHold;
import ghidra.util.Msg;
import ghidra.util.database.*;
import ghidra.util.database.annot.*;
import ghidra.util.exception.VersionException;
@ -69,7 +72,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
OFFSET {
@Override
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
return new DBTraceOffsetReference(ent);
return new DBTraceOffsetReference(ent, false);
}
},
SHIFT {
@ -77,6 +80,12 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
return new DBTraceShiftedReference(ent);
}
},
OFFSET_EXTERNAL { // Offset Reference into EXTERNAL memory block region
@Override
protected DBTraceReference construct(DBTraceReferenceEntry ent) {
return new DBTraceOffsetReference(ent, true);
}
};
protected abstract DBTraceReference construct(DBTraceReferenceEntry ent);
@ -411,7 +420,7 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
// TODO: Reference (from, to, opIndex) must be unique!
if (reference.isOffsetReference()) {
OffsetReference oRef = (OffsetReference) reference;
return addOffsetReference(lifespan, oRef.getFromAddress(), oRef.getToAddress(),
return addOffsetReference(lifespan, oRef.getFromAddress(), oRef.getBaseAddress(), true,
oRef.getOffset(), oRef.getReferenceType(), oRef.getSource(),
oRef.getOperandIndex());
}
@ -461,18 +470,61 @@ public class DBTraceReferenceSpace implements DBTraceSpaceBased, TraceReferenceS
}
}
private boolean isExternalBlockAddress(Range<Long> lifespan, Address addr) {
// TODO: Verify that this works for emulation
TraceMemoryRegion region =
trace.getMemoryManager().getRegionContaining(lifespan.lowerEndpoint(), addr);
return region != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(region.getName());
}
@Override
public DBTraceOffsetReference addOffsetReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, long offset, RefType refType, SourceType source, int operandIndex) {
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex) {
if (operandIndex < -1) {
throw new IllegalArgumentException("operandIndex");
}
try (LockHold hold = LockHold.lock(lock.writeLock())) {
// Handle EXTERNAL Block offset-reference transformation
TypeEnum type = TypeEnum.OFFSET;
boolean isExternalBlockRef = isExternalBlockAddress(lifespan, toAddress);
boolean badOffsetReference = false;
if (isExternalBlockRef) {
type = TypeEnum.OFFSET_EXTERNAL;
if (!toAddrIsBase) {
Address baseAddr = toAddress.subtractWrap(offset);
if (isExternalBlockAddress(lifespan, baseAddr)) {
toAddress = baseAddr;
toAddrIsBase = true;
}
else {
// assume unintentional reference into EXTERNAL block
isExternalBlockRef = false;
type = TypeEnum.OFFSET;
badOffsetReference = true;
}
}
}
else if (toAddrIsBase) {
toAddress = toAddress.addWrap(offset);
toAddrIsBase = false;
if (isExternalBlockAddress(lifespan, toAddress)) {
badOffsetReference = true;
}
}
if (badOffsetReference) {
Msg.warn(this, "Offset Reference from " + fromAddress +
" produces bad Xref into EXTERNAL block");
}
makeWay(lifespan, fromAddress, toAddress, operandIndex);
DBTraceReferenceEntry entry = referenceMapSpace.put(fromAddress, lifespan, null);
entry.set(toAddress, -1, refType, operandIndex, offset, false, TypeEnum.OFFSET, source);
DBTraceOffsetReference ref = new DBTraceOffsetReference(entry);
entry.set(toAddress, -1, refType, operandIndex, offset, false, type, source);
DBTraceOffsetReference ref = new DBTraceOffsetReference(entry, isExternalBlockRef);
entry.ref = ref;
manager.doAddXRef(entry);
return ref;

View file

@ -32,7 +32,8 @@ public interface TraceReferenceOperations {
RefType refType, SourceType source, int operandIndex);
TraceOffsetReference addOffsetReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, long offset, RefType refType, SourceType source, int operandIndex);
Address toAddress, boolean toAddrIsBase, long offset, RefType refType,
SourceType source, int operandIndex);
TraceShiftedReference addShiftedReference(Range<Long> lifespan, Address fromAddress,
Address toAddress, int shift, RefType refType, SourceType source, int operandIndex);

View file

@ -303,9 +303,9 @@ public class ToyDBTraceBuilder implements AutoCloseable {
}
public DBTraceReference addOffsetReference(long creationSnap, Address from, Address to,
long offset) {
boolean toAddrIsBase, long offset) {
return trace.getReferenceManager()
.addOffsetReference(Range.atLeast(creationSnap), from, to,
.addOffsetReference(Range.atLeast(creationSnap), from, to, toAddrIsBase,
offset, RefType.DATA, SourceType.DEFAULT, -1);
}

View file

@ -133,6 +133,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
long offset) {
super(startSnap, fromAddress, toAddress);
this.offset = offset;
// NOTE: intended for test use in the absence of any EXTERNAL memory block concern
this.baseAddress = toAddress.subtract(offset);
}
@ -198,7 +199,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
new DummyTraceShiftedReference(0, b.addr(0x4002), b.addr(0x5002), 1));
}
assertTrue(memRef instanceof DBTraceReference);
assertNotNull(memRef);
assertTrue(offRef instanceof DBTraceOffsetReference);
assertTrue(sftRef instanceof DBTraceShiftedReference);
@ -231,7 +232,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
@Test
public void testAddOffsetReference() {
try (UndoableTransaction tid = b.startTransaction()) {
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), false, 20);
}
DBTraceReferenceSpace space =
manager.getReferenceSpace(b.language.getDefaultDataSpace(), false);
@ -285,7 +286,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference stkRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20);
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), false, 20);
sftRef = b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5002), 1);
regRef = b.addRegisterReference(0, b.addr(0x4003), "r5");
stkRef = b.addStackReference(0, b.addr(0x4004), 0x20);
@ -323,7 +324,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference stkRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
sftRef = b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
regRef = b.addRegisterReference(0, b.addr(0x4000), "r5");
stkRef = b.addStackReference(0, b.addr(0x4000), 0x20);
@ -376,7 +377,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference offRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
offRef = b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
assertNull(manager.getPrimaryReferenceFrom(0, b.addr(0x4000), -1));
@ -400,7 +401,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
flowRef = manager.addMemoryReference(Range.atLeast(0L), b.addr(0x4000), b.addr(0x4001),
RefType.FLOW, SourceType.DEFAULT, -1);
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
}
assertEquals(Set.of(flowRef),
@ -412,7 +413,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference keptRef;
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
b.addRegisterReference(0, b.addr(0x4000), "r5");
b.addStackReference(0, b.addr(0x4000), 0x20);
@ -449,7 +450,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference sftRef;
try (UndoableTransaction tid = b.startTransaction()) {
memRef = b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), 20);
offRef = b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), false, 20);
sftRef = b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5000), 1);
b.addRegisterReference(0, b.addr(0x4003), "r5");
b.addStackReference(0, b.addr(0x4004), 0x20);
@ -466,7 +467,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
DBTraceReference keptRef;
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000), 3);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), 20);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5000), false, 20);
b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5000), 1);
keptRef = b.addMemoryReference(0, b.addr(0x8000), b.addr(0x5001));
}
@ -498,7 +499,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public void testGetReferenceSourcesAndDestinations() {
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4001), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4002), b.addr(0x5002), 1);
b.addRegisterReference(0, b.addr(0x4003), "r5");
b.addStackReference(0, b.addr(0x4004), 0x20);
@ -520,7 +521,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
b.addRegisterReference(0, b.addr(0x4000), "r5");
b.addStackReference(0, b.addr(0x4000), 0x20);
@ -538,7 +539,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public void testSaveAndLoad() throws CancelledException, IOException, VersionException {
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
}
@ -575,7 +576,7 @@ public class DBTraceReferenceManagerTest extends AbstractGhidraHeadlessIntegrati
public void testUndo() throws IOException {
try (UndoableTransaction tid = b.startTransaction()) {
b.addMemoryReference(0, b.addr(0x4000), b.addr(0x5000));
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), 20);
b.addOffsetReference(0, b.addr(0x4000), b.addr(0x5001), false, 20);
b.addShiftedReference(0, b.addr(0x4000), b.addr(0x5002), 1);
}

View file

@ -29,7 +29,6 @@ import ghidra.program.model.block.CodeBlock;
import ghidra.program.model.lang.Register;
import ghidra.program.model.lang.RegisterValue;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.*;
@ -237,7 +236,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
}
private AddressSetView computeThunkBody(Program program) {
if (MemoryBlock.isExternalBlockAddress(entry, program)) {
if (program.getMemory().isExternalBlockAddress(entry)) {
return new AddressSet(entry, entry);
}
Listing listing = program.getListing();
@ -306,7 +305,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
if (f == null) {
// If referencedFunctionAddr contained within EXTERNAL block attempt to
// create a thunk function for it
if (MemoryBlock.isExternalBlockAddress(referencedFunctionAddr, program)) {
if (program.getMemory().isExternalBlockAddress(referencedFunctionAddr)) {
CreateThunkFunctionCmd extThunkCmd =
new CreateThunkFunctionCmd(referencedFunctionAddr, false);
if (extThunkCmd.applyTo(program)) {
@ -627,7 +626,7 @@ public class CreateThunkFunctionCmd extends BackgroundCommand {
*/
static Address getThunkedExternalFunctionAddress(Program program, Address entry) {
if (!MemoryBlock.isExternalBlockAddress(entry, program)) {
if (!program.getMemory().isExternalBlockAddress(entry)) {
return null;
}

View file

@ -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.
@ -20,6 +19,7 @@ import ghidra.framework.cmd.Command;
import ghidra.framework.model.DomainObject;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
/**
@ -29,24 +29,35 @@ public class AddOffsetMemRefCmd implements Command {
private Address fromAddr;
private Address toAddr;
private boolean toAddrIsBase;
private RefType refType;
private SourceType source;
private int opIndex;
private long offset;
/**
* Command constructor for adding an offset memory reference
* Command constructor for adding an offset memory reference. The first memory reference placed on
* an operand will be made primary by default. All non-memory references
* will be removed from the specified operand. If toAddr corresponds to
* the EXTERNAL memory block (see {@link MemoryBlock#EXTERNAL_BLOCK_NAME}) the
* resulting offset reference will report to/base address as the same
* regardless of specified offset.
* @param fromAddr address of the codeunit where the reference occurs
* @param toAddr address of the location being referenced.
* @param toAddrIsBase if true toAddr is treated as base address, else treated as (base+offet).
* It is generally preferred to specify as a base address to ensure proper handling of
* EXTERNAL block case.
* @param refType reference type - how the location is being referenced.
* @param source the source of the reference
* @param opIndex the operand index in the code unit where the reference occurs
* @param offset value added to a base address to get the toAddr
*/
public AddOffsetMemRefCmd(Address fromAddr, Address toAddr, RefType refType,
public AddOffsetMemRefCmd(Address fromAddr, Address toAddr, boolean toAddrIsBase,
RefType refType,
SourceType source, int opIndex, long offset) {
this.fromAddr = fromAddr;
this.toAddr = toAddr;
this.toAddrIsBase = toAddrIsBase;
this.refType = refType;
this.source = source;
this.opIndex = opIndex;
@ -60,11 +71,11 @@ public class AddOffsetMemRefCmd implements Command {
public boolean applyTo(DomainObject obj) {
Program p = (Program)obj;
ReferenceManager refMgr = p.getReferenceManager();
refMgr.addOffsetMemReference(fromAddr, toAddr, offset, refType, source, opIndex);
refMgr.addOffsetMemReference(fromAddr, toAddr, toAddrIsBase, offset, refType, source,
opIndex);
return true;
}
/**
* @see ghidra.framework.cmd.Command#getStatusMsg()
*/

View file

@ -125,8 +125,7 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
private boolean newCodeFound = false;
private int processorAlignment = 1;
private MemoryBlock externalBlock;
private boolean respectExecuteFlags = true;
private boolean respectExecuteFlags = OPTION_DEFAULT_RESPECT_EXECUTE_ENABLED;
public OperandReferenceAnalyzer() {
this(NAME, DESCRIPTION, AnalyzerType.INSTRUCTION_ANALYZER);
@ -192,8 +191,6 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
processorAlignment = program.getLanguage().getInstructionAlignment();
externalBlock = program.getMemory().getBlock(MemoryBlock.EXTERNAL_BLOCK_NAME);
newCodeFound = false;
int count = NOTIFICATION_INTERVAL;
long initial_count = set.getNumAddresses();
@ -574,12 +571,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
throws CancelledException {
// Check any direct jumps into the EXTERNAL memory section
// These don't return!
if (externalBlock == null) {
return false;
}
Address toAddr = reference.getToAddress();
if (!externalBlock.contains(toAddr)) {
if (!program.getMemory().isExternalBlockAddress(toAddr)) {
return false;
}
Address fromAddr = reference.getFromAddress();
@ -779,8 +772,8 @@ public class OperandReferenceAnalyzer extends AbstractAnalyzer {
instr.removeOperandReference(opIndex, target);
program.getReferenceManager()
.addOffsetMemReference(instr.getMinAddress(),
lastGoodTable.getTopAddress(), -((i + 3) * entryLen), RefType.DATA,
SourceType.ANALYSIS, opIndex);
lastGoodTable.getTopAddress(), false, -((i + 3) * entryLen),
RefType.DATA, SourceType.ANALYSIS, opIndex);
}
return lastGoodTable;

View file

@ -294,7 +294,7 @@ public class ScalarOperandAnalyzer extends AbstractAnalyzer {
// add in an offcut reference
program.getReferenceManager()
.addOffsetMemReference(refInstr.getMinAddress(), offAddr,
-entryLen, RefType.DATA, SourceType.ANALYSIS, opIndex);
false, -entryLen, RefType.DATA, SourceType.ANALYSIS, opIndex);
return;
}
@ -332,7 +332,7 @@ public class ScalarOperandAnalyzer extends AbstractAnalyzer {
// add in an offcut reference
program.getReferenceManager()
.addOffsetMemReference(instr.getMinAddress(), offAddr,
(i + 3) * entryLen, RefType.DATA, SourceType.ANALYSIS, opIndex);
false, (i + 3) * entryLen, RefType.DATA, SourceType.ANALYSIS, opIndex);
return;
}
}

View file

@ -577,7 +577,7 @@ public class ReferencesPlugin extends Plugin {
int opIndex = editRef.getOperandIndex();
cmd.add(new RemoveReferenceCmd(editRef));
if (isOffsetRef) {
cmd.add(new AddOffsetMemRefCmd(fromCodeUnit.getMinAddress(), toAddr, refType,
cmd.add(new AddOffsetMemRefCmd(fromCodeUnit.getMinAddress(), toAddr, false, refType,
SourceType.USER_DEFINED, opIndex, offset));
}
else {
@ -612,7 +612,7 @@ public class ReferencesPlugin extends Plugin {
Command cmd;
if (isOffsetRef) {
cmd = new AddOffsetMemRefCmd(fromAddr, toAddr, refType, SourceType.USER_DEFINED,
cmd = new AddOffsetMemRefCmd(fromAddr, toAddr, false, refType, SourceType.USER_DEFINED,
opIndex, offset);
}
else {

View file

@ -22,9 +22,12 @@ import org.apache.commons.lang3.StringUtils;
import ghidra.app.util.bin.format.elf.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.program.model.address.Address;
import ghidra.program.model.data.*;
import ghidra.program.model.data.DataUtilities.ClearDataMode;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
import ghidra.util.classfinder.ExtensionPoint;
import ghidra.util.exception.NotFoundException;
@ -73,9 +76,31 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
throws MemoryAccessException, NotFoundException;
/**
* Determine if symbolAddr is contained within the EXTERNAL block. If so, relocationAddress will be marked
* with a <code>Unsupported EXTERNAL Data Elf Relocation</code> error bookmark.
* NOTE: This method should only be invoked when the symbol offset will be adjust with a non-zero
* Apply a pointer-typedef with a specified component-offset.
* @param program
* @param addr address where data should be applied
* @param componentOffset component offset
*/
public static void applyComponentOffsetPointer(Program program, Address addr,
long componentOffset) {
// TODO: we could also assign non-default address space setting if needed
PointerTypedef dt =
new PointerTypedef(null, null, -1, program.getDataTypeManager(), componentOffset);
try {
DataUtilities.createData(program, addr, dt, -1, false,
ClearDataMode.CLEAR_ALL_UNDEFINED_CONFLICT_DATA);
}
catch (CodeUnitInsertionException | DataTypeConflictException e) {
Msg.error(ElfRelocationHandler.class,
"Failed to apply component-offset pointer at " + addr);
}
}
/**
* Determine if symbolAddr is contained within the EXTERNAL block with a non-zero adjustment.
* If so, relocationAddress will be marked with a <code>EXTERNAL Data Elf Relocation with pointer-offset</code>
* warning bookmark.
* NOTE: This method should only be invoked when the symbol offset will be adjusted with a non-zero
* value (i.e., addend).
* @param program
* @param relocationAddress relocation address to be bookmarked if EXTERNAL block relocation
@ -83,19 +108,14 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
* @param symbolName symbol name (may not be null if symbolAddr is not null)
* @param adjustment relocation symbol offset adjustment/addend
* @param log import log
* @return true if symbolAddress contained within EXTERNAL block.
*/
public static boolean isUnsupportedExternalRelocation(Program program,
public static void warnExternalOffsetRelocation(Program program,
Address relocationAddress, Address symbolAddr, String symbolName, long adjustment,
MessageLog log) {
if (symbolAddr == null) {
return false;
}
MemoryBlock block = program.getMemory().getBlock(symbolAddr);
if (block == null || !MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName())) {
return false;
if (symbolAddr == null || adjustment == 0 ||
!program.getMemory().isExternalBlockAddress(symbolAddr)) {
return;
}
String sign = "+";
@ -106,12 +126,13 @@ abstract public class ElfRelocationHandler implements ExtensionPoint {
String adjStr = sign + "0x" + Long.toHexString(adjustment);
symbolName = symbolName == null ? "<no name>" : symbolName;
log.appendMsg("Unsupported EXTERNAL Data Elf Relocation: at " + relocationAddress +
Msg.warn(ElfRelocationHandler.class,
"EXTERNAL Data Elf Relocation with offset: at " + relocationAddress +
" (External Location = " + symbolName + adjStr + ")");
BookmarkManager bookmarkManager = program.getBookmarkManager();
bookmarkManager.setBookmark(relocationAddress, BookmarkType.ERROR, "EXTERNAL Relocation",
"Unsupported EXTERNAL Data Elf Relocation: External Location = " + symbolName + adjStr);
return true;
bookmarkManager.setBookmark(relocationAddress, BookmarkType.WARNING, "EXTERNAL Relocation",
"EXTERNAL Data Elf Relocation with offset: External Location = " + symbolName +
adjStr);
}
/**

View file

@ -95,7 +95,7 @@ public class DemangledAddressTable extends DemangledObject {
}
Listing listing = program.getListing();
if (MemoryBlock.isExternalBlockAddress(address, program)) {
if (program.getMemory().isExternalBlockAddress(address)) {
Msg.warn(this,
"Unable to fully apply external demangled Address Table at " + address + ": " +
s.getName(true));

View file

@ -29,7 +29,6 @@ import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.PrototypeModel;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.CodeUnitInsertionException;
import ghidra.util.Msg;
@ -347,7 +346,7 @@ public class DemangledFunction extends DemangledObject {
* This method assumes preconditions test has been run.
*/
private boolean shouldDisassemble(Program program, Address address, DemanglerOptions options) {
if (!address.isMemoryAddress() || MemoryBlock.isExternalBlockAddress(address, program)) {
if (!address.isMemoryAddress() || program.getMemory().isExternalBlockAddress(address)) {
return false;
}
CodeUnit codeUnit = program.getListing().getCodeUnitAt(address);

View file

@ -221,7 +221,7 @@ class MarkupXmlMgr {
Command cmd = null;
if (baseAddr != null) {
long offset = toAddr.subtract(baseAddr);
cmd = new AddOffsetMemRefCmd(fromAddr, toAddr, refType,
cmd = new AddOffsetMemRefCmd(fromAddr, toAddr, false, refType,
userDefined ? SourceType.USER_DEFINED : SourceType.DEFAULT, opIndex, offset);
}
else {

View file

@ -758,7 +758,7 @@ public class ProgramBuilder {
return tx(() -> {
ReferenceManager refManager = program.getReferenceManager();
Reference ref = refManager.addOffsetMemReference(addr(fromAddress), addr(toAddress),
offset, refType, sourceType, opIndex);
false, offset, refType, sourceType, opIndex);
return ref;
});
}

View file

@ -444,8 +444,9 @@ public class DiffUtility extends SimpleDiffUtility {
Reference newRef;
if (ref.isOffsetReference()) {
newRef = otherRefMgr.addOffsetMemReference(otherFromAddress, otherToAddress,
((OffsetReference) ref).getOffset(), ref.getReferenceType(), ref.getSource(),
OffsetReference offRef = (OffsetReference) ref;
newRef = otherRefMgr.addOffsetMemReference(otherFromAddress, offRef.getBaseAddress(),
true, offRef.getOffset(), ref.getReferenceType(), ref.getSource(),
ref.getOperandIndex());
}
else if (ref.isShiftedReference()) {

View file

@ -29,7 +29,6 @@ import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryAccessException;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.pcode.PcodeOp;
import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.scalar.Scalar;
@ -75,7 +74,6 @@ public class SymbolicPropogator {
new NotFoundException("Divide by zero");
private long pointerMask;
private AddressRange externalBlockRange;
protected static final int MAX_EXACT_INSTRUCTIONS = 100;
@ -99,7 +97,6 @@ public class SymbolicPropogator {
spaceContext = new ProgramContextImpl(language);
setPointerMask(program);
setExternalRange(program);
context = new VarnodeContext(program, programContext, spaceContext);
context.setDebug(debug);
@ -122,18 +119,6 @@ public class SymbolicPropogator {
pointerMask = maskSize[ptrSize];
}
/**
* Identify EXTERNAL block range which should not be disassembled.
* @param program
* @return EXTERNAL block range or null if not found
*/
private void setExternalRange(Program program) {
MemoryBlock block = program.getMemory().getBlock(MemoryBlock.EXTERNAL_BLOCK_NAME);
if (block != null) {
externalBlockRange = new AddressRangeImpl(block.getStart(), block.getEnd());
}
}
/**
* Process a subroutine using the processor function.
* The process function can control what flows are followed and when to stop.
@ -2329,7 +2314,7 @@ public class SymbolicPropogator {
}
if (refType.isFlow() && !refType.isIndirect() &&
(externalBlockRange == null || !externalBlockRange.contains(target))) {
!program.getMemory().isExternalBlockAddress(target)) {
Data udata = program.getListing().getUndefinedDataAt(target);
if (udata != null) {
DisassembleCommand cmd = new DisassembleCommand(target, null, true);

View file

@ -748,8 +748,8 @@ public class ReferenceManagerTest extends AbstractGhidraHeadedIntegrationTest {
@Test
public void testAddOffsetReference() {
refMgr.addOffsetMemReference(addr(100), addr(600), 100, RefType.COMPUTED_JUMP,
SourceType.USER_DEFINED, 0);
refMgr.addOffsetMemReference(addr(100), addr(600), false, 100,
RefType.COMPUTED_JUMP, SourceType.USER_DEFINED, 0);
Reference ref = refMgr.getReference(addr(100), addr(600), 0);
assertNotNull(ref);

View file

@ -69,11 +69,11 @@ public class AddressBasedLocationTest extends AbstractGhidraHeadlessIntegrationT
ReferenceManager rm = program.getReferenceManager();
Reference offsetRef1 =
rm.addOffsetMemReference(addr("CODE:0"), addr("CODE:110"), 0x10, DATA, ANALYSIS, 0);
rm.addOffsetMemReference(addr("CODE:0"), addr("CODE:110"), false, 0x10, DATA, ANALYSIS, 0);
Reference offsetRef2 =
rm.addOffsetMemReference(addr("CODE:1"), addr("CODE:f0"), -0x10, DATA, ANALYSIS, 0);
rm.addOffsetMemReference(addr("CODE:1"), addr("CODE:f0"), false, -0x10, DATA, ANALYSIS, 0);
Reference offsetRef3 =
rm.addOffsetMemReference(addr("CODE:2"), addr("CODE:120"), 0x20, DATA, ANALYSIS, 0);
rm.addOffsetMemReference(addr("CODE:2"), addr("CODE:120"), false, 0x20, DATA, ANALYSIS, 0);
Reference stackRef1 = rm.addStackReference(addr("CODE:3"), 0, 0x10, DATA, ANALYSIS);
Reference stackRef2 = rm.addStackReference(addr("CODE:4"), 0, -0x10, DATA, ANALYSIS);

View file

@ -473,7 +473,7 @@ public class DecompileCallback {
if (error != null && addr.equals(error.getInstructionAddress())) {
throw new UnknownInstructionException(error.getConflictMessage());
}
if (MemoryBlock.isExternalBlockAddress(addr, program)) {
if (program.getMemory().isExternalBlockAddress(addr)) {
throw new UnknownInstructionException(
"Unable to disassemble EXTERNAL block location: " + addr);
}

View file

@ -2115,8 +2115,9 @@ public class CodeManager implements ErrorHandler, ManagerDB {
long pointerComponentOffset =
PointerTypedefInspector.getPointerComponentOffset((TypeDef) dataType);
if (pointerComponentOffset != 0) {
refManager.addOffsetMemReference(data.getMinAddress(), toAddr,
pointerComponentOffset, RefType.DATA, SourceType.DEFAULT, 0);
refManager.addOffsetMemReference(data.getMinAddress(),
toAddr.subtractWrap(pointerComponentOffset), true, pointerComponentOffset,
RefType.DATA, SourceType.DEFAULT, 0);
return;
}
}

View file

@ -31,7 +31,6 @@ import ghidra.program.model.address.*;
import ghidra.program.model.data.*;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.program.model.pcode.HighFunction;
import ghidra.program.model.symbol.*;
import ghidra.program.model.util.PropertyMapManager;
@ -348,8 +347,7 @@ public class FunctionManagerDB implements FunctionManager {
if (body == null || !body.contains(entryPoint)) {
throw new IllegalArgumentException("Function body must contain the entrypoint");
}
if (codeMgr.getDefinedDataAt(entryPoint) != null &&
!MemoryBlock.isExternalBlockAddress(entryPoint, program)) {
if (codeMgr.getDefinedDataAt(entryPoint) != null) {
throw new IllegalArgumentException(
"Function entryPoint may not be created on defined data");
}

View file

@ -57,6 +57,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
private AddressSet initializedLoadedAddrSet = new AddressSet();
private AddressSet allInitializedAddrSet = new AddressSet();
private AddressSetView executeSet = null;
private AddressSet externalBlockAddrSet;
private MemoryBlock lastBlock;// the last accessed block
private LiveMemoryHandler liveMemory;
@ -130,6 +131,7 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
addrSet = new AddressSet();
initializedLoadedAddrSet = new AddressSet();
allInitializedAddrSet = new AddressSet();
externalBlockAddrSet = new AddressSet();
// we have to process the non-mapped blocks first because to process the mapped
// blocks we need the address sets for the non-mapped blocks to be complete
for (MemoryBlockDB block : blocks) {
@ -161,6 +163,10 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
private void addBlockAddresses(MemoryBlockDB block, boolean scanAllMappedBlocksIfNeeded) {
AddressSet blockSet = new AddressSet(block.getStart(), block.getEnd());
addrSet = addrSet.union(blockSet);
if (block.isExternalBlock()) {
// NOTE: no handling for mapped blocks which should never map onto EXTERNAL block
externalBlockAddrSet.add(block.getStart(), block.getEnd());
}
if (block.isMapped()) {
// Identify source-blocks which block maps onto and add as a mapped-block to each of these
@ -1765,6 +1771,11 @@ public class MemoryMapDB implements Memory, ManagerDB, LiveMemoryListener {
return addrSet.isEmpty();
}
@Override
public boolean isExternalBlockAddress(Address addr) {
return externalBlockAddrSet.contains(addr);
}
@Override
public Address getMinAddress() {
return addrSet.getMinAddress();

View file

@ -15,11 +15,10 @@
*/
package ghidra.program.database.references;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.*;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.*;
import ghidra.program.util.*;
import ghidra.util.task.TaskMonitor;
import ghidra.program.util.SimpleDiffUtility;
class MemReferenceDB extends ReferenceDB {
@ -44,6 +43,10 @@ class MemReferenceDB extends ReferenceDB {
this(program, from, to, type, opIndex, sourceType, isPrimary, symbolID, false, false, 0);
}
protected boolean isExternalBlockReference() {
return program.getMemory().isExternalBlockAddress(getToAddress());
}
public boolean isOffset() {
return isOffset;
}
@ -56,12 +59,6 @@ class MemReferenceDB extends ReferenceDB {
return offsetOrShift;
}
/**
* @see ghidra.program.database.references.ReferenceDB#setProgram(ghidra.program.model.listing.Program)
*/
void setProgram(Program program) {
}
/**
* @see ghidra.program.model.symbol.Reference#isOffsetReference()
*/

View file

@ -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.
@ -28,17 +27,17 @@ class OffsetReferenceDB extends MemReferenceDB implements OffsetReference {
offset);
}
/**
* @see ghidra.program.model.symbol.OffsetReference#getOffset()
*/
@Override
public long getOffset() {
return offsetOrShift;
}
/**
* @see ghidra.program.model.symbol.OffsetReference#getBaseAddress()
*/
@Override
public Address getBaseAddress() {
if (isExternalBlockReference()) {
// EXTERNAL block: must report toAddr and base as the same regardless of offset
return toAddr;
}
return toAddr.subtractWrap(offsetOrShift);
}
@ -56,4 +55,5 @@ class OffsetReferenceDB extends MemReferenceDB implements OffsetReference {
OffsetReference ref = (OffsetReference) obj;
return offsetOrShift == ref.getOffset();
}
}

View file

@ -34,6 +34,7 @@ import ghidra.program.model.pcode.Varnode;
import ghidra.program.model.symbol.*;
import ghidra.program.util.ChangeManager;
import ghidra.util.Lock;
import ghidra.util.Msg;
import ghidra.util.exception.*;
import ghidra.util.task.TaskMonitor;
@ -486,12 +487,48 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
return null;
}
private boolean isExternalBlockAddress(Address addr) {
return program.getMemory().isExternalBlockAddress(addr);
}
@Override
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, long offset,
RefType type, SourceType sourceType, int opIndex) {
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, boolean toAddrIsBase,
long offset, RefType type, SourceType sourceType, int opIndex) {
if (!fromAddr.isMemoryAddress() || !toAddr.isMemoryAddress()) {
throw new IllegalArgumentException("From and To addresses must be memory addresses");
}
// Handle EXTERNAL Block offset-reference transformation
boolean isExternalBlockRef = isExternalBlockAddress(toAddr);
boolean badOffsetReference = false;
if (isExternalBlockRef) {
// NOTE: Resulting EXTERNAL Block reference may become incorrect
// if EXTERNAL block is moved or removed.
if (!toAddrIsBase) {
Address baseAddr = toAddr.subtractWrap(offset);
if (isExternalBlockAddress(baseAddr)) {
toAddr = baseAddr;
toAddrIsBase = true;
}
else {
// assume unintentional reference into EXTERNAL block
isExternalBlockRef = false;
badOffsetReference = true;
}
}
}
else if (toAddrIsBase) {
Address addr = toAddr.addWrap(offset);
if (isExternalBlockAddress(addr)) {
badOffsetReference = true;
}
}
if (badOffsetReference) {
Msg.warn(this, "Offset Reference from " + fromAddr +
" produces bad Xref into EXTERNAL block");
}
try {
removeNonMemRefs(fromAddr, opIndex);
return addRef(fromAddr, toAddr, type, sourceType, opIndex, true, false, offset);
@ -1883,7 +1920,9 @@ public class ReferenceDBManager implements ReferenceManager, ManagerDB, ErrorHan
Reference memRef;
if (ref.isOffsetReference()) {
OffsetReference offRef = (OffsetReference) ref;
memRef = addOffsetMemReference(from, to, offRef.getOffset(), type, sourceType, opIndex);
memRef =
addOffsetMemReference(from, offRef.getBaseAddress(), true, offRef.getOffset(), type,
sourceType, opIndex);
}
else if (ref.isShiftedReference()) {
ShiftedReference shiftRef = (ShiftedReference) ref;

View file

@ -23,6 +23,7 @@ import ghidra.framework.store.LockException;
import ghidra.program.database.mem.*;
import ghidra.program.model.address.*;
import ghidra.program.model.listing.Program;
import ghidra.program.model.symbol.OffsetReference;
import ghidra.util.exception.CancelledException;
import ghidra.util.exception.NotFoundException;
import ghidra.util.task.TaskMonitor;
@ -87,6 +88,23 @@ public interface Memory extends AddressSetView {
*/
public boolean isBigEndian();
/**
* Determine if the specified address is contained within the reserved EXTERNAL block
* (see {@link MemoryBlock#EXTERNAL_BLOCK_NAME}). This artificial memory block has certain
* limitations that may require associated addresses to be properly identified. All
* data access/referencing has the biggest exposure since the importers generally
* allocate a fixed and possibly insufficient amount of memory to corresponding data
* symbols. Any pointer math performed based upon an EXTERNAL block symbol address
* is likely to produce an unuseable address that may collide with unrelated symbols
* stored within the memory block (e.g., {@link OffsetReference} is one such example).
* @param addr address
* @return true if address is contained within EXTERNAL memory block, else false.
*/
public default boolean isExternalBlockAddress(Address addr) {
MemoryBlock block = getBlock(addr);
return block != null && block.isExternalBlock();
}
/**
* Sets the live memory handler
* @param handler the live memory handler

View file

@ -22,7 +22,8 @@ import java.util.List;
import ghidra.framework.store.LockException;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.address.AddressSpace;
import ghidra.program.model.symbol.OffsetReference;
import ghidra.util.NamingUtilities;
/**
@ -31,8 +32,18 @@ import ghidra.util.NamingUtilities;
public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* A special EXTERNAL block may be created by certain program loaders (e.g., Elf) to act as a
* stand-in for unknown external symbol locations.
* A special purpose EXTERNAL block may be created by certain program loaders
* (e.g., Elf) to act as a stand-in for unknown external symbol locations when
* relocation support is required using a valid memory address. While the
* EXTERNAL block is created out of neccessity for relocation processing it
* introduces a number of limitations when used to carry data symbols
* where pointer math and offset-references may occur.
* <p>
* The method {@link Memory#isExternalBlockAddress(Address)}
* may be used to determine if a specific address is contained within an EXTERNAL memory block.
* <p>
* NOTE: Close proximity to the end of an address space should be avoided
* to allow for {@link OffsetReference} use.
*/
public static final String EXTERNAL_BLOCK_NAME = "EXTERNAL";
@ -272,9 +283,27 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
/**
* Returns true if this is either a bit-mapped or byte-mapped block
*
* @return true if this is either a bit-mapped or byte-mapped block
*/
public boolean isMapped();
/**
* Returns true if this is a reserved EXTERNAL memory block based upon its name
* (see {@link MemoryBlock#EXTERNAL_BLOCK_NAME}). Checks for individual addresses may be done
* using {@link Memory#isExternalBlockAddress(Address)}.
* <p>
* Note that EXTERNAL blocks always resides within a memory space and never within the artifial
* {@link AddressSpace#EXTERNAL_SPACE} which is not a memory space. This can be a source of confusion.
* An EXTERNAL memory block exists to facilitate relocation processing for some external
* symbols which require a real memory address.
*
* @return true if this is a reserved EXTERNAL memory block
*/
public default boolean isExternalBlock() {
return EXTERNAL_BLOCK_NAME.equals(getName());
}
/**
* Returns true if this is an overlay block (i.e., contained within overlay space).
*
@ -300,19 +329,4 @@ public interface MemoryBlock extends Serializable, Comparable<MemoryBlock> {
*/
public List<MemoryBlockSourceInfo> getSourceInfos();
/**
* Determine if the specified address is contained within the reserved EXTERNAL block.
*
* @param address address of interest
* @param program
* @return true if address is contained within the reserved EXTERNAL block, else false.
*/
public static boolean isExternalBlockAddress(Address address, Program program) {
Memory memory = program.getMemory();
if (!address.isMemoryAddress()) {
return false;
}
MemoryBlock block = memory.getBlock(address);
return block != null && MemoryBlock.EXTERNAL_BLOCK_NAME.equals(block.getName());
}
}

View file

@ -16,10 +16,15 @@
package ghidra.program.model.symbol;
import ghidra.program.model.address.Address;
import ghidra.program.model.mem.MemoryBlock;
/**
* <code>OffsetReference</code> is a memory reference whose "to" address is
* computed from a base address plus an offset.
* <p>
* NOTE: References into the reserved EXTERNAL block must report {@link #getToAddress()}
* the same as {@link #getBaseAddress()} regardless of offset value due to symbol
* spacing limitations within the EXTERNAL block. See {@link MemoryBlock#EXTERNAL_BLOCK_NAME}.
*/
public interface OffsetReference extends Reference {
@ -35,4 +40,12 @@ public interface OffsetReference extends Reference {
*/
public Address getBaseAddress();
/**
* Return the base address plus the offset. The exception to this is the
* EXTERNAL block case where this method returns the base address regardless
* of the offset value.
* @return reference "to" address
*/
public Address getToAddress();
}

View file

@ -18,6 +18,7 @@ package ghidra.program.model.symbol;
import ghidra.program.model.address.*;
import ghidra.program.model.lang.Register;
import ghidra.program.model.listing.Variable;
import ghidra.program.model.mem.MemoryBlock;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.exception.InvalidInputException;
@ -32,7 +33,8 @@ public interface ReferenceManager {
/**
* Add a memory, stack, register or external reference
* @param reference
* @param reference reference to be added
* @return new reference
*/
public Reference addReference(Reference reference);
@ -45,6 +47,7 @@ public interface ReferenceManager {
* @param stackOffset stack offset of the reference
* @param type reference type - how the location is being referenced.
* @param source the source of this reference
* @return new stack reference
*/
public Reference addStackReference(Address fromAddr, int opIndex, int stackOffset, RefType type,
SourceType source);
@ -58,12 +61,13 @@ public interface ReferenceManager {
* @param register register to add the reference to
* @param type reference type - how the location is being referenced.
* @param source the source of this reference
* @return new register reference
*/
public Reference addRegisterReference(Address fromAddr, int opIndex, Register register,
RefType type, SourceType source);
/**
* Adds a memory reference. Only first the first memory reference placed on
* Adds a memory reference. The first memory reference placed on
* an operand will be made primary by default. All non-memory references
* will be removed from the specified operand.
* @param fromAddr address of the codeunit where the reference occurs
@ -73,37 +77,46 @@ public interface ReferenceManager {
* @param source the source of this reference
* @param opIndex the operand index
* display of the operand making this reference
* @return new memory reference
*/
public Reference addMemoryReference(Address fromAddr, Address toAddr, RefType type,
SourceType source, int opIndex);
/**
* Add an offset memory reference. Only first the first memory reference placed on
* Add an offset memory reference. The first memory reference placed on
* an operand will be made primary by default. All non-memory references
* will be removed from the specified operand.
* will be removed from the specified operand. If toAddr corresponds to
* the EXTERNAL memory block (see {@link MemoryBlock#EXTERNAL_BLOCK_NAME}) the
* resulting offset reference will report to/base address as the same
* regardless of specified offset.
* @param fromAddr address for the "from"
* @param toAddr address of the "to"
* @param toAddr address of the location being referenced.
* @param toAddrIsBase if true toAddr is treated as base address, else treated as (base+offet).
* It is generally preferred to specify as a base address to ensure proper handling of
* EXTERNAL block case.
* @param offset value added to a base address to get the toAddr
* @param type reference type - how the location is being referenced
* @param source the source of this reference
* @param opIndex the operand index
* @return new offset reference
*/
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, long offset,
RefType type, SourceType source, int opIndex);
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, boolean toAddrIsBase,
long offset, RefType type, SourceType source, int opIndex);
/**
* Add a shifted memory reference; the "to" address is computed as the value
* at the operand at opIndex shifted by some number of bits, specified in the
* shiftValue parameter. Only first the first memory reference placed on
* shiftValue parameter. The first memory reference placed on
* an operand will be made primary by default. All non-memory references
* will be removed from the specified operand.
* @param fromAddr address for the "from"
* @param toAddr computed as the value of the operand at opIndex shifted
* by the number of bits specified by shiftValue
* @param shiftValue
* @param shiftValue shifted value
* @param type reference type - how the location is being referenced
* @param source the source of this reference
* @param opIndex the operand index
* @return new shifted reference
*/
public Reference addShiftedMemReference(Address fromAddr, Address toAddr, int shiftValue,
RefType type, SourceType source, int opIndex);
@ -117,8 +130,9 @@ public interface ReferenceManager {
* @param extLabel label within the external program, may be null if extAddr is not null
* @param extAddr address within the external program, may be null
* @param source the source of this reference
* @param type reference type - how the location is being referenced
* @param opIndex operand index
* @param type reference type - how the location is being referenced
* @return new external space reference
* @throws InvalidInputException
* @throws DuplicateNameException
*/
@ -135,8 +149,9 @@ public interface ReferenceManager {
* @param extLabel label within the external program, may be null if extAddr is not null
* @param extAddr address within the external program, may be null
* @param source the source of this reference
* @param type reference type - how the location is being referenced
* @param opIndex operand index
* @param type reference type - how the location is being referenced
* @return new external space reference
* @throws InvalidInputException
* @throws DuplicateNameException
*/
@ -191,7 +206,7 @@ public interface ReferenceManager {
/**
* Returns the referenced function variable.
* @param reference
* @param reference variable reference
* @return function variable or null if variable not found
*/
public Variable getReferencedVariable(Reference reference);
@ -204,19 +219,23 @@ public interface ReferenceManager {
public void setPrimary(Reference ref, boolean isPrimary);
/**
* Return whether the given address has flow references from this address.
* Return whether the given address has flow references from it.
* @param addr the address to test for flow references.
* @return true if the given address has flow references from it, else false
*/
public boolean hasFlowReferencesFrom(Address addr);
/**
* Get the flow references from the given address.
* Get all flow references from the given address.
* @param addr the address of the codeunit to get all flows from.
* @return get all flow references from the given address.
*
*/
public Reference[] getFlowReferencesFrom(Address addr);
/**
* Returns an iterator over all external references
* Returns an iterator over all external space references
* @return reference iterator over all external space references
*/
public ReferenceIterator getExternalReferences();
@ -224,6 +243,7 @@ public interface ReferenceManager {
* Get an iterator over all references that have the given address as
* their "To" address.
* @param addr the address that all references in the iterator refer to.
* @return reference iterator over all references to the specified address.
*/
public ReferenceIterator getReferencesTo(Address addr);
@ -242,6 +262,7 @@ public interface ReferenceManager {
* @param fromAddr the address of the codeunit making the reference.
* @param toAddr the address being referred to.
* @param opIndex the operand index.
* @return reference which satisfies the specified criteria or null
*/
public Reference getReference(Address fromAddr, Address toAddr, int opIndex);
@ -267,6 +288,8 @@ public interface ReferenceManager {
* fromAddr.
* @param fromAddr the address of the codeunit being tested
* @param opIndex the index of the operand being tested.
* @return true if one or more reference from the specified address
* and opindex are defined, else false
*/
public boolean hasReferencesFrom(Address fromAddr, int opIndex);
@ -274,6 +297,8 @@ public interface ReferenceManager {
* Returns true if there are any memory references at the given
* address.
* @param fromAddr the address of the codeunit being tested
* @return true if one or more reference from the specified address
* are defined, else false
*/
public boolean hasReferencesFrom(Address fromAddr);
@ -281,6 +306,8 @@ public interface ReferenceManager {
* Get the primary reference from the given address.
* @param addr from address
* @param opIndex operand index
* @return the primary reference from the specified address
* and opindex if it exists, else null
*/
public Reference getPrimaryReferenceFrom(Address addr, int opIndex);
@ -289,6 +316,7 @@ public interface ReferenceManager {
* reference
* @param startAddr address to position iterator.
* @param forward true means to iterate in the forward direction
* @return address iterator where references from exist
*/
public AddressIterator getReferenceSourceIterator(Address startAddr, boolean forward);
@ -297,6 +325,8 @@ public interface ReferenceManager {
* reference, restricted by the given address set.
* @param addrSet the set of address to restrict the iterator or null for all addresses.
* @param forward true means to iterate in the forward direction
* address iterator where references from exist
* @return address iterator where references from exist constrained by addrSet
*/
public AddressIterator getReferenceSourceIterator(AddressSetView addrSet, boolean forward);
@ -305,6 +335,8 @@ public interface ReferenceManager {
* reference.
* @param startAddr start of iterator
* @param forward true means to iterate in the forward direction
* address iterator where references to exist
* @return address iterator where references to exist
*/
public AddressIterator getReferenceDestinationIterator(Address startAddr, boolean forward);
@ -313,20 +345,21 @@ public interface ReferenceManager {
* memory reference, restricted by the given address set.
* @param addrSet the set of address to restrict the iterator or null for all addresses.
* @param forward true means to iterate in the forward direction
* @return address iterator where references to exist constrained by addrSet
*/
public AddressIterator getReferenceDestinationIterator(AddressSetView addrSet, boolean forward);
/**
* Returns the number of memory References to the specified
* <code>toAddr</code>
* Returns the number of references to the specified <code>toAddr</code>.
* @param toAddr the address being referenced
* @return the number of references to the specified <code>toAddr</code>.
*/
public int getReferenceCountTo(Address toAddr);
/**
* Returns the number of memory References from the specified
* <code>fromAddr</code>
* Returns the number of references from the specified <code>fromAddr</code>.
* @param fromAddr the address of the codeunit making the reference.
* @return the number of references from the specified <code>fromAddr</code>.
*/
public int getReferenceCountFrom(Address fromAddr);
@ -343,6 +376,7 @@ public interface ReferenceManager {
/**
* Return true if a memory reference exists with the given "to" address.
* @param toAddr address being referred to.
* @return true if specified toAddr has one or more references to it, else false.
*/
public boolean hasReferencesTo(Address toAddr);
@ -350,6 +384,7 @@ public interface ReferenceManager {
* Uodate the reference type on a memory reference.
* @param ref reference to be updated
* @param refType new reference type
* @return updated reference
*/
public Reference updateRefType(Reference ref, RefType refType);
@ -379,6 +414,7 @@ public interface ReferenceManager {
/**
* Returns the reference level for the references to the given address
* @param toAddr the address at which to find the highest reference level
* @return reference level for specified to address.
*/
public byte getReferenceLevel(Address toAddr);

View file

@ -48,8 +48,8 @@ public class ReferenceManagerTestDouble implements ReferenceManager {
}
@Override
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, long offset,
RefType type, SourceType source, int opIndex) {
public Reference addOffsetMemReference(Address fromAddr, Address toAddr, boolean toAddrIsBase,
long offset, RefType type, SourceType source, int opIndex) {
throw new UnsupportedOperationException();
}

View file

@ -71,12 +71,13 @@ public class AARCH64_ElfRelocationHandler extends ElfRelocationHandler {
switch (type) {
// .xword: (S+A)
case AARCH64_ElfRelocationConstants.R_AARCH64_ABS64: {
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
newValue = (symbolValue + addend);
memory.setLong(relocationAddress, newValue);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
}

View file

@ -91,15 +91,16 @@ public class ARM_ElfRelocationHandler extends ElfRelocationHandler {
if (elfRelocationContext.extractAddend()) {
addend = memory.getInt(relocationAddress);
}
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
newValue = (int) (symbolValue + addend);
if (isThumb) {
newValue |= 1;
}
memory.setInt(relocationAddress, newValue);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
}
case ARM_ElfRelocationConstants.R_ARM_REL32: { // Target class: Data

View file

@ -61,6 +61,7 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
MIPS_ElfRelocationContext mipsRelocationContext =
(MIPS_ElfRelocationContext) elfRelocationContext;
mipsRelocationContext.lastSymbolAddr = null;
int type = relocation.getType();
int symbolIndex = relocation.getSymbolIndex();
@ -117,6 +118,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
Memory memory = program.getMemory();
MessageLog log = mipsRelocationContext.getLog();
ElfHeader elf = mipsRelocationContext.getElfHeader();
long offset = (int) relocationAddress.getOffset();
ElfSymbol elfSymbol = mipsRelocationContext.getSymbol(symbolIndex);
@ -125,6 +128,10 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
long symbolValue = mipsRelocationContext.getSymbolValue(elfSymbol);
String symbolName = elfSymbol.getNameAsString();
if (symbolIndex != 0) {
mipsRelocationContext.lastSymbolAddr = symbolAddr;
}
long addend = 0;
if (mipsRelocationContext.useSavedAddend) {
if (mipsRelocationContext.savedAddendHasError) {
@ -396,30 +403,31 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
writeNewValue = true;
break;
case MIPS_ElfRelocationConstants.R_MIPS_32:
value = (int) symbolValue;
value += mipsRelocationContext.extractAddend() ? oldValue : addend;
newValue = value;
writeNewValue = true;
break;
case MIPS_ElfRelocationConstants.R_MIPS_REL32:
// TODO: unsure if reloc valid for symbolIndex != 0
if (symbolIndex == 0) {
symbolValue = mipsRelocationContext.getImageBaseWordAdjustmentOffset();
}
case MIPS_ElfRelocationConstants.R_MIPS_32:
value = (int) symbolValue;
int a = (int) (mipsRelocationContext.extractAddend() ? oldValue : addend);
// NOTE: this may not detect correctly for all combound relocations
if (a != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, a, log)) {
a = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
value += a;
int intAddend = (int) (mipsRelocationContext.extractAddend() ? oldValue : addend);
value += intAddend;
newValue = value;
writeNewValue = true;
if (symbolIndex != 0 && intAddend != 0 && !saveValue) {
// If not continuing with compound relocation perform fixup so
// we can create offset-pointer now.
// NOTE: this may not handle all combound relocation cases
memory.setInt(relocationAddress, newValue);
writeNewValue = false;
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, intAddend, mipsRelocationContext.getLog());
if (elf.is32Bit()) {
applyComponentOffsetPointer(program, relocationAddress, intAddend);
}
}
break;
case MIPS_ElfRelocationConstants.R_MIPS_26:
@ -461,6 +469,24 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
}
else {
memory.setLong(relocationAddress, newValueBig);
Address addr =
symbolIndex == 0 ? mipsRelocationContext.lastSymbolAddr : symbolAddr;
if (addr != null && addend != 0) {
if (symbolIndex == 0) {
// compute addend used with compound relocation and lastSymbolAddr
addend -= addr.getOffset();
}
if (addend != 0) {
// If not continuing with compound relocation perform fixup so
// we can create offset-pointer now.
// NOTE: this may not handle all combound relocation cases
warnExternalOffsetRelocation(program, relocationAddress,
addr, symbolName, addend, mipsRelocationContext.getLog());
if (elf.is64Bit()) {
applyComponentOffsetPointer(program, relocationAddress, addend);
}
}
}
}
break;
@ -1020,6 +1046,8 @@ public class MIPS_ElfRelocationHandler extends ElfRelocationHandler {
private boolean savedAddendHasError = false;
private long savedAddend;
private Address lastSymbolAddr;
MIPS_ElfRelocationContext(MIPS_ElfRelocationHandler handler, ElfLoadHelper loadHelper,
ElfRelocationTable relocationTable, Map<ElfSymbol, Address> symbolMap) {
super(handler, loadHelper, relocationTable, symbolMap);

View file

@ -222,12 +222,13 @@ public class PowerPC64_ElfRelocationHandler extends ElfRelocationHandler {
case PowerPC64_ElfRelocationConstants.R_PPC64_UADDR64:
case PowerPC64_ElfRelocationConstants.R_PPC64_ADDR64:
case PowerPC64_ElfRelocationConstants.R_PPC64_GLOB_DAT:
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
value64 = symbolValue + addend;
memory.setLong(relocationAddress, value64);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
case PowerPC64_ElfRelocationConstants.R_PPC64_TOC:
memory.setLong(relocationAddress, toc);

View file

@ -91,12 +91,13 @@ public class PowerPC_ElfRelocationHandler extends ElfRelocationHandler {
case PowerPC_ElfRelocationConstants.R_PPC_ADDR32:
case PowerPC_ElfRelocationConstants.R_PPC_UADDR32:
case PowerPC_ElfRelocationConstants.R_PPC_GLOB_DAT:
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
newValue = symbolValue + addend;
memory.setInt(relocationAddress, newValue);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
case PowerPC_ElfRelocationConstants.R_PPC_ADDR24:
newValue = (symbolValue + addend) >> 2;

View file

@ -92,16 +92,26 @@ public class RISCV_ElfRelocationHandler extends ElfRelocationHandler {
// Runtime relocation word32 = S + A
value32 = (int)(symbolValue + addend);
memory.setInt(relocationAddress, value32);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
if (elf.is32Bit()) {
applyComponentOffsetPointer(program, relocationAddress, addend);
}
}
break;
case RISCV_ElfRelocationConstants.R_RISCV_64:
// Runtime relocation word64 = S + A
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
value64 = symbolValue + addend;
memory.setLong(relocationAddress, value64);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
if (elf.is64Bit()) {
applyComponentOffsetPointer(program, relocationAddress, addend);
}
}
break;
case RISCV_ElfRelocationConstants.R_RISCV_RELATIVE:

View file

@ -63,18 +63,22 @@ public class SH_ElfRelocationHandler extends ElfRelocationHandler {
switch (type) {
case SH_ElfRelocationConstants.R_SH_DIR32:
case SH_ElfRelocationConstants.R_SH_GLOB_DAT:
case SH_ElfRelocationConstants.R_SH_JMP_SLOT:
// 32-bit absolute relocations
// 32-bit absolute relocation w/ addend
if (elfRelocationContext.extractAddend()) {
addend = memory.getInt(relocationAddress);
}
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
newValue = symbolValue + addend;
memory.setInt(relocationAddress, newValue);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
case SH_ElfRelocationConstants.R_SH_GLOB_DAT:
case SH_ElfRelocationConstants.R_SH_JMP_SLOT:
// 32-bit absolute relocations, no addend
memory.setInt(relocationAddress, symbolValue);
break;
case SH_ElfRelocationConstants.R_SH_REL32: // 32-bit PC relative relocation

View file

@ -82,12 +82,13 @@ public class X86_32_ElfRelocationHandler extends ElfRelocationHandler {
switch (type) {
case X86_32_ElfRelocationConstants.R_386_32:
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
value = (int) (symbolValue + addend);
memory.setInt(relocationAddress, value);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
case X86_32_ElfRelocationConstants.R_386_PC32:
value = (int) (symbolValue + addend - offset);

View file

@ -87,12 +87,13 @@ public class X86_64_ElfRelocationHandler extends ElfRelocationHandler {
"Runtime copy not supported", elfRelocationContext.getLog());
break;
case X86_64_ElfRelocationConstants.R_X86_64_64:
if (addend != 0 && isUnsupportedExternalRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog())) {
addend = 0; // prefer bad fixup for EXTERNAL over really-bad fixup
}
value = symbolValue + addend;
memory.setLong(relocationAddress, value);
if (addend != 0) {
warnExternalOffsetRelocation(program, relocationAddress,
symbolAddr, symbolName, addend, elfRelocationContext.getLog());
applyComponentOffsetPointer(program, relocationAddress, addend);
}
break;
case X86_64_ElfRelocationConstants.R_X86_64_16:
value = symbolValue + addend;