diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java index b814a19995..fc28ce2867 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/service/modules/DefaultModuleMapProposal.java @@ -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; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java index cf58bdd146..2766886972 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/program/AbstractDBTraceProgramViewReferenceManager.java @@ -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 diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java index e2dcc762e9..632f0fe9e2 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceOffsetReference.java @@ -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); } } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java index f8437c788f..34edddbed5 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceManager.java @@ -179,9 +179,10 @@ public class DBTraceReferenceManager extends @Override public DBTraceOffsetReference addOffsetReference(Range 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 diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java index 26d958c4b7..9ab33c14e3 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/database/symbol/DBTraceReferenceSpace.java @@ -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 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 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; diff --git a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java index d67d41306d..e328eb6c10 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/main/java/ghidra/trace/model/symbol/TraceReferenceOperations.java @@ -32,7 +32,8 @@ public interface TraceReferenceOperations { RefType refType, SourceType source, int operandIndex); TraceOffsetReference addOffsetReference(Range 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 lifespan, Address fromAddress, Address toAddress, int shift, RefType refType, SourceType source, int operandIndex); diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java index 378722387c..99c489073d 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/ToyDBTraceBuilder.java @@ -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); } diff --git a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java index 4fcec432e1..291d88ac34 100644 --- a/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java +++ b/Ghidra/Debug/Framework-TraceModeling/src/test/java/ghidra/trace/database/symbol/DBTraceReferenceManagerTest.java @@ -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); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java index 130da02064..8846dd64a9 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/function/CreateThunkFunctionCmd.java @@ -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; } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/refs/AddOffsetMemRefCmd.java b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/refs/AddOffsetMemRefCmd.java index af0b4bbfba..e5767690ca 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/refs/AddOffsetMemRefCmd.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/cmd/refs/AddOffsetMemRefCmd.java @@ -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,10 +71,10 @@ 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() diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java index f1c9c03003..8d802fbf13 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/OperandReferenceAnalyzer.java @@ -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; diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java index f69e3de890..ff62e6debc 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/analysis/ScalarOperandAnalyzer.java @@ -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; } } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java index 6620448819..68a0f0c779 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/references/ReferencesPlugin.java @@ -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 { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java index b911a99ab8..ac5cfa1f3e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/bin/format/elf/relocation/ElfRelocationHandler.java @@ -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 Unsupported EXTERNAL Data Elf Relocation 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 EXTERNAL Data Elf Relocation with pointer-offset + * 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 ? "" : 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); } /** diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java index 4a3d53e31b..b63a923c56 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledAddressTable.java @@ -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)); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java index 16a1ac12f6..311ec6a5fb 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/demangler/DemangledFunction.java @@ -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); diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MarkupXmlMgr.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MarkupXmlMgr.java index 47209f87a6..ec7ac60957 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MarkupXmlMgr.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/xml/MarkupXmlMgr.java @@ -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 { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java b/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java index c2814d7c1e..697de44808 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/database/ProgramBuilder.java @@ -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; }); } diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java index 8d8c87e32a..f4fe11379e 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/DiffUtility.java @@ -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()) { diff --git a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java index 0bdef3a230..400730dd9a 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/program/util/SymbolicPropogator.java @@ -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); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/references/ReferenceManagerTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/references/ReferenceManagerTest.java index f31f2da4c2..5add6e4624 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/references/ReferenceManagerTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/program/database/references/ReferenceManagerTest.java @@ -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); diff --git a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/table/field/AddressBasedLocationTest.java b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/table/field/AddressBasedLocationTest.java index 7767a93bfa..1d2f1b3f57 100644 --- a/Ghidra/Features/Base/src/test.slow/java/ghidra/util/table/field/AddressBasedLocationTest.java +++ b/Ghidra/Features/Base/src/test.slow/java/ghidra/util/table/field/AddressBasedLocationTest.java @@ -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); diff --git a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java index 5fa15b44ea..7b577e578b 100644 --- a/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java +++ b/Ghidra/Features/Decompiler/src/main/java/ghidra/app/decompiler/DecompileCallback.java @@ -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); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/CodeManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/CodeManager.java index 9626ac7c3a..31ac8e71be 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/CodeManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/code/CodeManager.java @@ -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; } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java index 37f8ac0a95..314ae35498 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/function/FunctionManagerDB.java @@ -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"); } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java index be25802fdc..0b2d8c48fa 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/mem/MemoryMapDB.java @@ -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(); diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/MemReferenceDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/MemReferenceDB.java index 7858f56c4a..345880a27e 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/MemReferenceDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/MemReferenceDB.java @@ -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() */ diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/OffsetReferenceDB.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/OffsetReferenceDB.java index f254bcd0c0..40bdb129d6 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/OffsetReferenceDB.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/OffsetReferenceDB.java @@ -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(); } + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java index 2cb2175c35..0c611eac28 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/database/references/ReferenceDBManager.java @@ -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; diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java index 31a28ac370..eefc954eae 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/Memory.java @@ -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 diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java index 85b858e944..0d8e5d2b46 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/mem/MemoryBlock.java @@ -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 { /** - * 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. + *

+ * The method {@link Memory#isExternalBlockAddress(Address)} + * may be used to determine if a specific address is contained within an EXTERNAL memory block. + *

+ * 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 { /** * 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)}. + *

+ * 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 { */ public List 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()); - } } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/OffsetReference.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/OffsetReference.java index 08c2ec213e..c94b8532a9 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/OffsetReference.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/OffsetReference.java @@ -16,10 +16,15 @@ package ghidra.program.model.symbol; import ghidra.program.model.address.Address; +import ghidra.program.model.mem.MemoryBlock; /** * OffsetReference is a memory reference whose "to" address is * computed from a base address plus an offset. + *

+ * 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(); + } diff --git a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/ReferenceManager.java b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/ReferenceManager.java index d478e14871..98b8932236 100644 --- a/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/ReferenceManager.java +++ b/Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/symbol/ReferenceManager.java @@ -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 - * toAddr + * Returns the number of references to the specified toAddr. * @param toAddr the address being referenced + * @return the number of references to the specified toAddr. */ public int getReferenceCountTo(Address toAddr); /** - * Returns the number of memory References from the specified - * fromAddr + * Returns the number of references from the specified fromAddr. * @param fromAddr the address of the codeunit making the reference. + * @return the number of references from the specified fromAddr. */ 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); diff --git a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ReferenceManagerTestDouble.java b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ReferenceManagerTestDouble.java index 322e617c8d..e57092c6f0 100644 --- a/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ReferenceManagerTestDouble.java +++ b/Ghidra/Framework/SoftwareModeling/src/test/java/ghidra/program/model/ReferenceManagerTestDouble.java @@ -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(); } diff --git a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java index 9d5d2a57f8..3b7ccff5f9 100644 --- a/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java +++ b/Ghidra/Processors/AARCH64/src/main/java/ghidra/app/util/bin/format/elf/relocation/AARCH64_ElfRelocationHandler.java @@ -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; } diff --git a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java index 3970457508..542b69a745 100644 --- a/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java +++ b/Ghidra/Processors/ARM/src/main/java/ghidra/app/util/bin/format/elf/relocation/ARM_ElfRelocationHandler.java @@ -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 diff --git a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java index 7a741a1b65..a487a58b7e 100644 --- a/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java +++ b/Ghidra/Processors/MIPS/src/main/java/ghidra/app/util/bin/format/elf/relocation/MIPS_ElfRelocationHandler.java @@ -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 symbolMap) { super(handler, loadHelper, relocationTable, symbolMap); diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java index aff180180e..883a2e91ce 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC64_ElfRelocationHandler.java @@ -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); diff --git a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java index 178b04d091..87b62bfb14 100644 --- a/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java +++ b/Ghidra/Processors/PowerPC/src/main/java/ghidra/app/util/bin/format/elf/relocation/PowerPC_ElfRelocationHandler.java @@ -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; diff --git a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java index 25e3bcfc2a..bba327d842 100644 --- a/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java +++ b/Ghidra/Processors/RISCV/src/main/java/ghidra/app/util/bin/format/elf/relocation/RISCV_ElfRelocationHandler.java @@ -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: diff --git a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java index 3860212645..f38adbb341 100644 --- a/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java +++ b/Ghidra/Processors/SuperH4/src/main/java/ghidra/app/util/bin/format/elf/relocation/SH_ElfRelocationHandler.java @@ -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 diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java index 2a116cd78f..fd0a3f926c 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_32_ElfRelocationHandler.java @@ -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); diff --git a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java index 04d599f32a..ab1dfc2791 100644 --- a/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java +++ b/Ghidra/Processors/x86/src/main/java/ghidra/app/util/bin/format/elf/relocation/X86_64_ElfRelocationHandler.java @@ -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;